@higgsfield/video-editor-mcp 1.1.1-dev.0 → 2.0.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/README.md +63 -26
- package/dist/cli.mjs +284 -112
- package/dist/guide.md +2 -3
- package/dist/index.html +1 -1
- package/dist/launcher.mjs +34 -14
- package/dist/server.mjs +209 -265
- package/node_modules/@higgsfield/higgsedit/dist/api.d.ts +481 -0
- package/node_modules/@higgsfield/higgsedit/dist/{chunk-PFQYUJQL.mjs → chunk-3XVMJSV2.mjs} +1 -1
- package/node_modules/@higgsfield/higgsedit/dist/{chunk-F4CMIG5G.mjs → chunk-4VE54E4U.mjs} +3 -1
- package/node_modules/@higgsfield/higgsedit/dist/{chunk-2JYLVSVV.mjs → chunk-55JARHLA.mjs} +205 -65
- package/node_modules/@higgsfield/higgsedit/dist/{chunk-YLVXQIPX.mjs → chunk-E4N76T2R.mjs} +1 -1
- package/node_modules/@higgsfield/higgsedit/dist/{chunk-OCIZ36XD.mjs → chunk-ECRSOIKI.mjs} +1 -1
- package/node_modules/@higgsfield/higgsedit/dist/{chunk-IEPPEDEU.mjs → chunk-ENALCTAD.mjs} +1 -1
- package/node_modules/@higgsfield/higgsedit/dist/chunk-HY2E7IWX.mjs +43 -0
- package/node_modules/@higgsfield/higgsedit/dist/{chunk-NARTAWRN.mjs → chunk-HYCUOCUQ.mjs} +9 -4
- package/node_modules/@higgsfield/higgsedit/dist/{chunk-C3GSB3XZ.mjs → chunk-NLEIBCAK.mjs} +1 -7
- package/node_modules/@higgsfield/higgsedit/dist/{chunk-2WKNH7OL.mjs → chunk-O3AVYZ6U.mjs} +1 -1
- package/node_modules/@higgsfield/higgsedit/dist/chunk-UXO22E3P.mjs +22 -0
- package/node_modules/@higgsfield/higgsedit/dist/{chunk-BH2QF635.mjs → chunk-V5XTCFYK.mjs} +4 -100
- package/node_modules/@higgsfield/higgsedit/dist/chunk-W2TANYEH.mjs +118 -0
- package/node_modules/@higgsfield/higgsedit/dist/{chunk-DVN4LUXV.mjs → chunk-XY5CCUOZ.mjs} +2 -6
- package/node_modules/@higgsfield/higgsedit/dist/{chunk-KIWGVAPJ.mjs → chunk-Y7SAX2P4.mjs} +8 -12
- package/node_modules/@higgsfield/higgsedit/dist/chunk-YNAIRXOP.mjs +22 -0
- package/node_modules/@higgsfield/higgsedit/dist/{chunk-WENFTPXQ.mjs → chunk-ZO3NDQD3.mjs} +1 -1
- package/node_modules/@higgsfield/higgsedit/dist/higgsedit.mjs +13 -13
- package/node_modules/@higgsfield/higgsedit/package.json +4 -1
- package/package.json +4 -4
- package/plugin/.codex-plugin/plugin.json +1 -1
- package/plugin/skills/video-editing/SKILL.md +109 -95
- package/plugin/mcp.json +0 -10
- package/plugin/plugin.json +0 -41
- package/plugin/skills/motion-craft/SKILL.md +0 -87
- package/plugin/skills/motion-craft/agents/openai.yaml +0 -6
- package/plugin/skills/motion-craft/references/causality.md +0 -25
- package/plugin/skills/motion-craft/references/composition.md +0 -20
- package/plugin/skills/motion-craft/references/easing.md +0 -19
- package/plugin/skills/motion-craft/references/qc.md +0 -33
- package/plugin/skills/motion-craft/references/recipes.md +0 -31
- package/plugin/skills/motion-craft/references/stepped.md +0 -43
- package/plugin/skills/motion-craft/references/timing.md +0 -60
- package/plugin/skills/motion-craft/references/tsx.md +0 -60
- package/plugin/skills/motion-craft/references/typography.md +0 -22
- package/plugin/skills/video-editing/agents/openai.yaml +0 -6
- package/plugin/skills/video-editing/references/animation-contract.md +0 -45
- package/plugin/skills/video-editing/references/assembly.md +0 -58
- package/plugin/skills/video-editing/references/caption-systems.md +0 -29
- package/plugin/skills/video-editing/references/caption-titling.md +0 -41
- package/plugin/skills/video-editing/references/clip-geometry.md +0 -37
- package/plugin/skills/video-editing/references/compose.md +0 -283
- package/plugin/skills/video-editing/references/editor-measured.md +0 -37
- package/plugin/skills/video-editing/references/failure-modes.md +0 -37
- package/plugin/skills/video-editing/references/local-setup.md +0 -25
- package/plugin/skills/video-editing/references/motion-language.md +0 -27
- package/plugin/skills/video-editing/references/provenance.md +0 -7
- package/plugin/skills/video-editing/references/sandbox.md +0 -31
- package/plugin/skills/video-editing/references/shot-blueprints.md +0 -24
- package/plugin/skills/video-editing/references/title-animation.md +0 -29
- package/plugin/skills/video-editing/references/tsx-projects.md +0 -187
- package/plugin/skills/video-editing/references/workflows.md +0 -41
package/dist/server.mjs
CHANGED
|
@@ -4274,7 +4274,7 @@ var require_core2 = __commonJS({
|
|
|
4274
4274
|
var util_1 = require_util2();
|
|
4275
4275
|
var $dataRefSchema = require_data2();
|
|
4276
4276
|
var uri_1 = require_uri2();
|
|
4277
|
-
var defaultRegExp = (str,
|
|
4277
|
+
var defaultRegExp = (str, flags) => new RegExp(str, flags);
|
|
4278
4278
|
defaultRegExp.code = "new RegExp";
|
|
4279
4279
|
var META_IGNORE_OPTIONS = ["removeAdditional", "useDefaults", "coerceTypes"];
|
|
4280
4280
|
var EXT_SCOPE_NAMES = /* @__PURE__ */ new Set([
|
|
@@ -30739,7 +30739,7 @@ var require_core$3 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
30739
30739
|
const util_1 = require_util();
|
|
30740
30740
|
const $dataRefSchema = require_data();
|
|
30741
30741
|
const uri_1 = require_uri();
|
|
30742
|
-
const defaultRegExp = (str,
|
|
30742
|
+
const defaultRegExp = (str, flags) => new RegExp(str, flags);
|
|
30743
30743
|
defaultRegExp.code = "new RegExp";
|
|
30744
30744
|
const META_IGNORE_OPTIONS = [
|
|
30745
30745
|
"removeAdditional",
|
|
@@ -41164,13 +41164,13 @@ var StreamableHTTPClientTransport = class {
|
|
|
41164
41164
|
this.onerror?.(new Error(`Maximum reconnection attempts (${maxRetries}) exceeded.`));
|
|
41165
41165
|
return;
|
|
41166
41166
|
}
|
|
41167
|
-
const
|
|
41167
|
+
const delay3 = this._getNextReconnectionDelay(attemptCount);
|
|
41168
41168
|
this._reconnectionTimeout = setTimeout(() => {
|
|
41169
41169
|
this._startOrAuthSse(options).catch((error51) => {
|
|
41170
41170
|
this.onerror?.(new Error(`Failed to reconnect SSE stream: ${error51 instanceof Error ? error51.message : String(error51)}`));
|
|
41171
41171
|
this._scheduleReconnection(options, attemptCount + 1);
|
|
41172
41172
|
});
|
|
41173
|
-
},
|
|
41173
|
+
}, delay3);
|
|
41174
41174
|
}
|
|
41175
41175
|
_handleSseStream(stream, options, isReconnectable) {
|
|
41176
41176
|
if (!stream) {
|
|
@@ -41915,7 +41915,7 @@ var DirectServer = class {
|
|
|
41915
41915
|
};
|
|
41916
41916
|
|
|
41917
41917
|
// src/video-editor-local/standalone-resource.ts
|
|
41918
|
-
var packageVersion = "
|
|
41918
|
+
var packageVersion = "2.0.0";
|
|
41919
41919
|
var VIDEO_EDITOR_RESOURCE_URI = packageVersion ? `ui://higgsfield/video-editor-v3-${encodeURIComponent(packageVersion)}.html` : "ui://higgsfield/video-editor-v3.html";
|
|
41920
41920
|
function panelHtmlPath(env = process.env) {
|
|
41921
41921
|
return env.VIDEO_EDITOR_LOCAL_HTML?.trim() || join2(import.meta.dirname, "index.html");
|
|
@@ -42049,7 +42049,7 @@ function registerHostedProxyTools(server, url2, session = new LocalBrowserSessio
|
|
|
42049
42049
|
const previous = connected?.client;
|
|
42050
42050
|
const next = new Client({
|
|
42051
42051
|
name: "higgsfield-video-editor-local",
|
|
42052
|
-
version: "
|
|
42052
|
+
version: "2.0.0"
|
|
42053
42053
|
});
|
|
42054
42054
|
const transport = new StreamableHTTPClientTransport(new URL(url2), {
|
|
42055
42055
|
requestInit: { headers: { Authorization: `Bearer ${token}` } }
|
|
@@ -42128,9 +42128,57 @@ function registerHostedProxyTools(server, url2, session = new LocalBrowserSessio
|
|
|
42128
42128
|
|
|
42129
42129
|
// src/video-editor-local/index.ts
|
|
42130
42130
|
import { readFileSync as readFileSync3 } from "node:fs";
|
|
42131
|
-
import { mkdir as
|
|
42132
|
-
import { tmpdir as
|
|
42133
|
-
import { join as
|
|
42131
|
+
import { mkdir as mkdir6 } from "node:fs/promises";
|
|
42132
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
42133
|
+
import { join as join10 } from "node:path";
|
|
42134
|
+
|
|
42135
|
+
// src/video-editor-local/dev-api.ts
|
|
42136
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
42137
|
+
var DevApiError = class extends Error {
|
|
42138
|
+
constructor(status, message) {
|
|
42139
|
+
super(message);
|
|
42140
|
+
this.status = status;
|
|
42141
|
+
}
|
|
42142
|
+
status;
|
|
42143
|
+
};
|
|
42144
|
+
async function send(origin, method, path2, body) {
|
|
42145
|
+
const res = await fetch(`${origin}${path2}`, {
|
|
42146
|
+
method,
|
|
42147
|
+
...body === void 0 ? {} : { headers: { "content-type": "application/json" }, body: JSON.stringify(body) }
|
|
42148
|
+
});
|
|
42149
|
+
if (res.ok) return res;
|
|
42150
|
+
let message = `${path2}: ${res.status}`;
|
|
42151
|
+
try {
|
|
42152
|
+
const error51 = await res.json();
|
|
42153
|
+
if (typeof error51.error === "string") message = error51.error;
|
|
42154
|
+
} catch {
|
|
42155
|
+
}
|
|
42156
|
+
throw new DevApiError(res.status, message);
|
|
42157
|
+
}
|
|
42158
|
+
var POLL_MS = 1e3;
|
|
42159
|
+
function devApi(origin) {
|
|
42160
|
+
const get = async (path2) => (await send(origin, "GET", path2)).json();
|
|
42161
|
+
const post = async (path2, body) => (await send(origin, "POST", path2, body)).json();
|
|
42162
|
+
return {
|
|
42163
|
+
get,
|
|
42164
|
+
post,
|
|
42165
|
+
/** A route that answers bytes (the contact sheet). */
|
|
42166
|
+
bytes: async (path2, body) => Buffer.from(await (await send(origin, "POST", path2, body)).arrayBuffer()),
|
|
42167
|
+
/** Starts a job and waits for its result. */
|
|
42168
|
+
async job(path2, body, timeoutMs) {
|
|
42169
|
+
const { id: id2 } = await post(path2, body);
|
|
42170
|
+
const deadline = Date.now() + timeoutMs;
|
|
42171
|
+
for (; ; ) {
|
|
42172
|
+
const job = await get(`/api/jobs/${id2}`);
|
|
42173
|
+
if (job.status === "done") return job.result;
|
|
42174
|
+
if (job.status === "failed") throw new Error(job.error);
|
|
42175
|
+
if (Date.now() >= deadline)
|
|
42176
|
+
throw new Error(`${path2} did not finish within ${Math.round(timeoutMs / 1e3)} s`);
|
|
42177
|
+
await delay(POLL_MS);
|
|
42178
|
+
}
|
|
42179
|
+
}
|
|
42180
|
+
};
|
|
42181
|
+
}
|
|
42134
42182
|
|
|
42135
42183
|
// src/video-editor-local/higgsedit.ts
|
|
42136
42184
|
import { execFile as execFile2 } from "node:child_process";
|
|
@@ -42180,22 +42228,14 @@ function runCli(args, cwd, timeoutMs = 12e4) {
|
|
|
42180
42228
|
);
|
|
42181
42229
|
});
|
|
42182
42230
|
}
|
|
42183
|
-
function
|
|
42231
|
+
async function cli(args, cwd, timeoutMs) {
|
|
42232
|
+
const result = await runCli(args, cwd, timeoutMs);
|
|
42184
42233
|
if (result.code !== 0)
|
|
42185
42234
|
throw new Error(
|
|
42186
42235
|
(result.stderr || result.stdout).trim().slice(-4e3) || `higgsedit exited ${result.code}`
|
|
42187
42236
|
);
|
|
42188
|
-
|
|
42189
|
-
try {
|
|
42190
|
-
value = JSON.parse(result.stdout);
|
|
42191
|
-
} catch {
|
|
42192
|
-
throw new Error("higgsedit returned invalid or incomplete JSON.");
|
|
42193
|
-
}
|
|
42194
|
-
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
42195
|
-
throw new Error("higgsedit returned an unexpected JSON response; expected an object.");
|
|
42196
|
-
return value;
|
|
42237
|
+
return result;
|
|
42197
42238
|
}
|
|
42198
|
-
var cliJson = async (args, cwd, timeoutMs) => parseCliJson(await runCli(args, cwd, timeoutMs));
|
|
42199
42239
|
|
|
42200
42240
|
// ../../packages/mcp-app/src/shared/video-editor-media-import.ts
|
|
42201
42241
|
var STREAMING_MEDIA_PATH = "api/media/stream";
|
|
@@ -42341,9 +42381,8 @@ async function importMedia(origin, url2, fileName, signal, options = {}) {
|
|
|
42341
42381
|
}
|
|
42342
42382
|
|
|
42343
42383
|
// src/video-editor-local/media-tools.ts
|
|
42344
|
-
import {
|
|
42345
|
-
import {
|
|
42346
|
-
import { basename as basename2, extname, isAbsolute as isAbsolute2, join as join5, relative as relative2 } from "node:path";
|
|
42384
|
+
import { readFile as readFile3, stat as stat2 } from "node:fs/promises";
|
|
42385
|
+
import { relative as relative2 } from "node:path";
|
|
42347
42386
|
|
|
42348
42387
|
// src/video-editor-local/roots.ts
|
|
42349
42388
|
import { realpath, stat } from "node:fs/promises";
|
|
@@ -42444,13 +42483,11 @@ var TIME = external_exports.union([external_exports.number(), external_exports.s
|
|
|
42444
42483
|
var PROJECT = external_exports.string().min(1).max(4096).optional().describe(
|
|
42445
42484
|
"The project to act on: its session id (or folder path) from video_editing_open_project. Default the last opened project; pass it whenever more than one project is open."
|
|
42446
42485
|
);
|
|
42447
|
-
var flags = (values) => Object.entries(values).flatMap(
|
|
42448
|
-
([name, value]) => value === void 0 || value === false ? [] : [value === true ? `--${name}` : `--${name}=${value}`]
|
|
42449
|
-
);
|
|
42450
42486
|
|
|
42451
42487
|
// src/video-editor-local/media-tools.ts
|
|
42452
42488
|
var INLINE_MAX_IMAGES = 4;
|
|
42453
42489
|
var INLINE_MAX_BYTES = 1 << 20;
|
|
42490
|
+
var JOB_MS = 18e5;
|
|
42454
42491
|
async function withImages(result, paths) {
|
|
42455
42492
|
const content = [{ type: "text", text: JSON.stringify(result) }];
|
|
42456
42493
|
const sizes = await Promise.all(paths.map(async (p) => (await stat2(p)).size));
|
|
@@ -42478,20 +42515,8 @@ var SCALE = external_exports.number().min(0.25).max(4).optional().describe(
|
|
|
42478
42515
|
var OUTPUT = external_exports.string().max(4096).optional().describe(
|
|
42479
42516
|
"Where to save: a file path, or a folder to create a new file in; default a new file in the system temp dir"
|
|
42480
42517
|
);
|
|
42481
|
-
|
|
42482
|
-
|
|
42483
|
-
const expanded = expandHome(path2);
|
|
42484
|
-
if (isAbsolute2(expanded)) return expanded;
|
|
42485
|
-
if (!root)
|
|
42486
|
-
throw new Error(`${path2} is relative but no project is open; pass an absolute path.`);
|
|
42487
|
-
return join5(root, expanded);
|
|
42488
|
-
};
|
|
42489
|
-
const media2 = async (root, command, path2, args, timeoutMs = 3e5) => await cliJson(
|
|
42490
|
-
["media", command, mediaPath(path2, root), ...args, "--json"],
|
|
42491
|
-
root ?? tmpdir(),
|
|
42492
|
-
timeoutMs
|
|
42493
|
-
);
|
|
42494
|
-
const output = (path2, root) => path2 ? ["-o", mediaPath(path2, root)] : [];
|
|
42518
|
+
var defined = (values) => Object.fromEntries(Object.entries(values).filter(([, value]) => value !== void 0));
|
|
42519
|
+
function registerMediaTools(server, scoped) {
|
|
42495
42520
|
const read = { readOnlyHint: true, openWorldHint: false };
|
|
42496
42521
|
server.registerTool(
|
|
42497
42522
|
"video_editing_media_probe",
|
|
@@ -42501,7 +42526,9 @@ function registerMediaTools(server, mediaScoped) {
|
|
|
42501
42526
|
inputSchema: external_exports.object({ path: MEDIA_PATH, project: PROJECT }),
|
|
42502
42527
|
annotations: read
|
|
42503
42528
|
},
|
|
42504
|
-
async ({ path: path2, project }) =>
|
|
42529
|
+
async ({ path: path2, project }) => scoped(project, async ({ origin }) => ({
|
|
42530
|
+
...await devApi(origin).post("/api/media/probe", { path: path2 })
|
|
42531
|
+
}))
|
|
42505
42532
|
);
|
|
42506
42533
|
server.registerTool(
|
|
42507
42534
|
"video_editing_media_grab",
|
|
@@ -42528,34 +42555,13 @@ function registerMediaTools(server, mediaScoped) {
|
|
|
42528
42555
|
}),
|
|
42529
42556
|
annotations: read
|
|
42530
42557
|
},
|
|
42531
|
-
async ({
|
|
42532
|
-
|
|
42533
|
-
|
|
42534
|
-
|
|
42535
|
-
|
|
42536
|
-
end,
|
|
42537
|
-
quality,
|
|
42538
|
-
separate,
|
|
42539
|
-
per_sheet,
|
|
42540
|
-
uncapped,
|
|
42541
|
-
output: out,
|
|
42542
|
-
project
|
|
42543
|
-
}) => mediaScoped(project, async (root) => {
|
|
42544
|
-
const r = await media2(root, "grab", path2, [
|
|
42545
|
-
...flags({
|
|
42546
|
-
times: times?.join(","),
|
|
42547
|
-
count,
|
|
42548
|
-
start,
|
|
42549
|
-
end,
|
|
42550
|
-
quality,
|
|
42551
|
-
separate,
|
|
42552
|
-
"per-sheet": per_sheet,
|
|
42553
|
-
uncapped
|
|
42554
|
-
}),
|
|
42555
|
-
...output(out, root)
|
|
42556
|
-
]);
|
|
42558
|
+
async ({ path: path2, times, count, start, end, quality, separate, per_sheet, uncapped, output, project }) => scoped(project, async ({ origin }) => {
|
|
42559
|
+
const r = await devApi(origin).post(
|
|
42560
|
+
"/api/media/grab",
|
|
42561
|
+
defined({ path: path2, times, count, start, end, quality, separate, perSheet: per_sheet, uncapped, output })
|
|
42562
|
+
);
|
|
42557
42563
|
return withImages(
|
|
42558
|
-
r,
|
|
42564
|
+
{ ...r },
|
|
42559
42565
|
r.images.map((image) => image.path)
|
|
42560
42566
|
);
|
|
42561
42567
|
})
|
|
@@ -42574,12 +42580,12 @@ function registerMediaTools(server, mediaScoped) {
|
|
|
42574
42580
|
}),
|
|
42575
42581
|
annotations: read
|
|
42576
42582
|
},
|
|
42577
|
-
async ({ path: path2, start, end, scale, output
|
|
42578
|
-
const r = await
|
|
42579
|
-
|
|
42580
|
-
|
|
42581
|
-
|
|
42582
|
-
return withImages(r, [r.path]);
|
|
42583
|
+
async ({ path: path2, start, end, scale, output, project }) => scoped(project, async ({ origin }) => {
|
|
42584
|
+
const r = await devApi(origin).post(
|
|
42585
|
+
"/api/media/filmstrip",
|
|
42586
|
+
defined({ path: path2, start, end, scale, output })
|
|
42587
|
+
);
|
|
42588
|
+
return withImages({ ...r }, [r.path]);
|
|
42583
42589
|
})
|
|
42584
42590
|
);
|
|
42585
42591
|
server.registerTool(
|
|
@@ -42598,12 +42604,12 @@ function registerMediaTools(server, mediaScoped) {
|
|
|
42598
42604
|
}),
|
|
42599
42605
|
annotations: read
|
|
42600
42606
|
},
|
|
42601
|
-
async ({ path: path2, start, end, scale, output
|
|
42602
|
-
const r = await
|
|
42603
|
-
|
|
42604
|
-
|
|
42605
|
-
|
|
42606
|
-
return withImages(r, [r.path]);
|
|
42607
|
+
async ({ path: path2, start, end, scale, output, silence_db, min_silence, project }) => scoped(project, async ({ origin }) => {
|
|
42608
|
+
const r = await devApi(origin).post(
|
|
42609
|
+
"/api/media/waveform",
|
|
42610
|
+
defined({ path: path2, start, end, scale, output, silenceDb: silence_db, minSilence: min_silence })
|
|
42611
|
+
);
|
|
42612
|
+
return withImages({ ...r }, [r.path]);
|
|
42607
42613
|
})
|
|
42608
42614
|
);
|
|
42609
42615
|
server.registerTool(
|
|
@@ -42622,16 +42628,13 @@ function registerMediaTools(server, mediaScoped) {
|
|
|
42622
42628
|
}),
|
|
42623
42629
|
annotations: read
|
|
42624
42630
|
},
|
|
42625
|
-
async ({ path: path2, output
|
|
42626
|
-
|
|
42627
|
-
|
|
42628
|
-
|
|
42629
|
-
|
|
42630
|
-
path2,
|
|
42631
|
-
[...flags({ language, model }), ...output(out, root)],
|
|
42632
|
-
18e5
|
|
42631
|
+
async ({ path: path2, output, language, model, project }) => scoped(project, async ({ origin }) => ({
|
|
42632
|
+
...await devApi(origin).job(
|
|
42633
|
+
"/api/media/transcribe",
|
|
42634
|
+
defined({ path: path2, output, language, model }),
|
|
42635
|
+
JOB_MS
|
|
42633
42636
|
)
|
|
42634
|
-
)
|
|
42637
|
+
}))
|
|
42635
42638
|
);
|
|
42636
42639
|
const POINT = external_exports.object({ x: external_exports.number().min(0).max(1), y: external_exports.number().min(0).max(1) });
|
|
42637
42640
|
server.registerTool(
|
|
@@ -42649,41 +42652,26 @@ function registerMediaTools(server, mediaScoped) {
|
|
|
42649
42652
|
box: external_exports.tuple([external_exports.number(), external_exports.number(), external_exports.number(), external_exports.number()]).optional().describe("[x0, y0, x1, y1] in 0..1"),
|
|
42650
42653
|
...WINDOW,
|
|
42651
42654
|
model: external_exports.enum(["tiny", "small", "base-plus", "large"]).optional().describe("SAM 2.1 size; tiny (default) is fastest"),
|
|
42652
|
-
output: external_exports.string().max(4096).optional().describe(
|
|
42653
|
-
"Where the .mask goes; default masks/<video name>.mask in the open project, else a temp file"
|
|
42654
|
-
),
|
|
42655
|
+
output: external_exports.string().max(4096).optional().describe("Where the .mask goes; default masks/<video name>.mask in the open project"),
|
|
42655
42656
|
project: PROJECT
|
|
42656
42657
|
}),
|
|
42657
42658
|
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: true }
|
|
42658
42659
|
},
|
|
42659
|
-
async ({ path: path2, time: time3, points, exclude, box, start, end, model, output
|
|
42660
|
-
const
|
|
42661
|
-
|
|
42662
|
-
|
|
42663
|
-
|
|
42664
|
-
const r = await cliJson(
|
|
42665
|
-
[
|
|
42666
|
-
"segment",
|
|
42667
|
-
file2,
|
|
42668
|
-
"-o",
|
|
42669
|
-
mask,
|
|
42670
|
-
...(points ?? []).map((p) => `--point=${p.x},${p.y}`),
|
|
42671
|
-
...(exclude ?? []).map((p) => `--exclude=${p.x},${p.y}`),
|
|
42672
|
-
...flags({ box: box?.join(","), at: time3, start, end, model, json: true })
|
|
42673
|
-
],
|
|
42674
|
-
root ?? tmpdir(),
|
|
42675
|
-
18e5
|
|
42660
|
+
async ({ path: path2, time: time3, points, exclude, box, start, end, model, output, project }) => scoped(project, async ({ origin, root }) => {
|
|
42661
|
+
const r = await devApi(origin).job(
|
|
42662
|
+
"/api/media/segment",
|
|
42663
|
+
defined({ path: path2, at: time3, points, exclude, box, start, end, model, output }),
|
|
42664
|
+
JOB_MS
|
|
42676
42665
|
);
|
|
42677
|
-
|
|
42678
|
-
return { ...r, ...src ? { src } : {} };
|
|
42666
|
+
return { ...r, ...isInside(root, r.path) ? { src: relative2(root, r.path) } : {} };
|
|
42679
42667
|
})
|
|
42680
42668
|
);
|
|
42681
42669
|
}
|
|
42682
42670
|
|
|
42683
42671
|
// src/video-editor-local/panel-relay.ts
|
|
42684
42672
|
import { execFile as execFile3 } from "node:child_process";
|
|
42685
|
-
import { appendFile, link as link2, mkdir as
|
|
42686
|
-
import { basename as
|
|
42673
|
+
import { appendFile, link as link2, mkdir as mkdir4, rm as rm4, stat as stat3, writeFile as writeFile5 } from "node:fs/promises";
|
|
42674
|
+
import { basename as basename2, extname, join as join8, resolve as resolve2 } from "node:path";
|
|
42687
42675
|
import { promisify } from "node:util";
|
|
42688
42676
|
|
|
42689
42677
|
// ../../packages/mcp-app/src/shared/video-editor-notes.ts
|
|
@@ -42743,11 +42731,11 @@ function projectNameFromPath(path2) {
|
|
|
42743
42731
|
|
|
42744
42732
|
// src/video-editor-local/notes.ts
|
|
42745
42733
|
import { randomUUID as randomUUID2, createHash as createHash2 } from "node:crypto";
|
|
42746
|
-
import { link, mkdir as
|
|
42747
|
-
import { join as
|
|
42734
|
+
import { link, mkdir as mkdir2, readFile as readFile4, readdir, rm, writeFile as writeFile2 } from "node:fs/promises";
|
|
42735
|
+
import { join as join5 } from "node:path";
|
|
42748
42736
|
async function projectNotes(directory, root, update) {
|
|
42749
42737
|
const key = createHash2("sha256").update(root).digest("hex");
|
|
42750
|
-
const folder =
|
|
42738
|
+
const folder = join5(directory, "notes", key);
|
|
42751
42739
|
const revisions = async () => {
|
|
42752
42740
|
try {
|
|
42753
42741
|
return (await readdir(folder)).filter((name) => /^[1-9]\d*\.json$/.test(name)).map((name) => Number.parseInt(name)).sort((a, b) => b - a);
|
|
@@ -42762,7 +42750,7 @@ async function projectNotes(directory, root, update) {
|
|
|
42762
42750
|
if (!latest) return { revision: 0, notes: [] };
|
|
42763
42751
|
try {
|
|
42764
42752
|
return editorNotesSchema.parse(
|
|
42765
|
-
JSON.parse(await readFile4(
|
|
42753
|
+
JSON.parse(await readFile4(join5(folder, `${latest}.json`), "utf8"))
|
|
42766
42754
|
);
|
|
42767
42755
|
} catch (error51) {
|
|
42768
42756
|
if (error51.code !== "ENOENT") throw error51;
|
|
@@ -42775,12 +42763,12 @@ async function projectNotes(directory, root, update) {
|
|
|
42775
42763
|
const current = await read();
|
|
42776
42764
|
if (current.revision !== next.revision)
|
|
42777
42765
|
throw new Error("Notes changed in another window. Reload notes before saving again.");
|
|
42778
|
-
await
|
|
42779
|
-
const temporary =
|
|
42766
|
+
await mkdir2(folder, { recursive: true, mode: 448 });
|
|
42767
|
+
const temporary = join5(folder, `${randomUUID2()}.tmp`);
|
|
42780
42768
|
const saved = { revision: current.revision + 1, notes: next.notes };
|
|
42781
42769
|
try {
|
|
42782
42770
|
await writeFile2(temporary, JSON.stringify(saved), { mode: 384, flag: "wx" });
|
|
42783
|
-
await link(temporary,
|
|
42771
|
+
await link(temporary, join5(folder, `${saved.revision}.json`));
|
|
42784
42772
|
} catch (error51) {
|
|
42785
42773
|
if (error51.code === "EEXIST")
|
|
42786
42774
|
throw new Error("Notes changed in another window. Reload notes before saving again.");
|
|
@@ -42791,19 +42779,19 @@ async function projectNotes(directory, root, update) {
|
|
|
42791
42779
|
if ((await read()).revision !== saved.revision)
|
|
42792
42780
|
throw new Error("Notes changed in another window. Reload notes before saving again.");
|
|
42793
42781
|
for (const revision of await revisions()) {
|
|
42794
|
-
if (revision < saved.revision - 2) await rm(
|
|
42782
|
+
if (revision < saved.revision - 2) await rm(join5(folder, `${revision}.json`), { force: true });
|
|
42795
42783
|
}
|
|
42796
42784
|
return saved;
|
|
42797
42785
|
}
|
|
42798
42786
|
|
|
42799
42787
|
// src/video-editor-local/project-name.ts
|
|
42800
42788
|
import { createHash as createHash3, randomUUID as randomUUID3 } from "node:crypto";
|
|
42801
|
-
import { mkdir as
|
|
42802
|
-
import { join as
|
|
42789
|
+
import { mkdir as mkdir3, readFile as readFile5, rename as rename2, rm as rm2, writeFile as writeFile3 } from "node:fs/promises";
|
|
42790
|
+
import { join as join6 } from "node:path";
|
|
42803
42791
|
async function projectName(directory, root, update) {
|
|
42804
|
-
const folder =
|
|
42792
|
+
const folder = join6(directory, "project-names");
|
|
42805
42793
|
const key = createHash3("sha256").update(root).digest("hex");
|
|
42806
|
-
const file2 =
|
|
42794
|
+
const file2 = join6(folder, `${key}.json`);
|
|
42807
42795
|
if (update === void 0) {
|
|
42808
42796
|
try {
|
|
42809
42797
|
return projectNameSchema.parse(JSON.parse(await readFile5(file2, "utf8")));
|
|
@@ -42813,8 +42801,8 @@ async function projectName(directory, root, update) {
|
|
|
42813
42801
|
}
|
|
42814
42802
|
}
|
|
42815
42803
|
const name = projectNameSchema.parse(update);
|
|
42816
|
-
await
|
|
42817
|
-
const temp =
|
|
42804
|
+
await mkdir3(folder, { recursive: true, mode: 448 });
|
|
42805
|
+
const temp = join6(folder, `${randomUUID3()}.tmp`);
|
|
42818
42806
|
try {
|
|
42819
42807
|
await writeFile3(temp, JSON.stringify(name), { mode: 384, flag: "wx" });
|
|
42820
42808
|
await rename2(temp, file2);
|
|
@@ -42827,8 +42815,8 @@ async function projectName(directory, root, update) {
|
|
|
42827
42815
|
// src/video-editor-local/relay.ts
|
|
42828
42816
|
import { openAsBlob } from "node:fs";
|
|
42829
42817
|
import { mkdtemp, rm as rm3, writeFile as writeFile4 } from "node:fs/promises";
|
|
42830
|
-
import { tmpdir
|
|
42831
|
-
import { join as
|
|
42818
|
+
import { tmpdir } from "node:os";
|
|
42819
|
+
import { join as join7 } from "node:path";
|
|
42832
42820
|
var MAX_CHUNK = 2 << 20;
|
|
42833
42821
|
var KEPT_HEADERS = [
|
|
42834
42822
|
"content-type",
|
|
@@ -42878,12 +42866,12 @@ async function httpTool(origin, call) {
|
|
|
42878
42866
|
}
|
|
42879
42867
|
const method = call.method.toUpperCase();
|
|
42880
42868
|
const body = call.body !== void 0 && method !== "GET" && method !== "HEAD" ? Buffer.from(call.body, "base64") : void 0;
|
|
42881
|
-
return
|
|
42869
|
+
return send2(origin, method, call.path, headers, body);
|
|
42882
42870
|
}
|
|
42883
42871
|
function checkPath(path2) {
|
|
42884
42872
|
if (!path2.startsWith("/") || path2.startsWith("//")) throw new Error(`bad path ${path2}`);
|
|
42885
42873
|
}
|
|
42886
|
-
async function
|
|
42874
|
+
async function send2(origin, method, path2, headers, body, signal) {
|
|
42887
42875
|
const res = await fetch(`${origin}${path2}`, {
|
|
42888
42876
|
method,
|
|
42889
42877
|
headers,
|
|
@@ -42971,9 +42959,9 @@ var UploadParts = class {
|
|
|
42971
42959
|
if (current.size + bytes.length > this.maxBytes)
|
|
42972
42960
|
throw new Error(`Upload exceeds ${this.maxBytes} bytes`);
|
|
42973
42961
|
current.abort.signal.throwIfAborted();
|
|
42974
|
-
current.directory ??= await mkdtemp(
|
|
42962
|
+
current.directory ??= await mkdtemp(join7(tmpdir(), "video-editor-upload-"));
|
|
42975
42963
|
current.abort.signal.throwIfAborted();
|
|
42976
|
-
const file2 =
|
|
42964
|
+
const file2 = join7(current.directory, "body");
|
|
42977
42965
|
await writeFile4(file2, bytes, { flag: "a", mode: 384, signal: current.abort.signal });
|
|
42978
42966
|
current.size += bytes.length;
|
|
42979
42967
|
current.idle.refresh();
|
|
@@ -42983,7 +42971,7 @@ var UploadParts = class {
|
|
|
42983
42971
|
}
|
|
42984
42972
|
const endpoint = new URL(current.path, origin);
|
|
42985
42973
|
if (endpoint.pathname === "/api/media") endpoint.pathname = `/${STREAMING_MEDIA_PATH}`;
|
|
42986
|
-
const result = await
|
|
42974
|
+
const result = await send2(
|
|
42987
42975
|
origin,
|
|
42988
42976
|
"POST",
|
|
42989
42977
|
endpoint.pathname + endpoint.search,
|
|
@@ -43094,12 +43082,12 @@ var EventFeed = class {
|
|
|
43094
43082
|
|
|
43095
43083
|
// src/video-editor-local/panel-relay.ts
|
|
43096
43084
|
async function newFile(dir, name, place) {
|
|
43097
|
-
const ext =
|
|
43098
|
-
const stem =
|
|
43085
|
+
const ext = extname(name);
|
|
43086
|
+
const stem = basename2(name, ext);
|
|
43099
43087
|
for (let n = 1; ; n++) {
|
|
43100
43088
|
const file2 = n === 1 ? name : `${stem}-${n}${ext}`;
|
|
43101
43089
|
try {
|
|
43102
|
-
await place(
|
|
43090
|
+
await place(join8(dir, file2));
|
|
43103
43091
|
return file2;
|
|
43104
43092
|
} catch (error51) {
|
|
43105
43093
|
if (error51.code !== "EEXIST") throw error51;
|
|
@@ -43109,7 +43097,7 @@ async function newFile(dir, name, place) {
|
|
|
43109
43097
|
var MEDIA_NAME = /^[^./\\\0][^/\\\0]{0,199}\.(mp4|webm|mov|m4a|weba|wav|mp3|png|jpe?g|webp|gif)$/i;
|
|
43110
43098
|
var execFileAsync = promisify(execFile3);
|
|
43111
43099
|
function registerPanelRelay(server, store, stateDirectory, direct) {
|
|
43112
|
-
void
|
|
43100
|
+
void mkdir4(stateDirectory, { recursive: true });
|
|
43113
43101
|
const sessionArg = external_exports.string().regex(/^[0-9a-f]{16}$/).optional();
|
|
43114
43102
|
const feeds = /* @__PURE__ */ new Map();
|
|
43115
43103
|
const uploads = new UploadParts();
|
|
@@ -43181,7 +43169,7 @@ function registerPanelRelay(server, store, stateDirectory, direct) {
|
|
|
43181
43169
|
},
|
|
43182
43170
|
async ({ lines }) => guarded(async () => {
|
|
43183
43171
|
await appendFile(
|
|
43184
|
-
|
|
43172
|
+
join8(stateDirectory, "panel.log"),
|
|
43185
43173
|
lines.map((line) => `${(/* @__PURE__ */ new Date()).toISOString()} ${line}
|
|
43186
43174
|
`).join("")
|
|
43187
43175
|
);
|
|
@@ -43278,9 +43266,9 @@ function registerPanelRelay(server, store, stateDirectory, direct) {
|
|
|
43278
43266
|
},
|
|
43279
43267
|
async ({ id: id2, name, offset, part, last, project }) => guarded(async () => {
|
|
43280
43268
|
const { root } = await store.session(project);
|
|
43281
|
-
const dir =
|
|
43282
|
-
await
|
|
43283
|
-
const temp =
|
|
43269
|
+
const dir = join8(root, "renders");
|
|
43270
|
+
await mkdir4(dir, { recursive: true });
|
|
43271
|
+
const temp = join8(dir, `.${id2}.part`);
|
|
43284
43272
|
const size = offset === 0 ? 0 : await stat3(temp).then(
|
|
43285
43273
|
(s) => s.size,
|
|
43286
43274
|
() => 0
|
|
@@ -43291,7 +43279,7 @@ function registerPanelRelay(server, store, stateDirectory, direct) {
|
|
|
43291
43279
|
if (!last) return { received: offset + bytes.length };
|
|
43292
43280
|
const file2 = await newFile(dir, name, (path2) => link2(temp, path2));
|
|
43293
43281
|
await rm4(temp, { force: true });
|
|
43294
|
-
return { file: `renders/${file2}`, path:
|
|
43282
|
+
return { file: `renders/${file2}`, path: join8(dir, file2) };
|
|
43295
43283
|
})
|
|
43296
43284
|
);
|
|
43297
43285
|
registerAppTool(
|
|
@@ -43310,7 +43298,7 @@ function registerPanelRelay(server, store, stateDirectory, direct) {
|
|
|
43310
43298
|
const { root } = await store.session(project);
|
|
43311
43299
|
const target = resolve2(root, path2 ?? ".");
|
|
43312
43300
|
if (!isInside(root, target)) throw new Error(`${path2} is outside the project folder.`);
|
|
43313
|
-
if (how === "open" && target !== root && !MEDIA_NAME.test(
|
|
43301
|
+
if (how === "open" && target !== root && !MEDIA_NAME.test(basename2(target)))
|
|
43314
43302
|
throw new Error("Only the project folder and its media can be opened.");
|
|
43315
43303
|
if (process.platform !== "darwin") throw new Error("Showing files needs macOS.");
|
|
43316
43304
|
await execFileAsync("open", how === "reveal" ? ["-R", target] : [target]);
|
|
@@ -43324,7 +43312,7 @@ import { spawn } from "node:child_process";
|
|
|
43324
43312
|
import { createHash as createHash4, randomUUID as randomUUID4 } from "node:crypto";
|
|
43325
43313
|
import { readFileSync as readFileSync2 } from "node:fs";
|
|
43326
43314
|
import {
|
|
43327
|
-
mkdir as
|
|
43315
|
+
mkdir as mkdir5,
|
|
43328
43316
|
readdir as readdir2,
|
|
43329
43317
|
readFile as readFile6,
|
|
43330
43318
|
rename as rename3,
|
|
@@ -43335,10 +43323,10 @@ import {
|
|
|
43335
43323
|
} from "node:fs/promises";
|
|
43336
43324
|
import { createServer as createServer3 } from "node:net";
|
|
43337
43325
|
import { homedir as homedir3 } from "node:os";
|
|
43338
|
-
import { join as
|
|
43326
|
+
import { join as join9 } from "node:path";
|
|
43339
43327
|
|
|
43340
43328
|
// src/video-editor-local/session-health.ts
|
|
43341
|
-
import { setTimeout as
|
|
43329
|
+
import { setTimeout as delay2 } from "node:timers/promises";
|
|
43342
43330
|
var PROBE_MS = 2e3;
|
|
43343
43331
|
async function request2(origin, path2, timeoutMs, read, method = "GET") {
|
|
43344
43332
|
const controller = new AbortController();
|
|
@@ -43365,7 +43353,7 @@ async function waitForDevReady(origin, exited, timeoutMs) {
|
|
|
43365
43353
|
if (exited()) return false;
|
|
43366
43354
|
const budget = deadline - Date.now();
|
|
43367
43355
|
if (budget <= 0) return false;
|
|
43368
|
-
await
|
|
43356
|
+
await delay2(Math.min(backoff, budget));
|
|
43369
43357
|
if (budget <= backoff) return false;
|
|
43370
43358
|
backoff = Math.min(backoff * 2, 1e3);
|
|
43371
43359
|
}
|
|
@@ -43397,7 +43385,7 @@ async function requestIdleStop(origin) {
|
|
|
43397
43385
|
|
|
43398
43386
|
// src/video-editor-local/session.ts
|
|
43399
43387
|
function localStateDirectory(env = process.env) {
|
|
43400
|
-
return env.VIDEO_EDITOR_LOCAL_STATE?.trim() ||
|
|
43388
|
+
return env.VIDEO_EDITOR_LOCAL_STATE?.trim() || join9(homedir3(), ".higgsfield", "video-editor-local");
|
|
43401
43389
|
}
|
|
43402
43390
|
var IDLE_MS = 60 * 60 * 1e3;
|
|
43403
43391
|
var sessionIdOf = (root) => createHash4("sha256").update(root).digest("hex").slice(0, 16);
|
|
@@ -43463,16 +43451,16 @@ var parseRecord = (text) => {
|
|
|
43463
43451
|
};
|
|
43464
43452
|
function createSessionStore(options = {}) {
|
|
43465
43453
|
const directory = options.directory ?? localStateDirectory();
|
|
43466
|
-
const projects =
|
|
43454
|
+
const projects = join9(directory, "projects");
|
|
43467
43455
|
const roots = options.roots ?? (() => configuredRoots());
|
|
43468
43456
|
const start = options.startDev ?? startDev;
|
|
43469
43457
|
const currentCli = options.cli ?? (() => cliIdentity());
|
|
43470
43458
|
const idleMs = options.idleMs ?? IDLE_MS;
|
|
43471
43459
|
const now = options.now ?? Date.now;
|
|
43472
|
-
const file2 = (id2, kind) =>
|
|
43460
|
+
const file2 = (id2, kind) => join9(projects, `${id2}.${kind}`);
|
|
43473
43461
|
const read = async (id2) => parseRecord(await readFile6(file2(id2, "json"), "utf8").catch(() => ""));
|
|
43474
43462
|
const write = async (id2, record2) => {
|
|
43475
|
-
await
|
|
43463
|
+
await mkdir5(projects, { recursive: true, mode: 448 });
|
|
43476
43464
|
const temp = `${file2(id2, "json")}.${randomUUID4()}.tmp`;
|
|
43477
43465
|
await writeFile6(temp, JSON.stringify(record2), { mode: 384 });
|
|
43478
43466
|
await rename3(temp, file2(id2, "json"));
|
|
@@ -43484,7 +43472,7 @@ function createSessionStore(options = {}) {
|
|
|
43484
43472
|
return (await Promise.all(ids.map(read))).filter((record2) => record2 !== null).sort((a, b) => b.openedAt - a.openedAt);
|
|
43485
43473
|
};
|
|
43486
43474
|
const locked = async (id2, run) => {
|
|
43487
|
-
await
|
|
43475
|
+
await mkdir5(projects, { recursive: true, mode: 448 });
|
|
43488
43476
|
const lock = file2(id2, "lock");
|
|
43489
43477
|
for (; ; ) {
|
|
43490
43478
|
const body = JSON.stringify({ pid: process.pid, at: Date.now() });
|
|
@@ -43532,7 +43520,7 @@ function createSessionStore(options = {}) {
|
|
|
43532
43520
|
const written = (await stat4(file2(id2, "used")).catch(() => null))?.mtimeMs ?? record2.openedAt;
|
|
43533
43521
|
return Math.max(written, touched.get(id2) ?? -Infinity);
|
|
43534
43522
|
};
|
|
43535
|
-
const activityDirectory = (id2) =>
|
|
43523
|
+
const activityDirectory = (id2) => join9(projects, `${id2}.activity`);
|
|
43536
43524
|
const hasActivity = async (id2) => {
|
|
43537
43525
|
const names = await readdir2(activityDirectory(id2)).catch((error51) => {
|
|
43538
43526
|
if (error51.code === "ENOENT") return [];
|
|
@@ -43541,7 +43529,7 @@ function createSessionStore(options = {}) {
|
|
|
43541
43529
|
for (const name of names) {
|
|
43542
43530
|
const owner = /^([1-9]\d*)-[0-9a-f-]{36}$/.exec(name);
|
|
43543
43531
|
if (!owner || alive(Number(owner[1]))) return true;
|
|
43544
|
-
await rm5(
|
|
43532
|
+
await rm5(join9(activityDirectory(id2), name), { force: true });
|
|
43545
43533
|
}
|
|
43546
43534
|
return false;
|
|
43547
43535
|
};
|
|
@@ -43612,9 +43600,9 @@ function createSessionStore(options = {}) {
|
|
|
43612
43600
|
record2 = { ...current, openedAt };
|
|
43613
43601
|
if (opened) await write(id2, record2);
|
|
43614
43602
|
} else {
|
|
43615
|
-
const
|
|
43603
|
+
const cli2 = currentCli();
|
|
43616
43604
|
if (opened) await write(id2, { root, openedAt });
|
|
43617
|
-
record2 = { root, ...await start(root), cli, openedAt };
|
|
43605
|
+
record2 = { root, ...await start(root), cli: cli2, openedAt };
|
|
43618
43606
|
await write(id2, record2);
|
|
43619
43607
|
}
|
|
43620
43608
|
await touch(id2, true);
|
|
@@ -43669,8 +43657,8 @@ function createSessionStore(options = {}) {
|
|
|
43669
43657
|
"The local project server changed before this operation. Retry the operation."
|
|
43670
43658
|
);
|
|
43671
43659
|
const directory2 = activityDirectory(current.id);
|
|
43672
|
-
await
|
|
43673
|
-
const path2 =
|
|
43660
|
+
await mkdir5(directory2, { recursive: true, mode: 448 });
|
|
43661
|
+
const path2 = join9(directory2, `${process.pid}-${randomUUID4()}`);
|
|
43674
43662
|
await writeFile6(path2, "", { flag: "wx", mode: 384 });
|
|
43675
43663
|
return path2;
|
|
43676
43664
|
});
|
|
@@ -43733,13 +43721,12 @@ function createSessionStore(options = {}) {
|
|
|
43733
43721
|
|
|
43734
43722
|
// src/video-editor-local/index.ts
|
|
43735
43723
|
var LOCAL_PROJECT_GUIDE = readFileSync3(new URL("./guide.md", import.meta.url), "utf8");
|
|
43736
|
-
var VIDEO_EDITOR_LOCAL_INSTRUCTIONS = "Local video editor (this Mac only): for any request to edit, cut or assemble a video in the editor, use the video_editing_* tools
|
|
43724
|
+
var VIDEO_EDITOR_LOCAL_INSTRUCTIONS = "Local video editor (this Mac only): for any request to edit, cut or assemble a video in the editor, use the video_editing_* tools. Start a new project with video_editing_create_project {path} (ask for a folder name when none is given) or open one with video_editing_open_project {path}. A project is a folder (index.tsx + media/; allowed roots: HIGGSEDIT_PROJECT_ROOTS, default ~/Downloads, ~/Movies, ~/Documents) shown in the Video Editor panel; the TSX source is the document and the panel hot-reloads it. Call video_editing_outline for element ids, then video_editing_edit to change props, text, timing or structure by id (all-or-nothing, one undo step shared with the panel). Look at footage with video_editing_media_* (probe, grab, filmstrip, waveform, transcribe, segment), check the result with video_editing_preview_frames, and render an mp4 under renders/ with video_editing_render (poll video_editing_render_status). The open and create results carry the project guide. Several projects can be open at once, each in its own panel: pass project (the session from the open or create result) to every video_editing_* call once more than one is open. Without it a tool acts on the last opened project; every result names the project it acted on.";
|
|
43737
43725
|
async function initProject(path2, roots, size = "1080x1920", fps = 30) {
|
|
43738
43726
|
const dir = await newProjectDir(path2, roots);
|
|
43739
43727
|
if (await hasProjectFile(dir)) return dir;
|
|
43740
|
-
|
|
43741
|
-
await
|
|
43742
|
-
await cliJson(["init", dir, `--size=${size}`, `--fps=${fps}`, "--json"], dir);
|
|
43728
|
+
await mkdir6(dir, { recursive: true });
|
|
43729
|
+
await cli(["init", dir, `--size=${size}`, `--fps=${fps}`], dir);
|
|
43743
43730
|
return dir;
|
|
43744
43731
|
}
|
|
43745
43732
|
var ID = external_exports.string().min(1).max(200).describe(
|
|
@@ -43794,8 +43781,6 @@ var keyed = (e) => {
|
|
|
43794
43781
|
const { id: id2, ...edit } = e;
|
|
43795
43782
|
return { key: id2, edit };
|
|
43796
43783
|
};
|
|
43797
|
-
var decode3 = (r) => JSON.parse(Buffer.from(r.body, "base64").toString());
|
|
43798
|
-
var encode3 = (value) => Buffer.from(JSON.stringify(value)).toString("base64");
|
|
43799
43784
|
function registerVideoEditorLocalTools(server, options = {}) {
|
|
43800
43785
|
const stateDirectory = options.stateDirectory ?? localStateDirectory();
|
|
43801
43786
|
const store = options.store ?? createSessionStore({ directory: stateDirectory });
|
|
@@ -43803,16 +43788,7 @@ function registerVideoEditorLocalTools(server, options = {}) {
|
|
|
43803
43788
|
const sweep = setInterval(() => void store.stopIdle().catch(() => void 0), 5 * 60 * 1e3);
|
|
43804
43789
|
sweep.unref();
|
|
43805
43790
|
}
|
|
43806
|
-
const
|
|
43807
|
-
const r = await httpTool(session.origin, {
|
|
43808
|
-
method,
|
|
43809
|
-
path: path2,
|
|
43810
|
-
...body === void 0 ? {} : { body: encode3(body) }
|
|
43811
|
-
});
|
|
43812
|
-
if (r.status >= 400)
|
|
43813
|
-
throw new Error(decode3(r).error ?? `${path2}: ${r.status}`);
|
|
43814
|
-
return decode3(r);
|
|
43815
|
-
};
|
|
43791
|
+
const dev = (session) => devApi(session.origin);
|
|
43816
43792
|
const othersOpen = async (session) => (await store.live()).filter((other) => other.id !== session.id).map((other) => `${other.name} (project: "${other.id}")`).join(", ");
|
|
43817
43793
|
const naming = async (session, project) => {
|
|
43818
43794
|
const others = project ? "" : await othersOpen(session);
|
|
@@ -43830,11 +43806,6 @@ function registerVideoEditorLocalTools(server, options = {}) {
|
|
|
43830
43806
|
await naming(session, project)
|
|
43831
43807
|
);
|
|
43832
43808
|
});
|
|
43833
|
-
const mediaScoped = (project, run) => guarded(async () => {
|
|
43834
|
-
const session = project ? await store.session(project) : await store.find().catch(() => null);
|
|
43835
|
-
const result = session ? await store.withActivity(session, () => run(session.root)) : await run(void 0);
|
|
43836
|
-
return session ? withProject(result, await naming(session, project)) : result;
|
|
43837
|
-
});
|
|
43838
43809
|
const opened = async (dir) => {
|
|
43839
43810
|
const session = await store.open(dir);
|
|
43840
43811
|
const others = await othersOpen(session);
|
|
@@ -43898,9 +43869,8 @@ ${LOCAL_PROJECT_GUIDE}`);
|
|
|
43898
43869
|
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
43899
43870
|
},
|
|
43900
43871
|
async ({ project }) => scoped(project, async (session) => {
|
|
43901
|
-
const
|
|
43902
|
-
|
|
43903
|
-
return reply({ ...describe3(session), ...rest }, text ?? JSON.stringify(rest));
|
|
43872
|
+
const { text, ...rest } = await dev(session).get("/api/outline");
|
|
43873
|
+
return reply({ ...describe3(session), ...rest }, text);
|
|
43904
43874
|
})
|
|
43905
43875
|
);
|
|
43906
43876
|
server.registerTool(
|
|
@@ -43917,7 +43887,7 @@ ${LOCAL_PROJECT_GUIDE}`);
|
|
|
43917
43887
|
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
|
|
43918
43888
|
},
|
|
43919
43889
|
async ({ name, edits, dry_run, project }) => scoped(project, async (session) => {
|
|
43920
|
-
const r = await
|
|
43890
|
+
const r = await dev(session).post("/api/edit", {
|
|
43921
43891
|
name: name ?? "Agent edit",
|
|
43922
43892
|
edits: edits.map(keyed),
|
|
43923
43893
|
...dry_run ? { dryRun: true } : {}
|
|
@@ -43949,12 +43919,9 @@ ${LOCAL_PROJECT_GUIDE}`);
|
|
|
43949
43919
|
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
|
|
43950
43920
|
},
|
|
43951
43921
|
async ({ project }) => scoped(project, async (session) => {
|
|
43952
|
-
const r = await
|
|
43953
|
-
|
|
43954
|
-
|
|
43955
|
-
);
|
|
43956
|
-
if (!r.ok) throw new Error(r.reason ?? `${title} failed`);
|
|
43957
|
-
return r;
|
|
43922
|
+
const r = await dev(session).post(path2, {});
|
|
43923
|
+
if (!r.ok) throw new Error(r.reason || `${title} failed`);
|
|
43924
|
+
return { ...r };
|
|
43958
43925
|
})
|
|
43959
43926
|
);
|
|
43960
43927
|
}
|
|
@@ -43973,7 +43940,7 @@ ${LOCAL_PROJECT_GUIDE}`);
|
|
|
43973
43940
|
annotations: { readOnlyHint: false, destructiveHint: false, openWorldHint: false }
|
|
43974
43941
|
},
|
|
43975
43942
|
async ({ file_name, from, to, depth, project }) => scoped(project, async (session) => {
|
|
43976
|
-
const { id: id2 } = await
|
|
43943
|
+
const { id: id2 } = await dev(session).post("/api/render", {
|
|
43977
43944
|
...file_name ? { fileName: file_name } : {},
|
|
43978
43945
|
...from ? { from } : {},
|
|
43979
43946
|
...to ? { to } : {},
|
|
@@ -43994,16 +43961,10 @@ ${LOCAL_PROJECT_GUIDE}`);
|
|
|
43994
43961
|
annotations: { readOnlyHint: true, openWorldHint: false }
|
|
43995
43962
|
},
|
|
43996
43963
|
async ({ job_id, project }) => scoped(project, async (session) => {
|
|
43997
|
-
const job = await api
|
|
43998
|
-
|
|
43999
|
-
|
|
44000
|
-
|
|
44001
|
-
"GET"
|
|
44002
|
-
);
|
|
44003
|
-
if (job.state !== "done") return job;
|
|
44004
|
-
const { root } = session;
|
|
44005
|
-
const path2 = join11(root, job.out);
|
|
44006
|
-
return { ...job, path: path2, media: await cliJson(["media", "probe", path2, "--json"], root) };
|
|
43964
|
+
const job = await dev(session).get(`/api/render?id=${job_id}`);
|
|
43965
|
+
if (job.state !== "done" || !job.out) return { ...job };
|
|
43966
|
+
const path2 = join10(session.root, job.out);
|
|
43967
|
+
return { ...job, path: path2, media: await dev(session).post("/api/media/probe", { path: path2 }) };
|
|
44007
43968
|
})
|
|
44008
43969
|
);
|
|
44009
43970
|
const read = { readOnlyHint: true, openWorldHint: false };
|
|
@@ -44033,39 +43994,20 @@ ${LOCAL_PROJECT_GUIDE}`);
|
|
|
44033
43994
|
}),
|
|
44034
43995
|
annotations: read
|
|
44035
43996
|
},
|
|
44036
|
-
async ({ times, width, project }) => scoped(project, async (
|
|
44037
|
-
const
|
|
44038
|
-
|
|
44039
|
-
|
|
44040
|
-
|
|
44041
|
-
|
|
44042
|
-
|
|
44043
|
-
|
|
44044
|
-
|
|
44045
|
-
|
|
44046
|
-
|
|
44047
|
-
out,
|
|
44048
|
-
...flags({ columns: Math.min(6, times.length), width: width ?? 360 })
|
|
44049
|
-
],
|
|
44050
|
-
root
|
|
44051
|
-
);
|
|
44052
|
-
return {
|
|
44053
|
-
content: [
|
|
44054
|
-
{
|
|
44055
|
-
type: "image",
|
|
44056
|
-
data: (await readFile7(out)).toString("base64"),
|
|
44057
|
-
mimeType: "image/png"
|
|
44058
|
-
}
|
|
44059
|
-
],
|
|
44060
|
-
// guarded passes a result through as is only when it has structuredContent.
|
|
44061
|
-
structuredContent: { times }
|
|
44062
|
-
};
|
|
44063
|
-
} finally {
|
|
44064
|
-
await rm6(dir, { recursive: true, force: true });
|
|
44065
|
-
}
|
|
43997
|
+
async ({ times, width, project }) => scoped(project, async (session) => {
|
|
43998
|
+
const png = await dev(session).bytes("/api/sheet", {
|
|
43999
|
+
times,
|
|
44000
|
+
columns: Math.min(6, times.length),
|
|
44001
|
+
width: width ?? 360
|
|
44002
|
+
});
|
|
44003
|
+
return {
|
|
44004
|
+
content: [{ type: "image", data: png.toString("base64"), mimeType: "image/png" }],
|
|
44005
|
+
// guarded passes a result through as is only when it has structuredContent.
|
|
44006
|
+
structuredContent: { times }
|
|
44007
|
+
};
|
|
44066
44008
|
})
|
|
44067
44009
|
);
|
|
44068
|
-
registerMediaTools(server,
|
|
44010
|
+
registerMediaTools(server, scoped);
|
|
44069
44011
|
server.registerTool(
|
|
44070
44012
|
"video_editing_fonts",
|
|
44071
44013
|
{
|
|
@@ -44075,20 +44017,19 @@ ${LOCAL_PROJECT_GUIDE}`);
|
|
|
44075
44017
|
family: external_exports.string().max(100).optional().describe("Substring of the family name, any case"),
|
|
44076
44018
|
category: external_exports.enum(["sans-serif", "serif", "display", "handwriting", "monospace"]).optional(),
|
|
44077
44019
|
cached: external_exports.boolean().optional().describe("Only families with variants already downloaded"),
|
|
44078
|
-
limit: external_exports.number().int().min(1).max(2e3).optional()
|
|
44020
|
+
limit: external_exports.number().int().min(1).max(2e3).optional(),
|
|
44021
|
+
project: PROJECT
|
|
44079
44022
|
}),
|
|
44080
44023
|
annotations: { readOnlyHint: true, openWorldHint: true }
|
|
44081
44024
|
},
|
|
44082
|
-
async ({ family, category, cached: cached2, limit }) =>
|
|
44083
|
-
|
|
44084
|
-
|
|
44085
|
-
|
|
44086
|
-
|
|
44087
|
-
|
|
44088
|
-
|
|
44089
|
-
|
|
44090
|
-
)
|
|
44091
|
-
)
|
|
44025
|
+
async ({ family, category, cached: cached2, limit, project }) => scoped(project, async (session) => {
|
|
44026
|
+
const query = new URLSearchParams();
|
|
44027
|
+
if (family) query.set("family", family);
|
|
44028
|
+
if (category) query.set("category", category);
|
|
44029
|
+
if (cached2) query.set("cached", "1");
|
|
44030
|
+
if (limit) query.set("limit", String(limit));
|
|
44031
|
+
return { ...await dev(session).get(`/api/fonts?${query}`) };
|
|
44032
|
+
})
|
|
44092
44033
|
);
|
|
44093
44034
|
server.registerTool(
|
|
44094
44035
|
"video_editing_diagnostics",
|
|
@@ -44099,7 +44040,7 @@ ${LOCAL_PROJECT_GUIDE}`);
|
|
|
44099
44040
|
annotations: read
|
|
44100
44041
|
},
|
|
44101
44042
|
async ({ project: ref }) => guarded(async () => {
|
|
44102
|
-
const r = await runCli(["doctor", "--json"],
|
|
44043
|
+
const r = await runCli(["doctor", "--json"], tmpdir2());
|
|
44103
44044
|
let doctor;
|
|
44104
44045
|
try {
|
|
44105
44046
|
doctor = JSON.parse(r.stdout);
|
|
@@ -44319,8 +44260,8 @@ import { EventEmitter } from "node:events";
|
|
|
44319
44260
|
|
|
44320
44261
|
// src/video-editor-timeline/local-store.ts
|
|
44321
44262
|
import { chmodSync, mkdirSync } from "node:fs";
|
|
44322
|
-
import { dirname as dirname3, join as
|
|
44323
|
-
function createLocalTimelineStore(path2 =
|
|
44263
|
+
import { dirname as dirname3, join as join11 } from "node:path";
|
|
44264
|
+
function createLocalTimelineStore(path2 = join11(localStateDirectory(), "timeline", "sessions.sqlite")) {
|
|
44324
44265
|
if (path2 !== ":memory:") mkdirSync(dirname3(path2), { recursive: true, mode: 448 });
|
|
44325
44266
|
const { DatabaseSync } = process.getBuiltinModule("node:sqlite");
|
|
44326
44267
|
const db = new DatabaseSync(path2, { timeout: 100 });
|
|
@@ -44452,7 +44393,7 @@ function createTimelineBroker({
|
|
|
44452
44393
|
if (!local()) return (await client()).get(sessionKey);
|
|
44453
44394
|
return (await storage()).read(sessionKey, now());
|
|
44454
44395
|
}
|
|
44455
|
-
function
|
|
44396
|
+
function decode3(value) {
|
|
44456
44397
|
if (!value)
|
|
44457
44398
|
throw new Error(
|
|
44458
44399
|
"This editor connection expired or belongs to a different account or workspace. Use the current editor context; do not edit another project."
|
|
@@ -44468,7 +44409,7 @@ function createTimelineBroker({
|
|
|
44468
44409
|
async function update(sessionKey, change) {
|
|
44469
44410
|
for (let attempt = 0; attempt < 12; attempt++) {
|
|
44470
44411
|
const before = await raw(sessionKey);
|
|
44471
|
-
const state =
|
|
44412
|
+
const state = decode3(before);
|
|
44472
44413
|
change(state);
|
|
44473
44414
|
const next = JSON.stringify(state);
|
|
44474
44415
|
if (Buffer.byteLength(next) > MAX_BYTES)
|
|
@@ -44581,7 +44522,7 @@ function createTimelineBroker({
|
|
|
44581
44522
|
const deadline = now() + 15e3;
|
|
44582
44523
|
while (!state.commands.length && now() < deadline) {
|
|
44583
44524
|
const version2 = versions.get(sessionKey);
|
|
44584
|
-
state =
|
|
44525
|
+
state = decode3(await raw(sessionKey));
|
|
44585
44526
|
writer(state, token, connectionId);
|
|
44586
44527
|
if (!state.commands.length)
|
|
44587
44528
|
await changed(sessionKey, Math.min(pollInterval(), deadline - now()), signal, version2);
|
|
@@ -44608,7 +44549,7 @@ function createTimelineBroker({
|
|
|
44608
44549
|
while (now() < command.expiresAt) {
|
|
44609
44550
|
signal?.throwIfAborted();
|
|
44610
44551
|
const version2 = versions.get(sessionKey);
|
|
44611
|
-
const state =
|
|
44552
|
+
const state = decode3(await raw(sessionKey));
|
|
44612
44553
|
if (state.results[command.id]) return state.results[command.id];
|
|
44613
44554
|
await changed(
|
|
44614
44555
|
sessionKey,
|
|
@@ -44633,7 +44574,7 @@ function createTimelineBroker({
|
|
|
44633
44574
|
for (let attempt = 0; attempt < 12; attempt++) {
|
|
44634
44575
|
const before = await raw(sessionKey);
|
|
44635
44576
|
if (!before) return;
|
|
44636
|
-
writer(
|
|
44577
|
+
writer(decode3(before), token, connectionId);
|
|
44637
44578
|
if (local()) {
|
|
44638
44579
|
if (!(await storage()).remove(sessionKey, before)) continue;
|
|
44639
44580
|
} else if (await (await client()).eval(REMOVE, 2, sessionKey, `video-editor:{${hash2(scope)}}:sessions`, before) !== 1)
|
|
@@ -44657,7 +44598,7 @@ function createTimelineBroker({
|
|
|
44657
44598
|
// src/video-editor-local/update-tools.ts
|
|
44658
44599
|
import { spawn as spawn2 } from "node:child_process";
|
|
44659
44600
|
import { existsSync as existsSync3, statSync as statSync3 } from "node:fs";
|
|
44660
|
-
import { dirname as dirname5, join as
|
|
44601
|
+
import { dirname as dirname5, join as join13 } from "node:path";
|
|
44661
44602
|
|
|
44662
44603
|
// src/video-editor-local/updates.ts
|
|
44663
44604
|
import {
|
|
@@ -44670,7 +44611,7 @@ import {
|
|
|
44670
44611
|
writeFileSync
|
|
44671
44612
|
} from "node:fs";
|
|
44672
44613
|
import { homedir as homedir4 } from "node:os";
|
|
44673
|
-
import { dirname as dirname4, join as
|
|
44614
|
+
import { dirname as dirname4, join as join12 } from "node:path";
|
|
44674
44615
|
|
|
44675
44616
|
// src/adapters/codex-plugin.ts
|
|
44676
44617
|
var PLUGIN_ROLLBACK_ERROR = "Plugin refresh failed and rollback requires attention.";
|
|
@@ -44679,6 +44620,9 @@ var identity = external_exports.object({
|
|
|
44679
44620
|
version: external_exports.string()
|
|
44680
44621
|
});
|
|
44681
44622
|
var registration = external_exports.object({ name: identity.shape.name, codex: external_exports.string().min(1) });
|
|
44623
|
+
var marketplaceList = external_exports.object({
|
|
44624
|
+
marketplaces: external_exports.array(external_exports.object({ name: external_exports.string(), root: external_exports.string() }))
|
|
44625
|
+
});
|
|
44682
44626
|
|
|
44683
44627
|
// src/video-editor-local/updates.ts
|
|
44684
44628
|
var UPDATE_PACKAGE = "@higgsfield/video-editor-mcp";
|
|
@@ -44690,14 +44634,14 @@ var stateSchema = external_exports.object({
|
|
|
44690
44634
|
error: external_exports.enum(["Update failed; keeping the installed editor.", PLUGIN_ROLLBACK_ERROR]).optional()
|
|
44691
44635
|
});
|
|
44692
44636
|
function updateOptions(dist) {
|
|
44693
|
-
const manifest = JSON.parse(readFileSync4(
|
|
44637
|
+
const manifest = JSON.parse(readFileSync4(join12(dirname4(dist), "package.json"), "utf8"));
|
|
44694
44638
|
const version2 = versionSchema.parse(manifest.version);
|
|
44695
44639
|
const channel = external_exports.enum(["next", "latest"]).parse(process.env.VIDEO_EDITOR_UPDATE_CHANNEL ?? (version2.includes("-") ? "next" : "latest"));
|
|
44696
44640
|
return {
|
|
44697
44641
|
dist,
|
|
44698
44642
|
version: version2,
|
|
44699
44643
|
channel,
|
|
44700
|
-
root:
|
|
44644
|
+
root: join12(
|
|
44701
44645
|
homedir4(),
|
|
44702
44646
|
".higgsfield/video-editor-mcp",
|
|
44703
44647
|
UPDATE_PACKAGE === "@higgsfield/video-editor-mcp" ? "public-updates" : "updates",
|
|
@@ -44707,7 +44651,7 @@ function updateOptions(dist) {
|
|
|
44707
44651
|
}
|
|
44708
44652
|
function readUpdateState(root) {
|
|
44709
44653
|
try {
|
|
44710
|
-
return stateSchema.parse(JSON.parse(readFileSync4(
|
|
44654
|
+
return stateSchema.parse(JSON.parse(readFileSync4(join12(root, "state.json"), "utf8")));
|
|
44711
44655
|
} catch {
|
|
44712
44656
|
return { checkedAt: 0 };
|
|
44713
44657
|
}
|
|
@@ -44742,13 +44686,13 @@ function newerVersion(candidate, current) {
|
|
|
44742
44686
|
return false;
|
|
44743
44687
|
}
|
|
44744
44688
|
function packageDist(prefix) {
|
|
44745
|
-
return
|
|
44689
|
+
return join12(prefix, "node_modules", UPDATE_PACKAGE, "dist");
|
|
44746
44690
|
}
|
|
44747
44691
|
function validPackage(dist, version2) {
|
|
44748
44692
|
try {
|
|
44749
|
-
const pkg = JSON.parse(readFileSync4(
|
|
44693
|
+
const pkg = JSON.parse(readFileSync4(join12(dirname4(dist), "package.json"), "utf8"));
|
|
44750
44694
|
return pkg.name === UPDATE_PACKAGE && pkg.version === version2 && ["server.mjs", "cli.mjs", "launcher.mjs", "index.html", "guide.md"].every(
|
|
44751
|
-
(file2) => existsSync2(
|
|
44695
|
+
(file2) => existsSync2(join12(dist, file2))
|
|
44752
44696
|
);
|
|
44753
44697
|
} catch {
|
|
44754
44698
|
return false;
|
|
@@ -44757,7 +44701,7 @@ function validPackage(dist, version2) {
|
|
|
44757
44701
|
function selectedDist(options) {
|
|
44758
44702
|
const { active } = readUpdateState(options.root);
|
|
44759
44703
|
if (!active || !newerVersion(active, options.version)) return options.dist;
|
|
44760
|
-
const dist = packageDist(
|
|
44704
|
+
const dist = packageDist(join12(options.root, active));
|
|
44761
44705
|
return validPackage(dist, active) ? dist : options.dist;
|
|
44762
44706
|
}
|
|
44763
44707
|
|
|
@@ -44766,7 +44710,7 @@ var EDITOR_UPDATES_TOOL = "video_editing_updates";
|
|
|
44766
44710
|
function createEditorUpdates(options, start = (done) => new Promise((resolve3, reject) => {
|
|
44767
44711
|
const child = spawn2(
|
|
44768
44712
|
process.execPath,
|
|
44769
|
-
[
|
|
44713
|
+
[join13(options.dist, "launcher.mjs"), "--update", "--force"],
|
|
44770
44714
|
{
|
|
44771
44715
|
detached: true,
|
|
44772
44716
|
stdio: "ignore"
|
|
@@ -44789,12 +44733,12 @@ function createEditorUpdates(options, start = (done) => new Promise((resolve3, r
|
|
|
44789
44733
|
let locked = false;
|
|
44790
44734
|
if (options) {
|
|
44791
44735
|
try {
|
|
44792
|
-
locked = Date.now() - statSync3(
|
|
44736
|
+
locked = Date.now() - statSync3(join13(options.root, "update.lock")).mtimeMs <= 6e5;
|
|
44793
44737
|
} catch {
|
|
44794
44738
|
}
|
|
44795
44739
|
}
|
|
44796
44740
|
return {
|
|
44797
|
-
runningVersion: options?.version ?? "
|
|
44741
|
+
runningVersion: options?.version ?? "2.0.0" ?? "Source checkout",
|
|
44798
44742
|
readyVersion: options && selectedDist(options) !== options.dist ? state.active : null,
|
|
44799
44743
|
channel: options?.channel ?? null,
|
|
44800
44744
|
supported: options !== null,
|
|
@@ -44826,7 +44770,7 @@ function createEditorUpdates(options, start = (done) => new Promise((resolve3, r
|
|
|
44826
44770
|
}
|
|
44827
44771
|
function registerEditorUpdateTools(server) {
|
|
44828
44772
|
const dist = dirname5(import.meta.filename);
|
|
44829
|
-
const options = process.env.VIDEO_EDITOR_UPDATE_LAUNCHER === "1" && existsSync3(
|
|
44773
|
+
const options = process.env.VIDEO_EDITOR_UPDATE_LAUNCHER === "1" && existsSync3(join13(dist, "launcher.mjs")) ? updateOptions(dist) : null;
|
|
44830
44774
|
const updates = createEditorUpdates(options);
|
|
44831
44775
|
registerAppTool(
|
|
44832
44776
|
server,
|
|
@@ -44858,7 +44802,7 @@ var handle = serveStdio(
|
|
|
44858
44802
|
const server = new McpServer(
|
|
44859
44803
|
{
|
|
44860
44804
|
name: "Higgsfield Video Editor (local)",
|
|
44861
|
-
version: "
|
|
44805
|
+
version: "2.0.0"
|
|
44862
44806
|
},
|
|
44863
44807
|
{ instructions: VIDEO_EDITOR_LOCAL_INSTRUCTIONS }
|
|
44864
44808
|
);
|