evomeme 0.1.10-beta.1 → 0.1.10-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +507 -389
- package/dist/skills/en-US/evomeme-cloud-fs/SKILL.md +24 -3
- package/dist/skills/en-US/evomeme-cover/SKILL.md +7 -8
- package/dist/skills/en-US/game-asset-image-generator/SKILL.md +38 -78
- package/dist/skills/en-US/game-asset-image-generator/references/background.md +1 -1
- package/dist/skills/en-US/game-asset-image-generator/references/static-game-assets.md +2 -2
- package/dist/skills/zh-CN/evomeme-cloud-fs/SKILL.md +24 -3
- package/dist/skills/zh-CN/evomeme-cover/SKILL.md +7 -8
- package/dist/skills/zh-CN/game-asset-image-generator/SKILL.md +38 -78
- package/dist/skills/zh-CN/game-asset-image-generator/references/background.md +1 -1
- package/dist/skills/zh-CN/game-asset-image-generator/references/static-game-assets.md +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -3237,8 +3237,8 @@ var require_utils = __commonJS({
|
|
|
3237
3237
|
}
|
|
3238
3238
|
return ind;
|
|
3239
3239
|
}
|
|
3240
|
-
function removeDotSegments(
|
|
3241
|
-
let input =
|
|
3240
|
+
function removeDotSegments(path60) {
|
|
3241
|
+
let input = path60;
|
|
3242
3242
|
const output = [];
|
|
3243
3243
|
let nextSlash = -1;
|
|
3244
3244
|
let len = 0;
|
|
@@ -3490,8 +3490,8 @@ var require_schemes = __commonJS({
|
|
|
3490
3490
|
wsComponent.secure = void 0;
|
|
3491
3491
|
}
|
|
3492
3492
|
if (wsComponent.resourceName) {
|
|
3493
|
-
const [
|
|
3494
|
-
wsComponent.path =
|
|
3493
|
+
const [path60, query] = wsComponent.resourceName.split("?");
|
|
3494
|
+
wsComponent.path = path60 && path60 !== "/" ? path60 : void 0;
|
|
3495
3495
|
wsComponent.query = query;
|
|
3496
3496
|
wsComponent.resourceName = void 0;
|
|
3497
3497
|
}
|
|
@@ -6909,7 +6909,7 @@ var require_windows = __commonJS({
|
|
|
6909
6909
|
module.exports = isexe;
|
|
6910
6910
|
isexe.sync = sync;
|
|
6911
6911
|
var fs15 = __require("fs");
|
|
6912
|
-
function checkPathExt(
|
|
6912
|
+
function checkPathExt(path60, options) {
|
|
6913
6913
|
var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
|
|
6914
6914
|
if (!pathext) {
|
|
6915
6915
|
return true;
|
|
@@ -6920,25 +6920,25 @@ var require_windows = __commonJS({
|
|
|
6920
6920
|
}
|
|
6921
6921
|
for (var i = 0; i < pathext.length; i++) {
|
|
6922
6922
|
var p = pathext[i].toLowerCase();
|
|
6923
|
-
if (p &&
|
|
6923
|
+
if (p && path60.substr(-p.length).toLowerCase() === p) {
|
|
6924
6924
|
return true;
|
|
6925
6925
|
}
|
|
6926
6926
|
}
|
|
6927
6927
|
return false;
|
|
6928
6928
|
}
|
|
6929
|
-
function checkStat(stat12,
|
|
6929
|
+
function checkStat(stat12, path60, options) {
|
|
6930
6930
|
if (!stat12.isSymbolicLink() && !stat12.isFile()) {
|
|
6931
6931
|
return false;
|
|
6932
6932
|
}
|
|
6933
|
-
return checkPathExt(
|
|
6933
|
+
return checkPathExt(path60, options);
|
|
6934
6934
|
}
|
|
6935
|
-
function isexe(
|
|
6936
|
-
fs15.stat(
|
|
6937
|
-
cb(er, er ? false : checkStat(stat12,
|
|
6935
|
+
function isexe(path60, options, cb) {
|
|
6936
|
+
fs15.stat(path60, function(er, stat12) {
|
|
6937
|
+
cb(er, er ? false : checkStat(stat12, path60, options));
|
|
6938
6938
|
});
|
|
6939
6939
|
}
|
|
6940
|
-
function sync(
|
|
6941
|
-
return checkStat(fs15.statSync(
|
|
6940
|
+
function sync(path60, options) {
|
|
6941
|
+
return checkStat(fs15.statSync(path60), path60, options);
|
|
6942
6942
|
}
|
|
6943
6943
|
}
|
|
6944
6944
|
});
|
|
@@ -6949,13 +6949,13 @@ var require_mode = __commonJS({
|
|
|
6949
6949
|
module.exports = isexe;
|
|
6950
6950
|
isexe.sync = sync;
|
|
6951
6951
|
var fs15 = __require("fs");
|
|
6952
|
-
function isexe(
|
|
6953
|
-
fs15.stat(
|
|
6952
|
+
function isexe(path60, options, cb) {
|
|
6953
|
+
fs15.stat(path60, function(er, stat12) {
|
|
6954
6954
|
cb(er, er ? false : checkStat(stat12, options));
|
|
6955
6955
|
});
|
|
6956
6956
|
}
|
|
6957
|
-
function sync(
|
|
6958
|
-
return checkStat(fs15.statSync(
|
|
6957
|
+
function sync(path60, options) {
|
|
6958
|
+
return checkStat(fs15.statSync(path60), options);
|
|
6959
6959
|
}
|
|
6960
6960
|
function checkStat(stat12, options) {
|
|
6961
6961
|
return stat12.isFile() && checkMode(stat12, options);
|
|
@@ -6988,7 +6988,7 @@ var require_isexe = __commonJS({
|
|
|
6988
6988
|
}
|
|
6989
6989
|
module.exports = isexe;
|
|
6990
6990
|
isexe.sync = sync;
|
|
6991
|
-
function isexe(
|
|
6991
|
+
function isexe(path60, options, cb) {
|
|
6992
6992
|
if (typeof options === "function") {
|
|
6993
6993
|
cb = options;
|
|
6994
6994
|
options = {};
|
|
@@ -6998,7 +6998,7 @@ var require_isexe = __commonJS({
|
|
|
6998
6998
|
throw new TypeError("callback not provided");
|
|
6999
6999
|
}
|
|
7000
7000
|
return new Promise(function(resolve, reject) {
|
|
7001
|
-
isexe(
|
|
7001
|
+
isexe(path60, options || {}, function(er, is) {
|
|
7002
7002
|
if (er) {
|
|
7003
7003
|
reject(er);
|
|
7004
7004
|
} else {
|
|
@@ -7007,7 +7007,7 @@ var require_isexe = __commonJS({
|
|
|
7007
7007
|
});
|
|
7008
7008
|
});
|
|
7009
7009
|
}
|
|
7010
|
-
core(
|
|
7010
|
+
core(path60, options || {}, function(er, is) {
|
|
7011
7011
|
if (er) {
|
|
7012
7012
|
if (er.code === "EACCES" || options && options.ignoreErrors) {
|
|
7013
7013
|
er = null;
|
|
@@ -7017,9 +7017,9 @@ var require_isexe = __commonJS({
|
|
|
7017
7017
|
cb(er, is);
|
|
7018
7018
|
});
|
|
7019
7019
|
}
|
|
7020
|
-
function sync(
|
|
7020
|
+
function sync(path60, options) {
|
|
7021
7021
|
try {
|
|
7022
|
-
return core.sync(
|
|
7022
|
+
return core.sync(path60, options || {});
|
|
7023
7023
|
} catch (er) {
|
|
7024
7024
|
if (options && options.ignoreErrors || er.code === "EACCES") {
|
|
7025
7025
|
return false;
|
|
@@ -7035,7 +7035,7 @@ var require_isexe = __commonJS({
|
|
|
7035
7035
|
var require_which = __commonJS({
|
|
7036
7036
|
"node_modules/which/which.js"(exports, module) {
|
|
7037
7037
|
var isWindows = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
|
|
7038
|
-
var
|
|
7038
|
+
var path60 = __require("path");
|
|
7039
7039
|
var COLON = isWindows ? ";" : ":";
|
|
7040
7040
|
var isexe = require_isexe();
|
|
7041
7041
|
var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
|
|
@@ -7073,7 +7073,7 @@ var require_which = __commonJS({
|
|
|
7073
7073
|
return opt.all && found.length ? resolve(found) : reject(getNotFoundError(cmd));
|
|
7074
7074
|
const ppRaw = pathEnv[i];
|
|
7075
7075
|
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
7076
|
-
const pCmd =
|
|
7076
|
+
const pCmd = path60.join(pathPart, cmd);
|
|
7077
7077
|
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
7078
7078
|
resolve(subStep(p, i, 0));
|
|
7079
7079
|
});
|
|
@@ -7100,7 +7100,7 @@ var require_which = __commonJS({
|
|
|
7100
7100
|
for (let i = 0; i < pathEnv.length; i++) {
|
|
7101
7101
|
const ppRaw = pathEnv[i];
|
|
7102
7102
|
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
7103
|
-
const pCmd =
|
|
7103
|
+
const pCmd = path60.join(pathPart, cmd);
|
|
7104
7104
|
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
7105
7105
|
for (let j = 0; j < pathExt.length; j++) {
|
|
7106
7106
|
const cur = p + pathExt[j];
|
|
@@ -7148,7 +7148,7 @@ var require_path_key = __commonJS({
|
|
|
7148
7148
|
var require_resolveCommand = __commonJS({
|
|
7149
7149
|
"node_modules/cross-spawn/lib/util/resolveCommand.js"(exports, module) {
|
|
7150
7150
|
"use strict";
|
|
7151
|
-
var
|
|
7151
|
+
var path60 = __require("path");
|
|
7152
7152
|
var which = require_which();
|
|
7153
7153
|
var getPathKey = require_path_key();
|
|
7154
7154
|
function resolveCommandAttempt(parsed, withoutPathExt) {
|
|
@@ -7166,7 +7166,7 @@ var require_resolveCommand = __commonJS({
|
|
|
7166
7166
|
try {
|
|
7167
7167
|
resolved = which.sync(parsed.command, {
|
|
7168
7168
|
path: env[getPathKey({ env })],
|
|
7169
|
-
pathExt: withoutPathExt ?
|
|
7169
|
+
pathExt: withoutPathExt ? path60.delimiter : void 0
|
|
7170
7170
|
});
|
|
7171
7171
|
} catch (e) {
|
|
7172
7172
|
} finally {
|
|
@@ -7175,7 +7175,7 @@ var require_resolveCommand = __commonJS({
|
|
|
7175
7175
|
}
|
|
7176
7176
|
}
|
|
7177
7177
|
if (resolved) {
|
|
7178
|
-
resolved =
|
|
7178
|
+
resolved = path60.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
|
|
7179
7179
|
}
|
|
7180
7180
|
return resolved;
|
|
7181
7181
|
}
|
|
@@ -7229,8 +7229,8 @@ var require_shebang_command = __commonJS({
|
|
|
7229
7229
|
if (!match) {
|
|
7230
7230
|
return null;
|
|
7231
7231
|
}
|
|
7232
|
-
const [
|
|
7233
|
-
const binary =
|
|
7232
|
+
const [path60, argument] = match[0].replace(/#! ?/, "").split(" ");
|
|
7233
|
+
const binary = path60.split("/").pop();
|
|
7234
7234
|
if (binary === "env") {
|
|
7235
7235
|
return argument;
|
|
7236
7236
|
}
|
|
@@ -7265,7 +7265,7 @@ var require_readShebang = __commonJS({
|
|
|
7265
7265
|
var require_parse = __commonJS({
|
|
7266
7266
|
"node_modules/cross-spawn/lib/parse.js"(exports, module) {
|
|
7267
7267
|
"use strict";
|
|
7268
|
-
var
|
|
7268
|
+
var path60 = __require("path");
|
|
7269
7269
|
var resolveCommand = require_resolveCommand();
|
|
7270
7270
|
var escape2 = require_escape();
|
|
7271
7271
|
var readShebang = require_readShebang();
|
|
@@ -7290,7 +7290,7 @@ var require_parse = __commonJS({
|
|
|
7290
7290
|
const needsShell = !isExecutableRegExp.test(commandFile);
|
|
7291
7291
|
if (parsed.options.forceShell || needsShell) {
|
|
7292
7292
|
const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
|
|
7293
|
-
parsed.command =
|
|
7293
|
+
parsed.command = path60.normalize(parsed.command);
|
|
7294
7294
|
parsed.command = escape2.command(parsed.command);
|
|
7295
7295
|
parsed.args = parsed.args.map((arg) => escape2.argument(arg, needsDoubleEscapeMetaChars));
|
|
7296
7296
|
const shellCommand = [parsed.command].concat(parsed.args).join(" ");
|
|
@@ -30414,6 +30414,7 @@ import path from "node:path";
|
|
|
30414
30414
|
|
|
30415
30415
|
// src/language/common/en-US.ts
|
|
30416
30416
|
var messages = {
|
|
30417
|
+
"error.project.missingBinding": "The workspace has no valid thread_id binding. Explicitly call evomeme_reinit_project to initialize it before submitting.",
|
|
30417
30418
|
"auth.browserLogin": "Complete login in the browser that was opened. If it did not open, visit: ",
|
|
30418
30419
|
"auth.loginSucceeded": "Login successful.",
|
|
30419
30420
|
"auth.sessionExpired": "The login session expired or was denied. Start login again.",
|
|
@@ -30520,6 +30521,7 @@ var messages = {
|
|
|
30520
30521
|
"update.remindRun": "Remind the user to run this command in a terminal:",
|
|
30521
30522
|
"update.restartIde": "Restart the IDE after updating.",
|
|
30522
30523
|
"error.network": "Network connection failed. Try again.",
|
|
30524
|
+
"error.network.timeoutPrefix": "Request timed out; limit (ms): ",
|
|
30523
30525
|
"error.http.contextSeparator": ", ",
|
|
30524
30526
|
"error.http.notFoundPrefix": "The server endpoint does not exist (",
|
|
30525
30527
|
"error.http.notFoundSuffix": "). Verify that this endpoint is deployed and check the API URL and gateway routes.",
|
|
@@ -30961,6 +30963,7 @@ var en_US_default = messages;
|
|
|
30961
30963
|
|
|
30962
30964
|
// src/language/common/zh-CN.ts
|
|
30963
30965
|
var messages2 = {
|
|
30966
|
+
"error.project.missingBinding": "当前工作区缺少有效的 thread_id 绑定,请显式调用 evomeme_reinit_project 初始化工作区后再提交。",
|
|
30964
30967
|
"auth.browserLogin": "请在打开的浏览器中完成登录(若未自动打开,请手动访问):",
|
|
30965
30968
|
"auth.loginSucceeded": "登录成功。",
|
|
30966
30969
|
"auth.sessionExpired": "登录会话已过期或已被拒绝,请重新发起登录",
|
|
@@ -31067,6 +31070,7 @@ var messages2 = {
|
|
|
31067
31070
|
"update.remindRun": "请提醒用户在终端运行:",
|
|
31068
31071
|
"update.restartIde": "更新后请重启 IDE。",
|
|
31069
31072
|
"error.network": "网络连接失败,请重试",
|
|
31073
|
+
"error.network.timeoutPrefix": "请求超时,时限(毫秒):",
|
|
31070
31074
|
"error.http.contextSeparator": ",",
|
|
31071
31075
|
"error.http.notFoundPrefix": "服务端接口不存在(",
|
|
31072
31076
|
"error.http.notFoundSuffix": ")。请确认当前环境已部署提供此接口的服务端,并检查 API 地址及网关路由。",
|
|
@@ -31541,39 +31545,43 @@ var messages3 = {
|
|
|
31541
31545
|
].join("\n"),
|
|
31542
31546
|
"login.succeeded": "Login successful.",
|
|
31543
31547
|
"login.saved": "The credential was saved to ~/.evomeme/auth.json.",
|
|
31544
|
-
"image.title": "Generate
|
|
31548
|
+
"image.title": "Generate Image",
|
|
31545
31549
|
"image.description": [
|
|
31546
|
-
"Generate
|
|
31547
|
-
"",
|
|
31548
|
-
"
|
|
31549
|
-
"
|
|
31550
|
-
'For background="transparent", use image_model="asset-max" for text-to-image. asset-pro requires exactly one reference image that already has transparency; asset-lite does not support it.'
|
|
31550
|
+
"Generate an image using the same client capability as the canvas, with model, background, preset size and prompt.",
|
|
31551
|
+
"Poll until success or failure; save the result under workspace assets and return only text metadata such as asset_id, local path and image URL, without image Base64.",
|
|
31552
|
+
'Defaults: model="asset-pro", background="opaque", size="2048x2048". Transparent text-to-image and auto background require asset-max. asset-lite ignores opaque background settings.',
|
|
31553
|
+
"This tool generates an image. Invoke smart cutout separately for background removal, or use color removal if smart cutout is unavailable."
|
|
31551
31554
|
].join("\n"),
|
|
31552
31555
|
"image.prompt": "Image generation prompt. Required.",
|
|
31553
|
-
"image.
|
|
31554
|
-
"image.
|
|
31555
|
-
"image.
|
|
31556
|
-
"image.
|
|
31557
|
-
"image.background": "Optional background mode. auto uses the provider default on Pro/Lite. Lite rejects transparent. Pro transparent requires one reference image with transparency. Max supports all three modes.",
|
|
31558
|
-
"image.workspace": "Optional absolute Agent workspace path. Defaults to the MCP process working directory.",
|
|
31556
|
+
"image.size": "Preset size, default 2048x2048. Must be supported by the selected model. asset-lite does not support 1024x1024; asset-max dimensions must satisfy its 16-pixel multiple constraint.",
|
|
31557
|
+
"image.model": "Model, default asset-pro. Options: asset-max, asset-pro, asset-lite.",
|
|
31558
|
+
"image.background": "Background, default opaque. auto and transparent without references require asset-max. asset-lite does not offer background switching.",
|
|
31559
|
+
"image.workspace": "Optional absolute workspace path. Defaults to the MCP process working directory. Source asset IDs are relative to this workspace.",
|
|
31559
31560
|
"image.missingPrompt": "Missing required parameter: prompt",
|
|
31560
|
-
"image.
|
|
31561
|
-
"image.
|
|
31562
|
-
"image.invalidModel": "Invalid image_model: ",
|
|
31563
|
-
"image.invalidBackground": "Invalid background: ",
|
|
31564
|
-
"image.emptyReferences": "reference_image_url cannot be empty",
|
|
31565
|
-
"image.tooManyReferences": "reference_image_url supports at most 14 reference images",
|
|
31561
|
+
"image.invalidSize": "Preset size is not supported by the selected model: ",
|
|
31562
|
+
"image.autoBackgroundMax": "auto background requires asset-max.",
|
|
31566
31563
|
"image.completed": "Image generation completed",
|
|
31567
|
-
"
|
|
31564
|
+
"imageTool.assetId": "Workspace image asset ID, such as assets/hero.png. Use the asset_id returned by an image tool.",
|
|
31565
|
+
"imageTool.unknownParameter": "Unsupported parameter: ",
|
|
31566
|
+
"imageTool.invalidParameter": "Invalid parameter: ",
|
|
31567
|
+
"imageTool.missingParameter": "Missing required parameter: ",
|
|
31568
|
+
"imageTool.sourceRequired": "Provide exactly one of id or image_url.",
|
|
31569
|
+
"imageTool.invalidUrl": "image_url must be a valid HTTP/HTTPS image URL.",
|
|
31570
|
+
"cutout.title": "Smart Cutout",
|
|
31568
31571
|
"cutout.description": [
|
|
31569
|
-
"
|
|
31570
|
-
"",
|
|
31571
|
-
"
|
|
31572
|
+
"Use the same smart-cutout client capability as the canvas. Provide exactly one workspace image id or image_url.",
|
|
31573
|
+
"Poll the mask job, compose a transparent PNG locally and upload it. Return only text metadata such as asset_id, local path and image URL, without image Base64.",
|
|
31574
|
+
"Errors are passed through to the client. If the service is unavailable, invoke evomeme_color_key on the original asset."
|
|
31572
31575
|
].join("\n"),
|
|
31573
|
-
"cutout.imageUrl": "
|
|
31574
|
-
"cutout.
|
|
31575
|
-
"
|
|
31576
|
-
"
|
|
31576
|
+
"cutout.imageUrl": "HTTP/HTTPS source image URL; provide this or id.",
|
|
31577
|
+
"cutout.completed": "Smart cutout completed",
|
|
31578
|
+
"colorKey.title": "Remove Color",
|
|
31579
|
+
"colorKey.description": "Use the same local src/image algorithm as canvas color removal to produce a transparent PNG. Does not require the smart-cutout service or authentication and can be used when smart cutout is unavailable. Input a workspace source image id; return only text metadata such as asset_id and local path, without image Base64.",
|
|
31580
|
+
"colorKey.color": "Color to remove, #RRGGBB, default #ffffff.",
|
|
31581
|
+
"colorKey.strength": "Removal strength from 0 to 100, default 80.",
|
|
31582
|
+
"colorKey.contiguousOnly": "Only remove matching regions connected to an image boundary, default false.",
|
|
31583
|
+
"colorKey.despill": "Remove background-color spill from retained edge pixels, default false.",
|
|
31584
|
+
"colorKey.completed": "Color removal completed",
|
|
31577
31585
|
"video.title": "Generate Game Video",
|
|
31578
31586
|
"video.description": [
|
|
31579
31587
|
"Generate a game video from a prompt and poll the submitted job until it succeeds or fails.",
|
|
@@ -31611,17 +31619,22 @@ var messages3 = {
|
|
|
31611
31619
|
"",
|
|
31612
31620
|
"Before calling, briefly review the main source files for unsafe behavior such as download-and-execute code, reverse shells, miners, long encoded eval payloads, or suspicious install scripts.",
|
|
31613
31621
|
"",
|
|
31614
|
-
"Flow: sign in → read
|
|
31622
|
+
"Flow: sign in → read the existing project binding → collect files using .evomemeignore → submit once → store checkpoint_id on success.",
|
|
31623
|
+
"Missing bindings and submission failures return the actual error without creating a thread, re-authenticating to resubmit, or retrying. For a new thread, explicitly call evomeme_reinit_project and then submit separately.",
|
|
31615
31624
|
"Binary assets cannot be submitted as source. Upload them with evomeme_upload_game_asset, add their paths to .evomemeignore, write asset_url to /public/config.json, rebuild, and submit again.",
|
|
31616
31625
|
"",
|
|
31617
31626
|
"Optional parameters: name changes the project display name; cover_url updates the game cover already uploaded to TOS."
|
|
31618
31627
|
].join("\n"),
|
|
31619
31628
|
"submit.workspace": "Absolute workspace root. Defaults to the MCP process working directory, usually the project opened by the IDE.",
|
|
31620
|
-
"submit.name": "Optional project display name. Updates the cloud name
|
|
31629
|
+
"submit.name": "Optional project display name. Updates the cloud name.",
|
|
31621
31630
|
"submit.cover": "Optional game cover URL. It must be a public image URL already uploaded to TOS.",
|
|
31622
31631
|
"submit.succeeded": "Code submission succeeded.",
|
|
31623
31632
|
"submit.workspaceLabel": "Workspace: ",
|
|
31624
31633
|
"submit.fileCountLabel": "File count: ",
|
|
31634
|
+
"reinit.title": "Reinitialize Project Binding",
|
|
31635
|
+
"reinit.description": "Create a new cloud thread for the workspace, then replace thread_id in .evomeme/config.json and clear the old checkpoint_id only after creation succeeds. Always creates a new ID, even with an existing binding; also supports first initialization. Only creates and binds: no file submission, deletion of the old cloud project, or automatic retry. Failures return the actual error and preserve the old binding. Call only when the user explicitly requests initialization or rebinding, never as automatic recovery after submission failure.",
|
|
31636
|
+
"reinit.name": "Optional display name for the new cloud project.",
|
|
31637
|
+
"reinit.succeeded": "Workspace project binding initialized successfully.",
|
|
31625
31638
|
"upload.title": "Upload Game Asset",
|
|
31626
31639
|
"upload.description": [
|
|
31627
31640
|
"Send a local binary file to the evomeme server for upload to TOS and return a public asset_url.",
|
|
@@ -31670,39 +31683,43 @@ var messages4 = {
|
|
|
31670
31683
|
].join("\n"),
|
|
31671
31684
|
"login.succeeded": "登录成功。",
|
|
31672
31685
|
"login.saved": "凭证已写入 ~/.evomeme/auth.json。",
|
|
31673
|
-
"image.title": "
|
|
31686
|
+
"image.title": "图片生成",
|
|
31674
31687
|
"image.description": [
|
|
31675
|
-
"
|
|
31676
|
-
"",
|
|
31677
|
-
"
|
|
31678
|
-
"
|
|
31679
|
-
'background="transparent":文生透明图使用 image_model="asset-max";asset-pro 必须提供恰好一张本身带透明通道的参考图;asset-lite 不支持。'
|
|
31688
|
+
"与画布图片生成功能共用客户端能力,按模型、背景、预设尺寸和提示词生成图片。",
|
|
31689
|
+
"工具持续轮询到成功或失败;成功后保存到工作区 assets,仅返回 asset_id、本地路径、图片 URL 等文本元数据,不返回图片 Base64。",
|
|
31690
|
+
'默认 model="asset-pro"、background="opaque"、size="2048x2048"。透明文生图使用 asset-max;auto 背景仅 asset-max 可选,asset-lite 忽略不透明背景设置。',
|
|
31691
|
+
"本工具仅生成图片。需要去除背景时,另行调用智能抠图;智能抠图不可用时可使用颜色剔除。"
|
|
31680
31692
|
].join("\n"),
|
|
31681
31693
|
"image.prompt": "生图提示词,必填。",
|
|
31682
|
-
"image.
|
|
31683
|
-
"image.
|
|
31684
|
-
"image.
|
|
31685
|
-
"image.
|
|
31686
|
-
"image.background": "可选背景模式。auto 在 Pro/Lite 中使用上游默认背景;Lite 不支持 transparent;Pro 的 transparent 必须提供一张带透明通道的参考图;Max 支持全部三种模式。",
|
|
31687
|
-
"image.workspace": "可选,Agent 工作区绝对路径;默认使用 MCP 进程当前工作目录。",
|
|
31694
|
+
"image.size": "预设尺寸,默认 2048x2048;必须使用所选模型支持的预设。asset-lite 不支持 1024x1024;asset-max 的尺寸须满足其 16 像素倍数限制。",
|
|
31695
|
+
"image.model": "模型,默认 asset-pro;可选 asset-max、asset-pro、asset-lite。",
|
|
31696
|
+
"image.background": "背景,默认 opaque。auto 仅 asset-max 支持;无参考图的 transparent 仅 asset-max 支持;asset-lite 不提供背景切换。",
|
|
31697
|
+
"image.workspace": "可选,工作区绝对路径;默认 MCP 进程当前目录。源素材 ID 相对于该工作区。",
|
|
31688
31698
|
"image.missingPrompt": "缺少必填参数 prompt",
|
|
31689
|
-
"image.
|
|
31690
|
-
"image.
|
|
31691
|
-
"image.
|
|
31692
|
-
"
|
|
31693
|
-
"
|
|
31694
|
-
"
|
|
31695
|
-
"
|
|
31696
|
-
"
|
|
31699
|
+
"image.invalidSize": "所选模型不支持此预设尺寸:",
|
|
31700
|
+
"image.autoBackgroundMax": "auto 背景仅适用于 asset-max。",
|
|
31701
|
+
"image.completed": "图片生成已完成",
|
|
31702
|
+
"imageTool.assetId": "工作区图片素材 ID,例如 assets/hero.png;可直接使用图片工具返回的 asset_id。",
|
|
31703
|
+
"imageTool.unknownParameter": "不支持的参数:",
|
|
31704
|
+
"imageTool.invalidParameter": "无效的参数:",
|
|
31705
|
+
"imageTool.missingParameter": "缺少必填参数 ",
|
|
31706
|
+
"imageTool.sourceRequired": "必须且只能提供 id 或 image_url 中的一个。",
|
|
31707
|
+
"imageTool.invalidUrl": "image_url 必须是有效的 HTTP/HTTPS 图片 URL。",
|
|
31708
|
+
"cutout.title": "智能抠图",
|
|
31697
31709
|
"cutout.description": [
|
|
31698
|
-
"
|
|
31699
|
-
"",
|
|
31700
|
-
"
|
|
31710
|
+
"与画布智能抠图共用客户端能力。通过 id 指定工作区图片,或提供 image_url,两者必须且只能提供一个。",
|
|
31711
|
+
"持续轮询蒙版任务,然后在本地合成透明背景 PNG 并上传,仅返回 asset_id、本地路径、图片 URL 等文本元数据,不返回图片 Base64。",
|
|
31712
|
+
"错误会透传给客户端;服务不可用时,可另行使用 evomeme_color_key 对原始素材进行颜色剔除。"
|
|
31701
31713
|
].join("\n"),
|
|
31702
|
-
"cutout.imageUrl": "
|
|
31703
|
-
"cutout.
|
|
31704
|
-
"
|
|
31705
|
-
"
|
|
31714
|
+
"cutout.imageUrl": "待抠图的 HTTP/HTTPS 原图 URL;与 id 二选一。",
|
|
31715
|
+
"cutout.completed": "智能抠图已完成",
|
|
31716
|
+
"colorKey.title": "颜色剔除",
|
|
31717
|
+
"colorKey.description": "与画布颜色剔除共用 src/image 的本地算法。按指定颜色生成透明 PNG;不依赖智能抠图服务或登录,可在智能抠图不可用时使用。输入工作区原图 id,仅返回 asset_id、本地路径等文本元数据,不返回图片 Base64。",
|
|
31718
|
+
"colorKey.color": "剔除颜色,格式 #RRGGBB,默认 #ffffff。",
|
|
31719
|
+
"colorKey.strength": "剔除强度,0–100,默认 80。",
|
|
31720
|
+
"colorKey.contiguousOnly": "是否仅剔除与图像边界相连的连续区域,默认 false。",
|
|
31721
|
+
"colorKey.despill": "是否滤色,消除保留边缘像素中的背景色溢出,默认 false。",
|
|
31722
|
+
"colorKey.completed": "颜色剔除已完成",
|
|
31706
31723
|
"video.title": "生成游戏视频",
|
|
31707
31724
|
"video.description": [
|
|
31708
31725
|
"根据提示词生成游戏视频,提交任务后持续轮询直到成功或失败。",
|
|
@@ -31740,17 +31757,22 @@ var messages4 = {
|
|
|
31740
31757
|
"",
|
|
31741
31758
|
"调用前请快速阅读将提交的主要源码,做一次浅层安全复检。若发现下载执行、反弹壳、挖矿、长编码 eval、可疑 install 脚本等危险代码,不要调用本工具,并告知用户。",
|
|
31742
31759
|
"",
|
|
31743
|
-
"流程:检查/完成登录 →
|
|
31760
|
+
"流程:检查/完成登录 → 读取已有作品绑定 → 按 .evomemeignore 收集文件(必须包含 dist/)→ 提交一次 → 成功后写入 checkpoint_id。",
|
|
31761
|
+
"缺少绑定或提交失败时直接返回真实错误,不自动创建 thread、重新登录后提交或重试。需要新 thread 时,显式调用 evomeme_reinit_project,成功后再另行提交。",
|
|
31744
31762
|
"二进制资源不能作为源码直接提交;请先用 evomeme_upload_game_asset 上传,把本地路径加入 .evomemeignore,并将 asset_url 写入 /public/config.json,再重新构建并提交。",
|
|
31745
31763
|
"",
|
|
31746
31764
|
"可选参数:name 用于修改作品显示名称;cover_url 用于更新已上传到 TOS 的游戏封面。"
|
|
31747
31765
|
].join("\n"),
|
|
31748
31766
|
"submit.workspace": "工作区根目录绝对路径。省略时使用 MCP 进程当前工作目录(通常即 IDE 打开的项目根)。",
|
|
31749
|
-
"submit.name": "
|
|
31767
|
+
"submit.name": "作品显示名称(可选)。传入时更新云端作品名。",
|
|
31750
31768
|
"submit.cover": "游戏封面图 URL(可选)。必须是已经上传到 TOS 的公开图片地址。",
|
|
31751
31769
|
"submit.succeeded": "代码提交成功。",
|
|
31752
31770
|
"submit.workspaceLabel": "工作区:",
|
|
31753
31771
|
"submit.fileCountLabel": "文件数:",
|
|
31772
|
+
"reinit.title": "重新初始化作品绑定",
|
|
31773
|
+
"reinit.description": "为当前工作区创建一个新的云端 thread,并在创建成功后替换 .evomeme/config.json 中的 thread_id、清除旧 checkpoint_id。即使已有绑定也创建新 id;没有绑定时可用于首次初始化。只负责创建与绑定,不提交文件、不删除旧云端作品、不自动重试。失败直接返回真实错误,保留旧绑定。只在用户明确需要初始化或重新绑定时调用,不能作为提交失败后的自动恢复步骤。",
|
|
31774
|
+
"reinit.name": "新建云端作品的显示名称(可选)。",
|
|
31775
|
+
"reinit.succeeded": "工作区作品绑定初始化成功。",
|
|
31754
31776
|
"upload.title": "上传游戏素材",
|
|
31755
31777
|
"upload.description": [
|
|
31756
31778
|
"将本地二进制文件交给 evomeme服务端上传到对象存储(TOS),返回公开可访问的 asset_url。",
|
|
@@ -32072,10 +32094,10 @@ function assignProp(target, prop, value) {
|
|
|
32072
32094
|
configurable: true
|
|
32073
32095
|
});
|
|
32074
32096
|
}
|
|
32075
|
-
function getElementAtPath(obj,
|
|
32076
|
-
if (!
|
|
32097
|
+
function getElementAtPath(obj, path60) {
|
|
32098
|
+
if (!path60)
|
|
32077
32099
|
return obj;
|
|
32078
|
-
return
|
|
32100
|
+
return path60.reduce((acc, key) => acc?.[key], obj);
|
|
32079
32101
|
}
|
|
32080
32102
|
function promiseAllObject(promisesObj) {
|
|
32081
32103
|
const keys = Object.keys(promisesObj);
|
|
@@ -32395,11 +32417,11 @@ function aborted(x, startIndex = 0) {
|
|
|
32395
32417
|
}
|
|
32396
32418
|
return false;
|
|
32397
32419
|
}
|
|
32398
|
-
function prefixIssues(
|
|
32420
|
+
function prefixIssues(path60, issues) {
|
|
32399
32421
|
return issues.map((iss) => {
|
|
32400
32422
|
var _a;
|
|
32401
32423
|
(_a = iss).path ?? (_a.path = []);
|
|
32402
|
-
iss.path.unshift(
|
|
32424
|
+
iss.path.unshift(path60);
|
|
32403
32425
|
return iss;
|
|
32404
32426
|
});
|
|
32405
32427
|
}
|
|
@@ -39153,7 +39175,7 @@ var StdioClientTransport = class {
|
|
|
39153
39175
|
};
|
|
39154
39176
|
|
|
39155
39177
|
// src/version.ts
|
|
39156
|
-
var VERSION = "0.1.10-beta.
|
|
39178
|
+
var VERSION = "0.1.10-beta.3";
|
|
39157
39179
|
|
|
39158
39180
|
// src/publishChannel.generated.ts
|
|
39159
39181
|
var PUBLISH_NPM_NAME = "evomeme";
|
|
@@ -39581,6 +39603,7 @@ import fs7 from "node:fs";
|
|
|
39581
39603
|
import path7 from "node:path";
|
|
39582
39604
|
import os5 from "node:os";
|
|
39583
39605
|
var MCP_SERVER_NAME4 = "evomeme";
|
|
39606
|
+
var MCP_TOOL_TIMEOUT_MS = 30 * 60 * 1e3;
|
|
39584
39607
|
function getWorkbuddyConfigPath(homeDir) {
|
|
39585
39608
|
return path7.join(homeDir ?? os5.homedir(), ".workbuddy", "mcp.json");
|
|
39586
39609
|
}
|
|
@@ -39595,7 +39618,8 @@ function mergeWorkbuddyMcpConfig(configPath, options) {
|
|
|
39595
39618
|
const serverEntry = {
|
|
39596
39619
|
type: "stdio",
|
|
39597
39620
|
command: options.launcher.command,
|
|
39598
|
-
args: [...options.launcher.args]
|
|
39621
|
+
args: [...options.launcher.args],
|
|
39622
|
+
timeout: MCP_TOOL_TIMEOUT_MS
|
|
39599
39623
|
};
|
|
39600
39624
|
const envValues = options.env ?? {};
|
|
39601
39625
|
if (Object.keys(envValues).length > 0) {
|
|
@@ -39642,6 +39666,7 @@ import fs8 from "node:fs";
|
|
|
39642
39666
|
import path8 from "node:path";
|
|
39643
39667
|
import os6 from "node:os";
|
|
39644
39668
|
var MCP_SERVER_NAME5 = "evomeme";
|
|
39669
|
+
var MCP_TOOL_TIMEOUT_MS2 = 30 * 60 * 1e3;
|
|
39645
39670
|
var TRAE_APP_DIR_NAME = "TRAE SOLO CN";
|
|
39646
39671
|
function getTraeAppDataDir(options = {}) {
|
|
39647
39672
|
if (options.appDataDir) {
|
|
@@ -39679,12 +39704,9 @@ function mergeTraeMcpConfig(configPath, options) {
|
|
|
39679
39704
|
const mcpServers = root.mcpServers && typeof root.mcpServers === "object" && !Array.isArray(root.mcpServers) ? { ...root.mcpServers } : {};
|
|
39680
39705
|
const serverEntry = {
|
|
39681
39706
|
command: options.launcher.command,
|
|
39682
|
-
args: [...options.launcher.args]
|
|
39707
|
+
args: [...options.launcher.args],
|
|
39708
|
+
env: { ...options.env, RUN_MCP_TIMEOUT_MS: String(MCP_TOOL_TIMEOUT_MS2) }
|
|
39683
39709
|
};
|
|
39684
|
-
const envValues = options.env ?? {};
|
|
39685
|
-
if (Object.keys(envValues).length > 0) {
|
|
39686
|
-
serverEntry.env = { ...envValues };
|
|
39687
|
-
}
|
|
39688
39710
|
mcpServers[MCP_SERVER_NAME5] = serverEntry;
|
|
39689
39711
|
const nextRoot = {
|
|
39690
39712
|
...root,
|
|
@@ -39767,6 +39789,41 @@ var NetworkError = class extends Error {
|
|
|
39767
39789
|
this.name = "NetworkError";
|
|
39768
39790
|
}
|
|
39769
39791
|
};
|
|
39792
|
+
function networkRequestError(method, url, cause, timeoutMs, timedOut) {
|
|
39793
|
+
const requestUrl = new URL(url);
|
|
39794
|
+
const details = /* @__PURE__ */ new Set();
|
|
39795
|
+
const seen = /* @__PURE__ */ new Set();
|
|
39796
|
+
function collect(value) {
|
|
39797
|
+
if (value == null || seen.has(value) || seen.size >= 12) return;
|
|
39798
|
+
seen.add(value);
|
|
39799
|
+
if (typeof value === "string") {
|
|
39800
|
+
details.add(value);
|
|
39801
|
+
return;
|
|
39802
|
+
}
|
|
39803
|
+
if (typeof value !== "object") return;
|
|
39804
|
+
const error2 = value;
|
|
39805
|
+
const code = typeof error2.code === "string" ? error2.code : "";
|
|
39806
|
+
const message = typeof error2.message === "string" ? error2.message : "";
|
|
39807
|
+
if (code || message) details.add([code, message].filter(Boolean).join(": "));
|
|
39808
|
+
collect(error2.cause);
|
|
39809
|
+
if (Array.isArray(error2.errors)) error2.errors.forEach(collect);
|
|
39810
|
+
}
|
|
39811
|
+
collect(cause);
|
|
39812
|
+
const safeDetails = [...details].map((detail) => detail.replace(/https?:\/\/[^\s"'<>]+/gi, (raw) => {
|
|
39813
|
+
try {
|
|
39814
|
+
const parsed = new URL(raw);
|
|
39815
|
+
return `${parsed.origin}${parsed.pathname}`;
|
|
39816
|
+
} catch {
|
|
39817
|
+
return "[URL]";
|
|
39818
|
+
}
|
|
39819
|
+
}));
|
|
39820
|
+
return new NetworkError([
|
|
39821
|
+
t("error.network"),
|
|
39822
|
+
`${method} ${requestUrl.origin}${requestUrl.pathname}`,
|
|
39823
|
+
...timedOut ? [t("error.network.timeoutPrefix") + timeoutMs] : [],
|
|
39824
|
+
...safeDetails
|
|
39825
|
+
].join("\n"), cause);
|
|
39826
|
+
}
|
|
39770
39827
|
var HttpResponseError = class extends Error {
|
|
39771
39828
|
constructor(status, method, url) {
|
|
39772
39829
|
const parsed = new URL(url);
|
|
@@ -39834,14 +39891,15 @@ async function performRequest(config2, fetchFn, request) {
|
|
|
39834
39891
|
const controller = new AbortController();
|
|
39835
39892
|
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
39836
39893
|
let response;
|
|
39894
|
+
let rawBody;
|
|
39837
39895
|
try {
|
|
39838
39896
|
response = await fetchFn(url, { method: request.method, headers, body, signal: controller.signal });
|
|
39897
|
+
rawBody = await response.text();
|
|
39839
39898
|
} catch (error2) {
|
|
39840
|
-
throw
|
|
39899
|
+
throw networkRequestError(request.method, url, error2, timeoutMs, controller.signal.aborted);
|
|
39841
39900
|
} finally {
|
|
39842
39901
|
clearTimeout(timer);
|
|
39843
39902
|
}
|
|
39844
|
-
const rawBody = await response.text();
|
|
39845
39903
|
let envelope;
|
|
39846
39904
|
try {
|
|
39847
39905
|
envelope = parseEnvelope(rawBody);
|
|
@@ -39859,8 +39917,8 @@ async function performRequest(config2, fetchFn, request) {
|
|
|
39859
39917
|
}
|
|
39860
39918
|
return envelope.data;
|
|
39861
39919
|
}
|
|
39862
|
-
function buildUrl(baseUrl,
|
|
39863
|
-
const url = new URL(`${baseUrl}${
|
|
39920
|
+
function buildUrl(baseUrl, path60, query) {
|
|
39921
|
+
const url = new URL(`${baseUrl}${path60.startsWith("/") ? path60 : `/${path60}`}`);
|
|
39864
39922
|
if (query) {
|
|
39865
39923
|
for (const [key, value] of Object.entries(query)) {
|
|
39866
39924
|
if (value !== void 0) {
|
|
@@ -39998,11 +40056,11 @@ async function uploadTosAsset(token, bytes, input = {}, options = {}) {
|
|
|
39998
40056
|
async function uploadTosModelAsset(token, bytes, input = {}, options = {}) {
|
|
39999
40057
|
return uploadApprovedTosAsset("/v1/tos/upload/model", 20 * 6e4, token, bytes, input, options);
|
|
40000
40058
|
}
|
|
40001
|
-
async function uploadApprovedTosAsset(
|
|
40059
|
+
async function uploadApprovedTosAsset(path60, timeoutMs, token, bytes, input, options) {
|
|
40002
40060
|
const client = createPluginServerClient(options);
|
|
40003
40061
|
const data = await client.request({
|
|
40004
40062
|
method: "PUT",
|
|
40005
|
-
path:
|
|
40063
|
+
path: path60,
|
|
40006
40064
|
token,
|
|
40007
40065
|
query: {
|
|
40008
40066
|
folder: input.folder,
|
|
@@ -40081,7 +40139,6 @@ function isMediaUploadStatus(value) {
|
|
|
40081
40139
|
}
|
|
40082
40140
|
|
|
40083
40141
|
// src/api/imageApi.ts
|
|
40084
|
-
var GAME_IMAGE_TYPES = ["asset", "background"];
|
|
40085
40142
|
var GAME_IMAGE_SIZES = [
|
|
40086
40143
|
"1024x1024",
|
|
40087
40144
|
"2048x2048",
|
|
@@ -40796,6 +40853,12 @@ import fs12 from "node:fs";
|
|
|
40796
40853
|
import path12 from "node:path";
|
|
40797
40854
|
|
|
40798
40855
|
// src/project/errors.ts
|
|
40856
|
+
var MissingProjectBindingError = class extends Error {
|
|
40857
|
+
constructor() {
|
|
40858
|
+
super(t("error.project.missingBinding"));
|
|
40859
|
+
this.name = "MissingProjectBindingError";
|
|
40860
|
+
}
|
|
40861
|
+
};
|
|
40799
40862
|
var BinaryFileError = class extends Error {
|
|
40800
40863
|
constructor(filePath) {
|
|
40801
40864
|
super(
|
|
@@ -40907,9 +40970,9 @@ async function createAndBindProject(workspaceDir, token, options = {}) {
|
|
|
40907
40970
|
|
|
40908
40971
|
// src/project/submit.ts
|
|
40909
40972
|
async function submitWorkspaceCode(workspaceDir, token, options = {}) {
|
|
40910
|
-
|
|
40973
|
+
const config2 = loadProjectConfig(workspaceDir);
|
|
40911
40974
|
if (!config2) {
|
|
40912
|
-
|
|
40975
|
+
throw new MissingProjectBindingError();
|
|
40913
40976
|
}
|
|
40914
40977
|
const { files } = collectWorkspaceFiles(workspaceDir, options);
|
|
40915
40978
|
const clientOptions = {
|
|
@@ -40920,29 +40983,14 @@ async function submitWorkspaceCode(workspaceDir, token, options = {}) {
|
|
|
40920
40983
|
name: options.name?.trim() || void 0,
|
|
40921
40984
|
coverUrl: options.coverUrl?.trim() || void 0
|
|
40922
40985
|
};
|
|
40923
|
-
|
|
40924
|
-
|
|
40925
|
-
|
|
40926
|
-
|
|
40927
|
-
|
|
40928
|
-
|
|
40929
|
-
|
|
40930
|
-
|
|
40931
|
-
);
|
|
40932
|
-
} catch (error2) {
|
|
40933
|
-
if (!(error2 instanceof ThreadInvalidError)) {
|
|
40934
|
-
throw error2;
|
|
40935
|
-
}
|
|
40936
|
-
config2 = await createAndBindProject(workspaceDir, token, options);
|
|
40937
|
-
return await submitAndRecordCheckpoint(
|
|
40938
|
-
workspaceDir,
|
|
40939
|
-
token,
|
|
40940
|
-
config2.threadId,
|
|
40941
|
-
files,
|
|
40942
|
-
clientOptions,
|
|
40943
|
-
meta
|
|
40944
|
-
);
|
|
40945
|
-
}
|
|
40986
|
+
return await submitAndRecordCheckpoint(
|
|
40987
|
+
workspaceDir,
|
|
40988
|
+
token,
|
|
40989
|
+
config2.threadId,
|
|
40990
|
+
files,
|
|
40991
|
+
clientOptions,
|
|
40992
|
+
meta
|
|
40993
|
+
);
|
|
40946
40994
|
}
|
|
40947
40995
|
async function submitAndRecordCheckpoint(workspaceDir, token, threadId, files, clientOptions, meta) {
|
|
40948
40996
|
const result = await submitProject(
|
|
@@ -45565,10 +45613,6 @@ async function executeImageGeneration(workspaceDir, body, imageServiceDeps) {
|
|
|
45565
45613
|
if (!completed?.outputAssetId || !completed.outputLocalPath) {
|
|
45566
45614
|
throw new Error(t("error.task.imageOutputMissing"));
|
|
45567
45615
|
}
|
|
45568
|
-
if (body.image_type === "asset") {
|
|
45569
|
-
const result = await executeImageCutout(workspaceDir, { image_url: generated.assetUrl, source_id: completed.outputAssetId }, imageServiceDeps);
|
|
45570
|
-
return { ...result, source_job_id: generated.jobId, image_type: "asset", has_transparent_background: true, size: generated.size };
|
|
45571
|
-
}
|
|
45572
45616
|
return {
|
|
45573
45617
|
generation: generated,
|
|
45574
45618
|
local_path: artifact.localPath,
|
|
@@ -48042,6 +48086,64 @@ async function createColorKeyPreview(workspaceDir, body) {
|
|
|
48042
48086
|
throw error2;
|
|
48043
48087
|
}
|
|
48044
48088
|
}
|
|
48089
|
+
async function executeColorKey(workspaceDir, body) {
|
|
48090
|
+
if (body.preview_token !== void 0) return applyColorKeyPreview(workspaceDir, body);
|
|
48091
|
+
const input = normalizeColorKeyInput(body);
|
|
48092
|
+
const sourcePath = resolveAssetPath(workspaceDir, input.sourceAssetId);
|
|
48093
|
+
if (mediaKind(path35.extname(sourcePath)) !== "image") {
|
|
48094
|
+
throw httpError(400, t("error.task.colorSourceImage"));
|
|
48095
|
+
}
|
|
48096
|
+
const paths = await ensureWorkspace(workspaceDir);
|
|
48097
|
+
const operationId = String(body.client_operation_id || createOperationId());
|
|
48098
|
+
const outputPath = path35.join(paths.assetsDir, `${operationId}_color-key.png`);
|
|
48099
|
+
const job = await beginTask({
|
|
48100
|
+
operationId,
|
|
48101
|
+
workspaceDir,
|
|
48102
|
+
kind: "color_key",
|
|
48103
|
+
parentAssetIds: [input.sourceAssetId],
|
|
48104
|
+
outputKind: "image",
|
|
48105
|
+
metadata: {
|
|
48106
|
+
color: input.color,
|
|
48107
|
+
strength: input.strength,
|
|
48108
|
+
contiguousOnly: input.contiguousOnly,
|
|
48109
|
+
despill: input.despill,
|
|
48110
|
+
perceptualColor: "oklab",
|
|
48111
|
+
featheredEdge: true
|
|
48112
|
+
}
|
|
48113
|
+
});
|
|
48114
|
+
try {
|
|
48115
|
+
await updateTask(workspaceDir, job.operationId, { status: "RUNNING" });
|
|
48116
|
+
const result = await processColorKey(sourcePath, outputPath, input);
|
|
48117
|
+
const completed = await completeTask({
|
|
48118
|
+
operationId: job.operationId,
|
|
48119
|
+
workspaceDir,
|
|
48120
|
+
localPath: result.file,
|
|
48121
|
+
mimeType: "image/png",
|
|
48122
|
+
metadata: { ...job.metadata, width: result.width, height: result.height }
|
|
48123
|
+
});
|
|
48124
|
+
if (!completed?.outputAssetId || !completed.outputLocalPath) throw new Error(t("error.task.colorOutputMissing"));
|
|
48125
|
+
return {
|
|
48126
|
+
id: completed.outputAssetId,
|
|
48127
|
+
name: path35.basename(completed.outputLocalPath),
|
|
48128
|
+
url: `/files/${completed.outputAssetId}`,
|
|
48129
|
+
local_path: completed.outputLocalPath,
|
|
48130
|
+
mime_type: "image/png",
|
|
48131
|
+
source_id: input.sourceAssetId,
|
|
48132
|
+
operation_id: job.operationId,
|
|
48133
|
+
width: result.width,
|
|
48134
|
+
height: result.height,
|
|
48135
|
+
color: result.color,
|
|
48136
|
+
strength: result.strength,
|
|
48137
|
+
contiguous_only: result.contiguousOnly,
|
|
48138
|
+
despill: result.despill,
|
|
48139
|
+
has_transparent_background: true
|
|
48140
|
+
};
|
|
48141
|
+
} catch (error2) {
|
|
48142
|
+
await unlink4(outputPath).catch(() => void 0);
|
|
48143
|
+
await failTask(workspaceDir, job.operationId, error2).catch(() => void 0);
|
|
48144
|
+
throw error2;
|
|
48145
|
+
}
|
|
48146
|
+
}
|
|
48045
48147
|
async function applyColorKeyPreview(workspaceDir, body) {
|
|
48046
48148
|
const input = normalizeColorKeyInput(body);
|
|
48047
48149
|
const token = normalizeColorKeyPreviewToken(body.preview_token);
|
|
@@ -48937,13 +49039,13 @@ function errorMessage(error2) {
|
|
|
48937
49039
|
}
|
|
48938
49040
|
function canvasGenerationErrorMessage(error2) {
|
|
48939
49041
|
const message = incompatibleResponseDetail(error2) ?? errorMessage(error2);
|
|
49042
|
+
if (error2 instanceof Error && error2.name === "NetworkError") return message;
|
|
48940
49043
|
const normalized = message.toLowerCase();
|
|
48941
49044
|
if (/insufficient[_ -]?quota|quota (?:has been )?(?:exceeded|exhausted)|insufficient (?:balance|credit|funds)|credit balance (?:is )?too low/i.test(message) || /(?:额度(?:不足|已?用完|耗尽)|余额(?:不足|已?用完))/.test(message)) {
|
|
48942
49045
|
return CANVAS_QUOTA_ERROR;
|
|
48943
49046
|
}
|
|
48944
49047
|
const code = String(error2?.code || "").toUpperCase();
|
|
48945
|
-
|
|
48946
|
-
if (name === "NetworkError" || ["ECONNABORTED", "ECONNREFUSED", "ECONNRESET", "EHOSTUNREACH", "ENETUNREACH", "ETIMEDOUT"].includes(code) || /fetch failed|network(?: request)? (?:error|failed)|socket hang up|connection (?:error|failed|refused|reset|timed out)|request timed out|connecttimeout|网络异常|连接失败/.test(normalized)) {
|
|
49048
|
+
if (["ECONNABORTED", "ECONNREFUSED", "ECONNRESET", "EHOSTUNREACH", "ENETUNREACH", "ETIMEDOUT"].includes(code) || /fetch failed|network(?: request)? (?:error|failed)|socket hang up|connection (?:error|failed|refused|reset|timed out)|request timed out|connecttimeout|网络异常|连接失败/.test(normalized)) {
|
|
48947
49049
|
return CANVAS_NETWORK_ERROR;
|
|
48948
49050
|
}
|
|
48949
49051
|
return message;
|
|
@@ -49099,7 +49201,7 @@ async function executeOperation(name, workspace, input, deps) {
|
|
|
49099
49201
|
case "eliminate_scroll_background_seam":
|
|
49100
49202
|
return executeScrollBackgroundSeamElimination(workspace, input, deps.image);
|
|
49101
49203
|
case "color_key":
|
|
49102
|
-
return
|
|
49204
|
+
return executeColorKey(workspace, input);
|
|
49103
49205
|
case "import_color_key":
|
|
49104
49206
|
return applyBrowserColorKeyResult(workspace, Buffer.from(String(input.png), "base64"), new URL(String(input.url), "http://localhost"));
|
|
49105
49207
|
case "import_perfect_pixel":
|
|
@@ -53152,14 +53254,6 @@ var Server = class extends Protocol {
|
|
|
53152
53254
|
function toolOk(text) {
|
|
53153
53255
|
return { content: [{ type: "text", text }] };
|
|
53154
53256
|
}
|
|
53155
|
-
function toolOkWithImage(text, data, mimeType3) {
|
|
53156
|
-
return {
|
|
53157
|
-
content: [
|
|
53158
|
-
{ type: "text", text },
|
|
53159
|
-
{ type: "image", data, mimeType: mimeType3 }
|
|
53160
|
-
]
|
|
53161
|
-
};
|
|
53162
|
-
}
|
|
53163
53257
|
function toolError(error2) {
|
|
53164
53258
|
const text = error2 instanceof Error ? error2.message : String(error2);
|
|
53165
53259
|
return { content: [{ type: "text", text }], isError: true };
|
|
@@ -53263,8 +53357,51 @@ async function handleLoginEvomeme(deps = defaultDeps4) {
|
|
|
53263
53357
|
}
|
|
53264
53358
|
}
|
|
53265
53359
|
|
|
53266
|
-
// src/mcp/tools/
|
|
53360
|
+
// src/mcp/tools/reinitProject.ts
|
|
53267
53361
|
import path52 from "node:path";
|
|
53362
|
+
var REINIT_PROJECT_TOOL_NAME = "evomeme_reinit_project";
|
|
53363
|
+
var reinitProjectTool = {
|
|
53364
|
+
name: REINIT_PROJECT_TOOL_NAME,
|
|
53365
|
+
description: mcpT("reinit.description"),
|
|
53366
|
+
inputSchema: {
|
|
53367
|
+
type: "object",
|
|
53368
|
+
properties: {
|
|
53369
|
+
workspace_dir: { type: "string", description: mcpT("submit.workspace") },
|
|
53370
|
+
name: { type: "string", description: mcpT("reinit.name") }
|
|
53371
|
+
},
|
|
53372
|
+
additionalProperties: false
|
|
53373
|
+
},
|
|
53374
|
+
annotations: {
|
|
53375
|
+
title: mcpT("reinit.title"),
|
|
53376
|
+
destructiveHint: true,
|
|
53377
|
+
idempotentHint: false,
|
|
53378
|
+
openWorldHint: true,
|
|
53379
|
+
readOnlyHint: false
|
|
53380
|
+
}
|
|
53381
|
+
};
|
|
53382
|
+
var defaultDeps5 = {
|
|
53383
|
+
ensureAuthenticated,
|
|
53384
|
+
createAndBindProject,
|
|
53385
|
+
cwd: () => process.cwd()
|
|
53386
|
+
};
|
|
53387
|
+
async function handleReinitProject(args = {}, deps = defaultDeps5) {
|
|
53388
|
+
try {
|
|
53389
|
+
const workspaceDir = path52.resolve(args.workspace_dir?.trim() || deps.cwd());
|
|
53390
|
+
const name = args.name?.trim();
|
|
53391
|
+
const token = await deps.ensureAuthenticated();
|
|
53392
|
+
const result = await deps.createAndBindProject(workspaceDir, token, name ? { name } : {});
|
|
53393
|
+
return toolOk([
|
|
53394
|
+
mcpT("reinit.succeeded"),
|
|
53395
|
+
mcpT("submit.workspaceLabel") + workspaceDir,
|
|
53396
|
+
`thread_id:${result.threadId}`
|
|
53397
|
+
].join("\n"));
|
|
53398
|
+
} catch (error2) {
|
|
53399
|
+
return toolError(error2);
|
|
53400
|
+
}
|
|
53401
|
+
}
|
|
53402
|
+
|
|
53403
|
+
// src/mcp/tools/submitGameCode.ts
|
|
53404
|
+
import path53 from "node:path";
|
|
53268
53405
|
var SUBMIT_GAME_CODE_TOOL_NAME = "evomeme_submit_game_code";
|
|
53269
53406
|
var SUBMIT_GAME_CODE_DESCRIPTION = mcpT("submit.description");
|
|
53270
53407
|
var submitGameCodeTool = {
|
|
@@ -53296,14 +53433,14 @@ var submitGameCodeTool = {
|
|
|
53296
53433
|
readOnlyHint: false
|
|
53297
53434
|
}
|
|
53298
53435
|
};
|
|
53299
|
-
var
|
|
53436
|
+
var defaultDeps6 = {
|
|
53300
53437
|
ensureAuthenticated,
|
|
53301
53438
|
submitWorkspaceCode,
|
|
53302
53439
|
cwd: () => process.cwd()
|
|
53303
53440
|
};
|
|
53304
|
-
async function handleSubmitGameCode(args = {}, deps =
|
|
53441
|
+
async function handleSubmitGameCode(args = {}, deps = defaultDeps6) {
|
|
53305
53442
|
try {
|
|
53306
|
-
const workspaceDir =
|
|
53443
|
+
const workspaceDir = path53.resolve(args.workspace_dir?.trim() || deps.cwd());
|
|
53307
53444
|
const submitOptions = {};
|
|
53308
53445
|
const name = args.name?.trim();
|
|
53309
53446
|
if (name) {
|
|
@@ -53313,11 +53450,8 @@ async function handleSubmitGameCode(args = {}, deps = defaultDeps5) {
|
|
|
53313
53450
|
if (coverUrl) {
|
|
53314
53451
|
submitOptions.coverUrl = coverUrl;
|
|
53315
53452
|
}
|
|
53316
|
-
const
|
|
53317
|
-
const result = await
|
|
53318
|
-
(token) => deps.submitWorkspaceCode(workspaceDir, token, submitOptions),
|
|
53319
|
-
{ ...authOptions, ensureAuthenticatedFn: deps.ensureAuthenticated }
|
|
53320
|
-
);
|
|
53453
|
+
const token = await deps.ensureAuthenticated();
|
|
53454
|
+
const result = await deps.submitWorkspaceCode(workspaceDir, token, submitOptions);
|
|
53321
53455
|
return toolOk(formatSuccess(workspaceDir, result));
|
|
53322
53456
|
} catch (error2) {
|
|
53323
53457
|
return toolError(error2);
|
|
@@ -53334,7 +53468,7 @@ function formatSuccess(workspaceDir, result) {
|
|
|
53334
53468
|
}
|
|
53335
53469
|
|
|
53336
53470
|
// src/mcp/tools/uploadGameAsset.ts
|
|
53337
|
-
import
|
|
53471
|
+
import path54 from "node:path";
|
|
53338
53472
|
var UPLOAD_GAME_ASSET_TOOL_NAME = "evomeme_upload_game_asset";
|
|
53339
53473
|
var UPLOAD_GAME_ASSET_DESCRIPTION = mcpT("upload.description");
|
|
53340
53474
|
var uploadGameAssetTool = {
|
|
@@ -53367,17 +53501,17 @@ var uploadGameAssetTool = {
|
|
|
53367
53501
|
readOnlyHint: false
|
|
53368
53502
|
}
|
|
53369
53503
|
};
|
|
53370
|
-
var
|
|
53504
|
+
var defaultDeps7 = {
|
|
53371
53505
|
ensureAuthenticated,
|
|
53372
53506
|
uploadLocalAsset,
|
|
53373
53507
|
cwd: () => process.cwd()
|
|
53374
53508
|
};
|
|
53375
|
-
async function handleUploadGameAsset(args, deps =
|
|
53509
|
+
async function handleUploadGameAsset(args, deps = defaultDeps7) {
|
|
53376
53510
|
try {
|
|
53377
53511
|
if (!args.local_path?.trim()) {
|
|
53378
53512
|
return toolError(new Error(mcpT("upload.missingLocalPath")));
|
|
53379
53513
|
}
|
|
53380
|
-
const localPath =
|
|
53514
|
+
const localPath = path54.isAbsolute(args.local_path) ? args.local_path : path54.resolve(deps.cwd(), args.local_path);
|
|
53381
53515
|
const uploadOptions = {};
|
|
53382
53516
|
if (args.folder !== void 0) {
|
|
53383
53517
|
uploadOptions.folder = args.folder;
|
|
@@ -53406,13 +53540,13 @@ function formatSuccess2(result) {
|
|
|
53406
53540
|
|
|
53407
53541
|
// src/tasks/client.ts
|
|
53408
53542
|
import { spawn as spawn8 } from "node:child_process";
|
|
53409
|
-
import
|
|
53543
|
+
import path55 from "node:path";
|
|
53410
53544
|
var INTERNAL_TASK_WORKER_COMMAND = "__evomeme_task_worker";
|
|
53411
53545
|
var runDetachedTask = async (kind, input, workspace) => {
|
|
53412
53546
|
const task = await createTask(workspace, kind, input, "mcp");
|
|
53413
53547
|
if (!process.argv[1]) throw new Error(t("error.task.workerEntryMissing"));
|
|
53414
|
-
const entry =
|
|
53415
|
-
const execArgs =
|
|
53548
|
+
const entry = path55.resolve(process.argv[1]);
|
|
53549
|
+
const execArgs = path55.extname(entry) === ".ts" ? process.execArgv.filter((arg) => !arg.startsWith("--inspect") && !arg.startsWith("--debug")) : [];
|
|
53416
53550
|
const child = spawn8(process.execPath, [...execArgs, entry, INTERNAL_TASK_WORKER_COMMAND, task.workspaceDir, task.operationId], {
|
|
53417
53551
|
cwd: task.workspaceDir,
|
|
53418
53552
|
env: process.env,
|
|
@@ -53439,11 +53573,46 @@ async function runTaskWorker(workspace, id) {
|
|
|
53439
53573
|
}
|
|
53440
53574
|
}
|
|
53441
53575
|
|
|
53576
|
+
// src/mcp/imageTool.ts
|
|
53577
|
+
var defaultImageToolDeps = { ...defaultImageServiceDeps, taskRunner: runDetachedTask };
|
|
53578
|
+
function validateImageToolInput(tool, args) {
|
|
53579
|
+
const values = args;
|
|
53580
|
+
const properties = tool.inputSchema.properties;
|
|
53581
|
+
for (const [key, value] of Object.entries(values)) {
|
|
53582
|
+
if (value === void 0) continue;
|
|
53583
|
+
const field = properties[key];
|
|
53584
|
+
if (!field) throw new Error(`${mcpT("imageTool.unknownParameter")}${key}`);
|
|
53585
|
+
if (typeof value !== field.type || typeof value === "number" && (!Number.isFinite(value) || field.minimum !== void 0 && value < field.minimum || field.maximum !== void 0 && value > field.maximum) || field.enum && !field.enum.includes(value)) {
|
|
53586
|
+
throw new Error(`${mcpT("imageTool.invalidParameter")}${key}: ${String(value)}`);
|
|
53587
|
+
}
|
|
53588
|
+
}
|
|
53589
|
+
for (const key of tool.inputSchema.required ?? []) {
|
|
53590
|
+
if (values[key] === void 0 || values[key] === "") throw new Error(`${mcpT("imageTool.missingParameter")}${key}`);
|
|
53591
|
+
}
|
|
53592
|
+
}
|
|
53593
|
+
function imageToolSource(args) {
|
|
53594
|
+
const id = args.id?.trim();
|
|
53595
|
+
const url = args.image_url?.trim();
|
|
53596
|
+
if (args.id !== void 0 === (args.image_url !== void 0) || args.id !== void 0 && !id || args.image_url !== void 0 && !url) {
|
|
53597
|
+
throw new Error(mcpT("imageTool.sourceRequired"));
|
|
53598
|
+
}
|
|
53599
|
+
if (id) return { id };
|
|
53600
|
+
let valid = false;
|
|
53601
|
+
try {
|
|
53602
|
+
valid = ["http:", "https:"].includes(new URL(url).protocol);
|
|
53603
|
+
} catch {
|
|
53604
|
+
}
|
|
53605
|
+
if (!valid) throw new Error(mcpT("imageTool.invalidUrl"));
|
|
53606
|
+
return { image_url: url };
|
|
53607
|
+
}
|
|
53608
|
+
function runImageToolTask(name, parameters, workspace, deps) {
|
|
53609
|
+
return deps.taskRunner ? deps.taskRunner(name, parameters, workspace) : runTask(workspace, name, parameters, "mcp", { image: deps });
|
|
53610
|
+
}
|
|
53611
|
+
|
|
53442
53612
|
// src/mcp/imageJob.ts
|
|
53443
|
-
import { readFile as readFile19 } from "node:fs/promises";
|
|
53444
53613
|
function imageArtifactToolResult(input) {
|
|
53445
53614
|
const detailLines = Object.entries(input.details ?? {}).map(([key, value]) => `${key}: ${value}`);
|
|
53446
|
-
return
|
|
53615
|
+
return toolOk(
|
|
53447
53616
|
[
|
|
53448
53617
|
`${input.successLabel}。`,
|
|
53449
53618
|
`job_id: ${input.jobId}`,
|
|
@@ -53453,28 +53622,32 @@ function imageArtifactToolResult(input) {
|
|
|
53453
53622
|
`attempts: ${input.attempts}/${input.maxAttempts}`,
|
|
53454
53623
|
...detailLines,
|
|
53455
53624
|
`local_path: ${input.artifact.localPath}`,
|
|
53456
|
-
`multimodal_base64: content[1].data (${input.artifact.base64.length} characters)`,
|
|
53457
53625
|
`mime_type: ${input.artifact.mimeType}`
|
|
53458
|
-
].join("\n")
|
|
53459
|
-
input.artifact.base64,
|
|
53460
|
-
input.artifact.mimeType
|
|
53626
|
+
].join("\n")
|
|
53461
53627
|
);
|
|
53462
53628
|
}
|
|
53463
53629
|
async function formatImageTaskResult(result, successLabel) {
|
|
53464
53630
|
const generated = result.generation;
|
|
53465
|
-
const bytes = await readFile19(String(result.local_path));
|
|
53466
53631
|
const details = {};
|
|
53467
|
-
for (const key of ["
|
|
53632
|
+
for (const key of ["model", "size", "has_transparent_background", "mask_url", "source_id", "width", "height", "color", "strength", "contiguous_only", "despill"]) {
|
|
53468
53633
|
const value = result[key];
|
|
53469
53634
|
if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") details[key] = value;
|
|
53470
53635
|
}
|
|
53636
|
+
if (typeof result.id === "string") details.asset_id = result.id;
|
|
53637
|
+
if (!generated) {
|
|
53638
|
+
return toolOk([
|
|
53639
|
+
successLabel,
|
|
53640
|
+
"status: SUCCEEDED",
|
|
53641
|
+
`operation_id: ${result.operation_id}`,
|
|
53642
|
+
...Object.entries(details).map(([key, value]) => `${key}: ${value}`),
|
|
53643
|
+
`local_path: ${result.local_path}`,
|
|
53644
|
+
`mime_type: ${result.mime_type}`
|
|
53645
|
+
].join("\n"));
|
|
53646
|
+
}
|
|
53471
53647
|
return imageArtifactToolResult({
|
|
53472
53648
|
artifact: {
|
|
53473
|
-
bytes,
|
|
53474
|
-
base64: bytes.toString("base64"),
|
|
53475
53649
|
mimeType: String(result.mime_type),
|
|
53476
|
-
localPath: String(result.local_path)
|
|
53477
|
-
assetUrl: generated.assetUrl
|
|
53650
|
+
localPath: String(result.local_path)
|
|
53478
53651
|
},
|
|
53479
53652
|
jobId: generated.jobId,
|
|
53480
53653
|
assetUrl: generated.assetUrl,
|
|
@@ -53495,106 +53668,35 @@ var generateGameImageTool = {
|
|
|
53495
53668
|
inputSchema: {
|
|
53496
53669
|
type: "object",
|
|
53497
53670
|
properties: {
|
|
53498
|
-
|
|
53499
|
-
|
|
53500
|
-
|
|
53501
|
-
},
|
|
53502
|
-
|
|
53503
|
-
type: "string",
|
|
53504
|
-
enum: [...GAME_IMAGE_TYPES],
|
|
53505
|
-
description: mcpT("image.type")
|
|
53506
|
-
},
|
|
53507
|
-
size: {
|
|
53508
|
-
type: "string",
|
|
53509
|
-
description: mcpT("image.size")
|
|
53510
|
-
},
|
|
53511
|
-
reference_image_url: {
|
|
53512
|
-
oneOf: [
|
|
53513
|
-
{ type: "string" },
|
|
53514
|
-
{ type: "array", items: { type: "string" }, minItems: 1, maxItems: 16 }
|
|
53515
|
-
],
|
|
53516
|
-
description: mcpT("image.references")
|
|
53517
|
-
},
|
|
53518
|
-
image_model: {
|
|
53519
|
-
type: "string",
|
|
53520
|
-
enum: [...GAME_IMAGE_MODELS],
|
|
53521
|
-
description: mcpT("image.model")
|
|
53522
|
-
},
|
|
53523
|
-
background: {
|
|
53524
|
-
type: "string",
|
|
53525
|
-
enum: [...GAME_IMAGE_BACKGROUNDS],
|
|
53526
|
-
description: mcpT("image.background")
|
|
53527
|
-
},
|
|
53528
|
-
workspace_dir: {
|
|
53529
|
-
type: "string",
|
|
53530
|
-
description: mcpT("image.workspace")
|
|
53531
|
-
}
|
|
53671
|
+
model: { type: "string", enum: [...GAME_IMAGE_MODELS], default: "asset-pro", description: mcpT("image.model") },
|
|
53672
|
+
background: { type: "string", enum: [...GAME_IMAGE_BACKGROUNDS], default: "opaque", description: mcpT("image.background") },
|
|
53673
|
+
size: { type: "string", enum: [...GAME_IMAGE_SIZES], default: "2048x2048", description: mcpT("image.size") },
|
|
53674
|
+
prompt: { type: "string", description: mcpT("image.prompt") },
|
|
53675
|
+
workspace_dir: { type: "string", description: mcpT("image.workspace") }
|
|
53532
53676
|
},
|
|
53533
53677
|
required: ["prompt"],
|
|
53534
53678
|
additionalProperties: false
|
|
53535
53679
|
},
|
|
53536
|
-
annotations: {
|
|
53537
|
-
title: mcpT("image.title"),
|
|
53538
|
-
destructiveHint: false,
|
|
53539
|
-
idempotentHint: false,
|
|
53540
|
-
openWorldHint: true,
|
|
53541
|
-
readOnlyHint: false
|
|
53542
|
-
}
|
|
53680
|
+
annotations: { title: mcpT("image.title"), destructiveHint: false, idempotentHint: false, openWorldHint: true, readOnlyHint: false }
|
|
53543
53681
|
};
|
|
53544
|
-
|
|
53545
|
-
async function handleGenerateGameImage(args, deps = defaultDeps7) {
|
|
53682
|
+
async function handleGenerateGameImage(args, deps = defaultImageToolDeps) {
|
|
53546
53683
|
try {
|
|
53547
|
-
|
|
53548
|
-
const
|
|
53549
|
-
if (
|
|
53550
|
-
const
|
|
53551
|
-
|
|
53552
|
-
|
|
53553
|
-
|
|
53554
|
-
|
|
53555
|
-
|
|
53556
|
-
|
|
53557
|
-
|
|
53558
|
-
const workspace = args.workspace_dir?.trim() || deps.cwd();
|
|
53559
|
-
const result = deps.taskRunner ? await deps.taskRunner("generate_game_image", parameters, workspace) : await runTask(workspace, "generate_game_image", parameters, "mcp", { image: deps });
|
|
53684
|
+
validateImageToolInput(generateGameImageTool, args);
|
|
53685
|
+
const prompt = args.prompt.trim();
|
|
53686
|
+
if (!prompt) throw new Error(mcpT("image.missingPrompt"));
|
|
53687
|
+
const model = args.model ?? "asset-pro";
|
|
53688
|
+
const size = args.size ?? "2048x2048";
|
|
53689
|
+
if (!gameImageSizePresets(model).includes(size)) throw new Error(`${mcpT("image.invalidSize")}${model}: ${size}`);
|
|
53690
|
+
const background = args.background ?? "opaque";
|
|
53691
|
+
if (background === "auto" && model !== "asset-max") throw new Error(mcpT("image.autoBackgroundMax"));
|
|
53692
|
+
const input = normalizeGameImageInput({ prompt, imageModel: model, size, background });
|
|
53693
|
+
const parameters = { prompt, model, size: input.size, background: input.background };
|
|
53694
|
+
const result = await runImageToolTask("generate_game_image", parameters, args.workspace_dir?.trim() || deps.cwd(), deps);
|
|
53560
53695
|
return await formatImageTaskResult(result, mcpT("image.completed"));
|
|
53561
53696
|
} catch (error2) {
|
|
53562
53697
|
return toolError(error2);
|
|
53563
53698
|
}
|
|
53564
53699
|
}
|
|
53565
|
-
function buildGenerateInput(args) {
|
|
53566
|
-
const input = {
|
|
53567
|
-
prompt: args.prompt.trim(),
|
|
53568
|
-
imageModel: "asset-lite"
|
|
53569
|
-
};
|
|
53570
|
-
if (args.image_type !== void 0) {
|
|
53571
|
-
if (!GAME_IMAGE_TYPES.includes(args.image_type)) {
|
|
53572
|
-
return new Error(mcpT("image.invalidType") + args.image_type);
|
|
53573
|
-
}
|
|
53574
|
-
input.imageType = args.image_type;
|
|
53575
|
-
}
|
|
53576
|
-
if (args.size !== void 0) {
|
|
53577
|
-
input.size = args.size;
|
|
53578
|
-
}
|
|
53579
|
-
if (args.image_model !== void 0) {
|
|
53580
|
-
if (!GAME_IMAGE_MODELS.includes(args.image_model)) {
|
|
53581
|
-
return new Error(mcpT("image.invalidModel") + args.image_model);
|
|
53582
|
-
}
|
|
53583
|
-
input.imageModel = args.image_model;
|
|
53584
|
-
}
|
|
53585
|
-
if (args.background !== void 0) {
|
|
53586
|
-
if (!GAME_IMAGE_BACKGROUNDS.includes(args.background)) {
|
|
53587
|
-
return new Error(mcpT("image.invalidBackground") + args.background);
|
|
53588
|
-
}
|
|
53589
|
-
input.background = args.background;
|
|
53590
|
-
}
|
|
53591
|
-
if (args.reference_image_url !== void 0) {
|
|
53592
|
-
const references = (Array.isArray(args.reference_image_url) ? args.reference_image_url : [args.reference_image_url]).map((value) => value.trim()).filter(Boolean);
|
|
53593
|
-
if (!references.length) return new Error(mcpT("image.emptyReferences"));
|
|
53594
|
-
input.referenceImageUrl = references.length === 1 ? references[0] : references;
|
|
53595
|
-
}
|
|
53596
|
-
return normalizeGameImageInput(input);
|
|
53597
|
-
}
|
|
53598
53700
|
|
|
53599
53701
|
// src/mcp/tools/cutoutGameImage.ts
|
|
53600
53702
|
var CUTOUT_GAME_IMAGE_TOOL_NAME = "evomeme_cutout_game_image";
|
|
@@ -53605,33 +53707,19 @@ var cutoutGameImageTool = {
|
|
|
53605
53707
|
inputSchema: {
|
|
53606
53708
|
type: "object",
|
|
53607
53709
|
properties: {
|
|
53608
|
-
|
|
53609
|
-
|
|
53610
|
-
|
|
53611
|
-
},
|
|
53612
|
-
workspace_dir: {
|
|
53613
|
-
type: "string",
|
|
53614
|
-
description: mcpT("cutout.workspace")
|
|
53615
|
-
}
|
|
53710
|
+
id: { type: "string", description: mcpT("imageTool.assetId") },
|
|
53711
|
+
image_url: { type: "string", description: mcpT("cutout.imageUrl") },
|
|
53712
|
+
workspace_dir: { type: "string", description: mcpT("image.workspace") }
|
|
53616
53713
|
},
|
|
53617
|
-
required: ["image_url"],
|
|
53714
|
+
oneOf: [{ required: ["id"] }, { required: ["image_url"] }],
|
|
53618
53715
|
additionalProperties: false
|
|
53619
53716
|
},
|
|
53620
|
-
annotations: {
|
|
53621
|
-
title: mcpT("cutout.title"),
|
|
53622
|
-
destructiveHint: false,
|
|
53623
|
-
idempotentHint: false,
|
|
53624
|
-
openWorldHint: true,
|
|
53625
|
-
readOnlyHint: false
|
|
53626
|
-
}
|
|
53717
|
+
annotations: { title: mcpT("cutout.title"), destructiveHint: false, idempotentHint: false, openWorldHint: true, readOnlyHint: false }
|
|
53627
53718
|
};
|
|
53628
|
-
|
|
53629
|
-
async function handleCutoutGameImage(args, deps = defaultDeps8) {
|
|
53719
|
+
async function handleCutoutGameImage(args, deps = defaultImageToolDeps) {
|
|
53630
53720
|
try {
|
|
53631
|
-
|
|
53632
|
-
const
|
|
53633
|
-
const workspace = args.workspace_dir?.trim() || deps.cwd();
|
|
53634
|
-
const result = deps.taskRunner ? await deps.taskRunner("cutout_game_image", parameters, workspace) : await runTask(workspace, "cutout_game_image", parameters, "mcp", { image: deps });
|
|
53721
|
+
validateImageToolInput(cutoutGameImageTool, args);
|
|
53722
|
+
const result = await runImageToolTask("cutout_game_image", imageToolSource(args), args.workspace_dir?.trim() || deps.cwd(), deps);
|
|
53635
53723
|
return await formatImageTaskResult(result, mcpT("cutout.completed"));
|
|
53636
53724
|
} catch (error2) {
|
|
53637
53725
|
return toolError(error2);
|
|
@@ -53685,8 +53773,8 @@ var generateGameVideoTool = {
|
|
|
53685
53773
|
readOnlyHint: false
|
|
53686
53774
|
}
|
|
53687
53775
|
};
|
|
53688
|
-
var
|
|
53689
|
-
async function handleGenerateGameVideo(args, deps =
|
|
53776
|
+
var defaultDeps8 = { ...defaultVideoGenerationDeps, taskRunner: runDetachedTask };
|
|
53777
|
+
async function handleGenerateGameVideo(args, deps = defaultDeps8) {
|
|
53690
53778
|
try {
|
|
53691
53779
|
const input = buildVideoInput(args);
|
|
53692
53780
|
if (input instanceof Error) throw input;
|
|
@@ -53782,8 +53870,46 @@ function buildVideoInput(args) {
|
|
|
53782
53870
|
return input;
|
|
53783
53871
|
}
|
|
53784
53872
|
|
|
53873
|
+
// src/mcp/tools/colorKey.ts
|
|
53874
|
+
var COLOR_KEY_TOOL_NAME = "evomeme_color_key";
|
|
53875
|
+
var colorKeyTool = {
|
|
53876
|
+
name: COLOR_KEY_TOOL_NAME,
|
|
53877
|
+
description: mcpT("colorKey.description"),
|
|
53878
|
+
inputSchema: {
|
|
53879
|
+
type: "object",
|
|
53880
|
+
properties: {
|
|
53881
|
+
id: { type: "string", description: mcpT("imageTool.assetId") },
|
|
53882
|
+
color: { type: "string", default: "#ffffff", description: mcpT("colorKey.color") },
|
|
53883
|
+
strength: { type: "number", minimum: 0, maximum: 100, default: 80, description: mcpT("colorKey.strength") },
|
|
53884
|
+
contiguous_only: { type: "boolean", default: false, description: mcpT("colorKey.contiguousOnly") },
|
|
53885
|
+
despill: { type: "boolean", default: false, description: mcpT("colorKey.despill") },
|
|
53886
|
+
workspace_dir: { type: "string", description: mcpT("image.workspace") }
|
|
53887
|
+
},
|
|
53888
|
+
required: ["id"],
|
|
53889
|
+
additionalProperties: false
|
|
53890
|
+
},
|
|
53891
|
+
annotations: { title: mcpT("colorKey.title"), destructiveHint: false, idempotentHint: false, openWorldHint: false, readOnlyHint: false }
|
|
53892
|
+
};
|
|
53893
|
+
async function handleColorKey(args, deps = defaultImageToolDeps) {
|
|
53894
|
+
try {
|
|
53895
|
+
validateImageToolInput(colorKeyTool, args);
|
|
53896
|
+
if (!args.id.trim()) throw new Error(`${mcpT("imageTool.missingParameter")}id`);
|
|
53897
|
+
const parameters = {
|
|
53898
|
+
id: args.id.trim(),
|
|
53899
|
+
color: normalizeColorKeyHex(args.color ?? "#ffffff"),
|
|
53900
|
+
strength: args.strength ?? 80,
|
|
53901
|
+
contiguous_only: args.contiguous_only ?? false,
|
|
53902
|
+
despill: args.despill ?? false
|
|
53903
|
+
};
|
|
53904
|
+
const result = await runImageToolTask("color_key", parameters, args.workspace_dir?.trim() || deps.cwd(), deps);
|
|
53905
|
+
return await formatImageTaskResult(result, mcpT("colorKey.completed"));
|
|
53906
|
+
} catch (error2) {
|
|
53907
|
+
return toolError(error2);
|
|
53908
|
+
}
|
|
53909
|
+
}
|
|
53910
|
+
|
|
53785
53911
|
// src/mcp/tools/stage/index.ts
|
|
53786
|
-
import
|
|
53912
|
+
import path59 from "node:path";
|
|
53787
53913
|
|
|
53788
53914
|
// src/stage/index.ts
|
|
53789
53915
|
init_schema();
|
|
@@ -53794,9 +53920,9 @@ init_sceneContract();
|
|
|
53794
53920
|
init_workspace();
|
|
53795
53921
|
init_schema();
|
|
53796
53922
|
init_sceneContract();
|
|
53797
|
-
import { copyFile as copyFile10, mkdir as mkdir26, writeFile as writeFile13, readFile as
|
|
53923
|
+
import { copyFile as copyFile10, mkdir as mkdir26, writeFile as writeFile13, readFile as readFile21, realpath as realpath6, lstat as lstat3 } from "node:fs/promises";
|
|
53798
53924
|
import { existsSync as existsSync11 } from "node:fs";
|
|
53799
|
-
import
|
|
53925
|
+
import path58 from "node:path";
|
|
53800
53926
|
|
|
53801
53927
|
// src/stage/runtime/applyCanonicalOrientation.ts
|
|
53802
53928
|
function runtimeYawRadians(forwardAxis) {
|
|
@@ -53881,9 +54007,9 @@ init_publicDir();
|
|
|
53881
54007
|
init_godotAppearance();
|
|
53882
54008
|
|
|
53883
54009
|
// src/stage/threeDelivery.ts
|
|
53884
|
-
import { readFile as
|
|
54010
|
+
import { readFile as readFile19 } from "node:fs/promises";
|
|
53885
54011
|
import { createHash as createHash12 } from "node:crypto";
|
|
53886
|
-
import
|
|
54012
|
+
import path56 from "node:path";
|
|
53887
54013
|
async function threeDeliveryFiles(publicDir, input, confirmation) {
|
|
53888
54014
|
const runtimeFiles = input.runtimeFiles.filter((file) => ["scene-runtime.js", "three-appearance.js", "sceneContractRuntime.js"].includes(file) || file.startsWith("baked/") || file.startsWith("vendor/"));
|
|
53889
54015
|
const packageFiles = /* @__PURE__ */ new Map(), gameFiles = /* @__PURE__ */ new Map();
|
|
@@ -53899,7 +54025,7 @@ async function threeDeliveryFiles(publicDir, input, confirmation) {
|
|
|
53899
54025
|
};
|
|
53900
54026
|
packageFiles.set("three.appearance.json", Buffer.from(JSON.stringify(config2, null, 2)));
|
|
53901
54027
|
for (const file of runtimeFiles) {
|
|
53902
|
-
const bytes = await
|
|
54028
|
+
const bytes = await readFile19(path56.join(publicDir, file));
|
|
53903
54029
|
if (createHash12("sha256").update(bytes).digest("hex") !== confirmation.implementation[file]) throw new Error("Three.js 显示实现已变化,请重新确认");
|
|
53904
54030
|
packageFiles.set(`engine-runtime/${file}`, bytes);
|
|
53905
54031
|
if (!file.startsWith("vendor/")) gameFiles.set(file, bytes);
|
|
@@ -53971,9 +54097,9 @@ init_workspace();
|
|
|
53971
54097
|
init_schema();
|
|
53972
54098
|
import { spawn as spawn9 } from "node:child_process";
|
|
53973
54099
|
import { existsSync as existsSync10 } from "node:fs";
|
|
53974
|
-
import { copyFile as copyFile9, mkdir as mkdir25, mkdtemp as mkdtemp7, readFile as
|
|
54100
|
+
import { copyFile as copyFile9, mkdir as mkdir25, mkdtemp as mkdtemp7, readFile as readFile20, readdir as readdir6, realpath as realpath5, lstat as lstat2, rename as rename5, writeFile as writeFile12, open as open2, unlink as unlink8 } from "node:fs/promises";
|
|
53975
54101
|
import { createHash as createHash13 } from "node:crypto";
|
|
53976
|
-
import
|
|
54102
|
+
import path57 from "node:path";
|
|
53977
54103
|
init_publicDir();
|
|
53978
54104
|
init_review();
|
|
53979
54105
|
init_sceneContract();
|
|
@@ -53981,30 +54107,30 @@ init_godotAppearance();
|
|
|
53981
54107
|
init_threeAppearance();
|
|
53982
54108
|
var digest = (bytes) => ({ bytes: bytes.length, sha256: createHash13("sha256").update(bytes).digest("hex") });
|
|
53983
54109
|
function resolveSceneExporter() {
|
|
53984
|
-
const entry =
|
|
54110
|
+
const entry = path57.dirname(path57.resolve(process.argv[1] || process.cwd()));
|
|
53985
54111
|
const candidates = [
|
|
53986
|
-
|
|
53987
|
-
|
|
53988
|
-
|
|
53989
|
-
|
|
54112
|
+
path57.join(entry, "stage-blender/export_scene.py"),
|
|
54113
|
+
path57.join(entry, "../src/stage/blender/export_scene.py"),
|
|
54114
|
+
path57.resolve("src/stage/blender/export_scene.py"),
|
|
54115
|
+
path57.resolve("plugin_client/src/stage/blender/export_scene.py")
|
|
53990
54116
|
];
|
|
53991
54117
|
const found = candidates.find((p) => existsSync10(p));
|
|
53992
54118
|
if (!found) throw new Error("找不到 Blender 场景导出脚本,请重新构建或更新插件");
|
|
53993
54119
|
return found;
|
|
53994
54120
|
}
|
|
53995
54121
|
async function readGodotProjectRenderer(projectDir) {
|
|
53996
|
-
const text = await
|
|
54122
|
+
const text = await readFile20(path57.join(projectDir, "project.godot"), "utf8");
|
|
53997
54123
|
const section = text.match(/\[rendering\]([\s\S]*?)(?=\n\[|$)/)?.[1] || "";
|
|
53998
54124
|
const value = section.match(/^renderer\/rendering_method\s*=\s*"([^"]+)"/m)?.[1] || (/^config_version\s*=/m.test(text) ? "forward_plus" : "gl_compatibility");
|
|
53999
54125
|
if (!["gl_compatibility", "mobile", "forward_plus"].includes(value)) throw new Error("不支持的 Godot 工程渲染器:" + value);
|
|
54000
54126
|
return value;
|
|
54001
54127
|
}
|
|
54002
54128
|
async function safeDirectory(workspace, directory) {
|
|
54003
|
-
const relative =
|
|
54004
|
-
if (relative.startsWith("..") ||
|
|
54129
|
+
const relative = path57.relative(workspace, directory);
|
|
54130
|
+
if (relative.startsWith("..") || path57.isAbsolute(relative)) throw new Error("场景导出目录必须位于工作区内");
|
|
54005
54131
|
let current = workspace;
|
|
54006
|
-
for (const part of relative.split(
|
|
54007
|
-
current =
|
|
54132
|
+
for (const part of relative.split(path57.sep).filter(Boolean)) {
|
|
54133
|
+
current = path57.join(current, part);
|
|
54008
54134
|
if (existsSync10(current)) {
|
|
54009
54135
|
const stat12 = await lstat2(current);
|
|
54010
54136
|
if (stat12.isSymbolicLink() || !stat12.isDirectory()) throw new Error("场景导出目录不能包含链接或文件:" + current);
|
|
@@ -54033,7 +54159,7 @@ async function nativeExport(command, args, logFile, timeout) {
|
|
|
54033
54159
|
});
|
|
54034
54160
|
}
|
|
54035
54161
|
async function exportBlenderScene(input) {
|
|
54036
|
-
if (!input.sourceBlendPath || !
|
|
54162
|
+
if (!input.sourceBlendPath || !path57.isAbsolute(input.sourceBlendPath) || path57.extname(input.sourceBlendPath).toLowerCase() !== ".blend") throw new Error("source_blend_path 必须是已保存的 .blend 绝对路径");
|
|
54037
54163
|
const id = normalizeAssetId(input.assetId);
|
|
54038
54164
|
if (!input.assetId) throw new Error("asset_id 必填");
|
|
54039
54165
|
const width = input.width ?? 960, size = input.textureSize ?? 1024;
|
|
@@ -54044,24 +54170,24 @@ async function exportBlenderScene(input) {
|
|
|
54044
54170
|
if (!Number.isInteger(width) || width < 320 || width > 1920) throw new Error("参考图宽度必须为 320–1920");
|
|
54045
54171
|
if (![256, 512, 1024, 2048].includes(size)) throw new Error("烘焙贴图尺寸必须为 256/512/1024/2048");
|
|
54046
54172
|
if (input.cameraNames && (!Array.isArray(input.cameraNames) || input.cameraNames.length > 6 || input.cameraNames.some((n) => typeof n !== "string" || !n))) throw new Error("camera_names 最多包含 6 个有效相机名");
|
|
54047
|
-
const source = await realpath5(input.sourceBlendPath), sourceHash = digest(await
|
|
54173
|
+
const source = await realpath5(input.sourceBlendPath), sourceHash = digest(await readFile20(source));
|
|
54048
54174
|
await mkdir25(input.workspaceDir, { recursive: true });
|
|
54049
54175
|
const workspace = await realpath5(input.workspaceDir), dest = packagePaths(workspace, id).packageDir;
|
|
54050
|
-
await safeDirectory(workspace,
|
|
54176
|
+
await safeDirectory(workspace, path57.dirname(dest));
|
|
54051
54177
|
if (existsSync10(dest)) {
|
|
54052
54178
|
await safeDirectory(workspace, dest);
|
|
54053
54179
|
if (!input.replaceExisting) throw new Error("资产包已存在;更新当前场景请设置 replace_existing=true");
|
|
54054
54180
|
}
|
|
54055
|
-
const jobRoot =
|
|
54181
|
+
const jobRoot = path57.join(workspace, ".evomeme/scene-exports");
|
|
54056
54182
|
await safeDirectory(workspace, jobRoot);
|
|
54057
|
-
const lockPath =
|
|
54183
|
+
const lockPath = path57.join(jobRoot, `${id}.lock`);
|
|
54058
54184
|
const lock = await open2(lockPath, "wx").catch((error2) => {
|
|
54059
54185
|
if (error2.code === "EEXIST") throw new Error("该资产正在导出;如上次进程意外终止,请确认其已退出后移除锁文件:" + lockPath);
|
|
54060
54186
|
throw error2;
|
|
54061
54187
|
});
|
|
54062
54188
|
try {
|
|
54063
54189
|
if (existsSync10(dest) && !input.replaceExisting) throw new Error("资产包已存在;更新当前场景请设置 replace_existing=true");
|
|
54064
|
-
const job = await mkdtemp7(
|
|
54190
|
+
const job = await mkdtemp7(path57.join(jobRoot, "export-")), output = path57.join(job, "output");
|
|
54065
54191
|
await mkdir25(output);
|
|
54066
54192
|
const request = {
|
|
54067
54193
|
output_dir: output,
|
|
@@ -54073,7 +54199,7 @@ async function exportBlenderScene(input) {
|
|
|
54073
54199
|
bake_materials: input.bakeMaterials === true,
|
|
54074
54200
|
texture_size: size
|
|
54075
54201
|
};
|
|
54076
|
-
const requestFile =
|
|
54202
|
+
const requestFile = path57.join(job, "request.json");
|
|
54077
54203
|
await writeFile12(requestFile, JSON.stringify(request));
|
|
54078
54204
|
await nativeExport(resolveBlenderExecutable(input.blenderExecutable), [
|
|
54079
54205
|
"--background",
|
|
@@ -54086,12 +54212,12 @@ async function exportBlenderScene(input) {
|
|
|
54086
54212
|
resolveSceneExporter(),
|
|
54087
54213
|
"--",
|
|
54088
54214
|
requestFile
|
|
54089
|
-
],
|
|
54090
|
-
if (digest(await
|
|
54091
|
-
const contract = JSON.parse(await
|
|
54215
|
+
], path57.join(job, "blender.log"), input.timeoutMs ?? 9e5);
|
|
54216
|
+
if (digest(await readFile20(source)).sha256 !== sourceHash.sha256) throw new Error("导出期间源 .blend 已变化,请保存后重试");
|
|
54217
|
+
const contract = JSON.parse(await readFile20(path57.join(output, "export-manifest.json"), "utf8"));
|
|
54092
54218
|
const made = await createPackage({
|
|
54093
54219
|
workspaceDir: job,
|
|
54094
|
-
sourceGlbPath:
|
|
54220
|
+
sourceGlbPath: path57.join(output, "model.glb"),
|
|
54095
54221
|
assetId: id,
|
|
54096
54222
|
type: "scene",
|
|
54097
54223
|
source: "blender",
|
|
@@ -54103,23 +54229,23 @@ async function exportBlenderScene(input) {
|
|
|
54103
54229
|
});
|
|
54104
54230
|
const files = {};
|
|
54105
54231
|
async function copyArtifacts(relative = "") {
|
|
54106
|
-
for (const entry of await readdir6(
|
|
54232
|
+
for (const entry of await readdir6(path57.join(output, relative), { withFileTypes: true })) {
|
|
54107
54233
|
const file = relative ? `${relative}/${entry.name}` : entry.name;
|
|
54108
54234
|
if (entry.isSymbolicLink()) throw new Error("导出产物不允许符号链接");
|
|
54109
54235
|
if (entry.isDirectory()) {
|
|
54110
|
-
await mkdir25(
|
|
54236
|
+
await mkdir25(path57.join(made.paths.packageDir, file), { recursive: true });
|
|
54111
54237
|
await copyArtifacts(file);
|
|
54112
54238
|
} else if (entry.isFile() && file !== "export-manifest.json" && !file.endsWith(".blend1")) {
|
|
54113
|
-
const bytes = await
|
|
54114
|
-
await copyFile9(
|
|
54239
|
+
const bytes = await readFile20(path57.join(output, file));
|
|
54240
|
+
await copyFile9(path57.join(output, file), path57.join(made.paths.packageDir, file));
|
|
54115
54241
|
files[file] = digest(bytes);
|
|
54116
54242
|
}
|
|
54117
54243
|
}
|
|
54118
54244
|
}
|
|
54119
54245
|
await copyArtifacts();
|
|
54120
54246
|
async function previousProfile(file, schema) {
|
|
54121
|
-
if (!existsSync10(
|
|
54122
|
-
const profile = JSON.parse(await
|
|
54247
|
+
if (!existsSync10(path57.join(dest, file))) return {};
|
|
54248
|
+
const profile = JSON.parse(await readFile20(path57.join(dest, file), "utf8"));
|
|
54123
54249
|
return profile.schema === schema ? profile : {};
|
|
54124
54250
|
}
|
|
54125
54251
|
const oldGodot = await previousProfile("runtime/godot.profile.json", "evomeme.godot_scene_profile.v1");
|
|
@@ -54130,17 +54256,17 @@ async function exportBlenderScene(input) {
|
|
|
54130
54256
|
buildThreeProfile(id, contract, three);
|
|
54131
54257
|
for (const [file, profile] of [["runtime/godot.profile.json", godot], ["runtime/three.profile.json", three]]) {
|
|
54132
54258
|
const bytes = Buffer.from(JSON.stringify(profile, null, 2));
|
|
54133
|
-
await writeFile12(
|
|
54259
|
+
await writeFile12(path57.join(made.paths.packageDir, file), bytes);
|
|
54134
54260
|
files[file] = digest(bytes);
|
|
54135
54261
|
}
|
|
54136
54262
|
contract.files = files;
|
|
54137
54263
|
contract.display_profiles = { three_js: { profile_file: "runtime/three.profile.json" }, godot: { profile_file: "runtime/godot.profile.json" } };
|
|
54138
|
-
await writeFile12(
|
|
54264
|
+
await writeFile12(path57.join(made.paths.packageDir, "scene.contract.json"), JSON.stringify(contract, null, 2));
|
|
54139
54265
|
await readSceneSupplement(made.paths.packageDir, made.asset);
|
|
54140
54266
|
const check2 = await inspectAsset(job, id, resolveStagePublicDir());
|
|
54141
54267
|
if (!check2.technical_ok) throw new Error("导出 GLB 未通过格式验证;原资产包保持不变。诊断目录:" + job);
|
|
54142
|
-
await safeDirectory(workspace,
|
|
54143
|
-
const backup = existsSync10(dest) ?
|
|
54268
|
+
await safeDirectory(workspace, path57.dirname(dest));
|
|
54269
|
+
const backup = existsSync10(dest) ? path57.join(job, "previous-package") : void 0;
|
|
54144
54270
|
if (backup) {
|
|
54145
54271
|
await safeDirectory(workspace, dest);
|
|
54146
54272
|
await rename5(dest, backup);
|
|
@@ -54154,9 +54280,9 @@ async function exportBlenderScene(input) {
|
|
|
54154
54280
|
return {
|
|
54155
54281
|
asset_id: id,
|
|
54156
54282
|
package_dir: dest,
|
|
54157
|
-
source_blend_path:
|
|
54158
|
-
model_path:
|
|
54159
|
-
contract_path:
|
|
54283
|
+
source_blend_path: path57.join(dest, "source/scene.blend"),
|
|
54284
|
+
model_path: path57.join(dest, "model.glb"),
|
|
54285
|
+
contract_path: path57.join(dest, "scene.contract.json"),
|
|
54160
54286
|
backup_dir: backup,
|
|
54161
54287
|
job_dir: job,
|
|
54162
54288
|
adaptation: check2.adaptation,
|
|
@@ -54171,16 +54297,16 @@ async function exportBlenderScene(input) {
|
|
|
54171
54297
|
// src/stage/syncEngine.ts
|
|
54172
54298
|
function destRoot(projectDir, target) {
|
|
54173
54299
|
if (target === "godot") {
|
|
54174
|
-
return
|
|
54300
|
+
return path58.join(projectDir, "assets", "canonical");
|
|
54175
54301
|
}
|
|
54176
|
-
return
|
|
54302
|
+
return path58.join(projectDir, "public", "assets", "canonical");
|
|
54177
54303
|
}
|
|
54178
54304
|
async function syncPackageToEngine(input) {
|
|
54179
|
-
const projectDir =
|
|
54305
|
+
const projectDir = path58.resolve(input.projectDir);
|
|
54180
54306
|
if (!existsSync11(projectDir)) {
|
|
54181
54307
|
throw new Error(`引擎工程目录不存在:${projectDir}`);
|
|
54182
54308
|
}
|
|
54183
|
-
if (input.target === "godot" && !existsSync11(
|
|
54309
|
+
if (input.target === "godot" && !existsSync11(path58.join(projectDir, "project.godot"))) {
|
|
54184
54310
|
throw new Error(`Godot 工程缺少 project.godot:${projectDir}`);
|
|
54185
54311
|
}
|
|
54186
54312
|
const exported = await exportPackage(input.workspaceDir, input.assetId);
|
|
@@ -54189,12 +54315,12 @@ async function syncPackageToEngine(input) {
|
|
|
54189
54315
|
const godotAppearance = input.target === "godot" ? await godotAppearanceInput(await reviewInputs(input.workspaceDir, input.assetId, publicDir), publicDir) : null;
|
|
54190
54316
|
if (godotAppearance && await readGodotProjectRenderer(projectDir) !== godotAppearance.profile.renderer) throw new Error("Godot 工程渲染器与 Stage 配置不同;更新 profile 并重新查看确认后再同步。");
|
|
54191
54317
|
const threeDelivery = input.target === "three_js" ? await threeDeliveryFiles(publicDir, await reviewInputs(input.workspaceDir, input.assetId, publicDir), confirmation) : null;
|
|
54192
|
-
const gameRuntimeDir =
|
|
54318
|
+
const gameRuntimeDir = path58.join(projectDir, "src", "evomeme-stage", exported.asset.asset_id);
|
|
54193
54319
|
const root = destRoot(projectDir, input.target);
|
|
54194
|
-
const destPackageDir =
|
|
54320
|
+
const destPackageDir = path58.join(root, exported.asset.asset_id);
|
|
54195
54321
|
const hasSupplement = exported.files.includes(SCENE_CONTRACT_FILENAME);
|
|
54196
54322
|
const packageFiles = hasSupplement ? exported.files : [MODEL_FILENAME, ASSET_JSON_FILENAME];
|
|
54197
|
-
if (!hasSupplement && existsSync11(
|
|
54323
|
+
if (!hasSupplement && existsSync11(path58.join(destPackageDir, SCENE_CONTRACT_FILENAME))) throw new Error("目标保留了旧场景契约,不能用不含契约的包覆盖;请先明确清理目标旧包");
|
|
54198
54324
|
const generatedFiles = [input.target === "three_js" ? "applyCanonicalOrientation.example.ts" : "canonical_loader.gd"];
|
|
54199
54325
|
if (input.target === "three_js") generatedFiles.push("applyCanonicalOrientation.ts");
|
|
54200
54326
|
else generatedFiles.push("canonical_appearance.gd", "godot.appearance.json", "GODOT_IMPORT.md");
|
|
@@ -54211,26 +54337,26 @@ async function syncPackageToEngine(input) {
|
|
|
54211
54337
|
if (cursor === destination && !entry.isFile()) throw new Error(`同步目标不是普通文件:${cursor}`);
|
|
54212
54338
|
if (entry.isSymbolicLink()) throw new Error(`同步目标不可包含符号链接或 junction:${cursor}`);
|
|
54213
54339
|
const resolved = await realpath6(cursor);
|
|
54214
|
-
const relative =
|
|
54215
|
-
if (relative === ".." || relative.startsWith(`..${
|
|
54340
|
+
const relative = path58.relative(actualProject, resolved);
|
|
54341
|
+
if (relative === ".." || relative.startsWith(`..${path58.sep}`) || path58.isAbsolute(relative)) throw new Error(`同步目标越出引擎工程:${cursor}`);
|
|
54216
54342
|
} catch (error2) {
|
|
54217
54343
|
if (error2.code !== "ENOENT") throw error2;
|
|
54218
54344
|
}
|
|
54219
|
-
const parent =
|
|
54345
|
+
const parent = path58.dirname(cursor);
|
|
54220
54346
|
if (parent === cursor) throw new Error("同步目标不在引擎工程内");
|
|
54221
54347
|
cursor = parent;
|
|
54222
54348
|
}
|
|
54223
54349
|
}
|
|
54224
|
-
for (const file of [...packageFiles, ...generatedFiles]) await checkDestination(
|
|
54225
|
-
if (threeDelivery) for (const file of threeDelivery.gameFiles.keys()) await checkDestination(
|
|
54226
|
-
await checkDestination(
|
|
54227
|
-
if (await realpath6(exported.paths.packageDir) ===
|
|
54350
|
+
for (const file of [...packageFiles, ...generatedFiles]) await checkDestination(path58.join(destPackageDir, file));
|
|
54351
|
+
if (threeDelivery) for (const file of threeDelivery.gameFiles.keys()) await checkDestination(path58.join(gameRuntimeDir, file));
|
|
54352
|
+
await checkDestination(path58.join(root, "index.json"));
|
|
54353
|
+
if (await realpath6(exported.paths.packageDir) === path58.resolve(destPackageDir)) throw new Error("源资产包与引擎目标目录相同");
|
|
54228
54354
|
await mkdir26(destPackageDir, { recursive: true });
|
|
54229
|
-
const destModel =
|
|
54230
|
-
const destJson =
|
|
54355
|
+
const destModel = path58.join(destPackageDir, MODEL_FILENAME);
|
|
54356
|
+
const destJson = path58.join(destPackageDir, ASSET_JSON_FILENAME);
|
|
54231
54357
|
for (const file of packageFiles) {
|
|
54232
|
-
await mkdir26(
|
|
54233
|
-
await copyFile10(
|
|
54358
|
+
await mkdir26(path58.dirname(path58.join(destPackageDir, file)), { recursive: true });
|
|
54359
|
+
await copyFile10(path58.join(exported.paths.packageDir, file), path58.join(destPackageDir, file));
|
|
54234
54360
|
}
|
|
54235
54361
|
const notes = [
|
|
54236
54362
|
`已同步到 ${destPackageDir}`,
|
|
@@ -54239,7 +54365,7 @@ async function syncPackageToEngine(input) {
|
|
|
54239
54365
|
if (hasSupplement) notes.push("已验证并同步 scene.contract.json 及全部声明依赖。相机须按契约画幅留边;外观 profile 由引擎显式消费,不代表跨渲染器像素一致。");
|
|
54240
54366
|
let helperPath;
|
|
54241
54367
|
if (input.target === "three_js") {
|
|
54242
|
-
const orientationPath =
|
|
54368
|
+
const orientationPath = path58.join(destPackageDir, "applyCanonicalOrientation.ts");
|
|
54243
54369
|
await writeFile13(orientationPath, `// @ts-nocheck
|
|
54244
54370
|
// Generated from the canonical runtime helper.
|
|
54245
54371
|
${runtimeYawRadians.toString()}
|
|
@@ -54247,7 +54373,7 @@ ${degToRad.toString()}
|
|
|
54247
54373
|
${applyCanonicalOrientation.toString()}
|
|
54248
54374
|
export { ${runtimeYawRadians.name} as runtimeYawRadians, ${degToRad.name} as degToRad, ${applyCanonicalOrientation.name} as applyCanonicalOrientation };
|
|
54249
54375
|
`, "utf8");
|
|
54250
|
-
helperPath =
|
|
54376
|
+
helperPath = path58.join(destPackageDir, "applyCanonicalOrientation.example.ts");
|
|
54251
54377
|
await writeFile13(
|
|
54252
54378
|
helperPath,
|
|
54253
54379
|
[
|
|
@@ -54277,19 +54403,19 @@ export { ${runtimeYawRadians.name} as runtimeYawRadians, ${degToRad.name} as deg
|
|
|
54277
54403
|
notes.push(`three 示例加载器:${helperPath}`);
|
|
54278
54404
|
notes.push(`URL:/assets/canonical/${exported.asset.asset_id}/model.glb`);
|
|
54279
54405
|
for (const [file, bytes] of threeDelivery.packageFiles) {
|
|
54280
|
-
await mkdir26(
|
|
54281
|
-
await writeFile13(
|
|
54406
|
+
await mkdir26(path58.dirname(path58.join(destPackageDir, file)), { recursive: true });
|
|
54407
|
+
await writeFile13(path58.join(destPackageDir, file), bytes);
|
|
54282
54408
|
}
|
|
54283
54409
|
for (const [file, bytes] of threeDelivery.gameFiles) {
|
|
54284
|
-
await mkdir26(
|
|
54285
|
-
await writeFile13(
|
|
54410
|
+
await mkdir26(path58.dirname(path58.join(gameRuntimeDir, file)), { recursive: true });
|
|
54411
|
+
await writeFile13(path58.join(gameRuntimeDir, file), bytes);
|
|
54286
54412
|
}
|
|
54287
|
-
helperPath =
|
|
54413
|
+
helperPath = path58.join(gameRuntimeDir, "canonical_loader.js");
|
|
54288
54414
|
notes.push("完整场景使用 loadReviewedScene,并通过返回的 render(camera, delta) 执行同一套灯光、环境、烘焙和后处理。");
|
|
54289
54415
|
notes.push("Three.js 版本锁定为 0.170.0;游戏入口:" + helperPath);
|
|
54290
54416
|
} else {
|
|
54291
|
-
for (const file of authoringFiles) await writeFile13(
|
|
54292
|
-
helperPath =
|
|
54417
|
+
for (const file of authoringFiles) await writeFile13(path58.join(destPackageDir, `${file}.import`), '[remap]\nimporter="keep"\n');
|
|
54418
|
+
helperPath = path58.join(destPackageDir, "canonical_loader.gd");
|
|
54293
54419
|
await writeFile13(
|
|
54294
54420
|
helperPath,
|
|
54295
54421
|
[
|
|
@@ -54372,14 +54498,14 @@ export { ${runtimeYawRadians.name} as runtimeYawRadians, ${degToRad.name} as deg
|
|
|
54372
54498
|
notes.push(`Godot 加载脚本:${helperPath}`);
|
|
54373
54499
|
notes.push("Godot 同步门禁已验证 alignment.ready、源/意图/配方修订与完整 TRS。");
|
|
54374
54500
|
notes.push(`res 路径:res://assets/canonical/${exported.asset.asset_id}/`);
|
|
54375
|
-
await writeFile13(
|
|
54376
|
-
await writeFile13(
|
|
54501
|
+
await writeFile13(path58.join(destPackageDir, "canonical_appearance.gd"), godotAppearance.runtime);
|
|
54502
|
+
await writeFile13(path58.join(destPackageDir, "godot.appearance.json"), JSON.stringify({
|
|
54377
54503
|
profile: godotAppearance.profile,
|
|
54378
54504
|
profile_key: godotAppearance.key,
|
|
54379
54505
|
camera: confirmation.presentation.camera,
|
|
54380
54506
|
stage_revision: confirmation.revision
|
|
54381
54507
|
}, null, 2));
|
|
54382
|
-
const loader = await
|
|
54508
|
+
const loader = await readFile21(helperPath, "utf8");
|
|
54383
54509
|
await writeFile13(helperPath, loader + "\n" + [
|
|
54384
54510
|
"## Scene entry: reproduce Stage-reviewed materials, lights, environment and camera.",
|
|
54385
54511
|
"## Call once for a scene. For props in an existing lit level, use load_package.",
|
|
@@ -54395,7 +54521,7 @@ export { ${runtimeYawRadians.name} as runtimeYawRadians, ${degToRad.name} as deg
|
|
|
54395
54521
|
" return model",
|
|
54396
54522
|
""
|
|
54397
54523
|
].join("\n"));
|
|
54398
|
-
await writeFile13(
|
|
54524
|
+
await writeFile13(path58.join(destPackageDir, "GODOT_IMPORT.md"), `# Godot 已确认场景
|
|
54399
54525
|
|
|
54400
54526
|
Stage 版本:${confirmation.revision}
|
|
54401
54527
|
|
|
@@ -54412,11 +54538,11 @@ ${godotAppearance.profile.warnings.join("\n")}
|
|
|
54412
54538
|
notes.push("已通过 Stage 当前版本 Godot 原生画面确认;使用 load_scene 复现基础材质、灯光、环境和相机。");
|
|
54413
54539
|
notes.push(...godotAppearance.profile.warnings);
|
|
54414
54540
|
}
|
|
54415
|
-
const indexPath =
|
|
54541
|
+
const indexPath = path58.join(root, "index.json");
|
|
54416
54542
|
let index = { assets: {} };
|
|
54417
54543
|
if (existsSync11(indexPath)) {
|
|
54418
54544
|
try {
|
|
54419
|
-
index = JSON.parse(await
|
|
54545
|
+
index = JSON.parse(await readFile21(indexPath, "utf8"));
|
|
54420
54546
|
if (!index.assets) index.assets = {};
|
|
54421
54547
|
} catch {
|
|
54422
54548
|
index = { assets: {} };
|
|
@@ -54433,9 +54559,9 @@ ${godotAppearance.profile.warnings.join("\n")}
|
|
|
54433
54559
|
model_path: destModel,
|
|
54434
54560
|
asset_json_path: destJson,
|
|
54435
54561
|
helper_path: helperPath,
|
|
54436
|
-
scene_contract_path: hasSupplement ?
|
|
54562
|
+
scene_contract_path: hasSupplement ? path58.join(destPackageDir, SCENE_CONTRACT_FILENAME) : void 0,
|
|
54437
54563
|
synced_files: [...packageFiles, ...generatedFiles],
|
|
54438
|
-
game_source_files: threeDelivery ? [...threeDelivery.gameFiles.keys()].map((file) =>
|
|
54564
|
+
game_source_files: threeDelivery ? [...threeDelivery.gameFiles.keys()].map((file) => path58.join(gameRuntimeDir, file)) : void 0,
|
|
54439
54565
|
alignment_status: exported.asset.alignment.overall_status,
|
|
54440
54566
|
alignment_key: exported.asset.alignment.revisions.alignment_key,
|
|
54441
54567
|
notes
|
|
@@ -54731,7 +54857,7 @@ function listStageTools() {
|
|
|
54731
54857
|
function resolveWorkspace2(raw, cwd) {
|
|
54732
54858
|
const value = String(raw || "").trim();
|
|
54733
54859
|
if (!value) throw new Error("workspace_dir 必填");
|
|
54734
|
-
return
|
|
54860
|
+
return path59.resolve(value.startsWith("/") || /^[A-Za-z]:/.test(value) ? value : path59.join(cwd, value));
|
|
54735
54861
|
}
|
|
54736
54862
|
async function handleStageOpen(args, cwd = process.cwd()) {
|
|
54737
54863
|
try {
|
|
@@ -54759,7 +54885,7 @@ async function handleStageOpen(args, cwd = process.cwd()) {
|
|
|
54759
54885
|
async function handleAssetPackageCreate(args, cwd = process.cwd()) {
|
|
54760
54886
|
try {
|
|
54761
54887
|
const workspaceDir = resolveWorkspace2(args.workspace_dir, cwd);
|
|
54762
|
-
const sourceGlbPath =
|
|
54888
|
+
const sourceGlbPath = path59.resolve(String(args.source_glb_path || ""));
|
|
54763
54889
|
const result = await createPackage({
|
|
54764
54890
|
workspaceDir,
|
|
54765
54891
|
sourceGlbPath,
|
|
@@ -54915,7 +55041,7 @@ async function handleAssetRepairBlender(args, cwd = process.cwd()) {
|
|
|
54915
55041
|
async function handleAssetSyncThree(args, cwd = process.cwd()) {
|
|
54916
55042
|
try {
|
|
54917
55043
|
const workspaceDir = resolveWorkspace2(args.workspace_dir, cwd);
|
|
54918
|
-
const projectDir =
|
|
55044
|
+
const projectDir = path59.resolve(String(args.project_dir || ""));
|
|
54919
55045
|
const result = await syncPackageToEngine({
|
|
54920
55046
|
workspaceDir,
|
|
54921
55047
|
assetId: String(args.asset_id || ""),
|
|
@@ -54930,7 +55056,7 @@ async function handleAssetSyncThree(args, cwd = process.cwd()) {
|
|
|
54930
55056
|
async function handleAssetSyncGodot(args, cwd = process.cwd()) {
|
|
54931
55057
|
try {
|
|
54932
55058
|
const workspaceDir = resolveWorkspace2(args.workspace_dir, cwd);
|
|
54933
|
-
const projectDir =
|
|
55059
|
+
const projectDir = path59.resolve(String(args.project_dir || ""));
|
|
54934
55060
|
const result = await syncPackageToEngine({
|
|
54935
55061
|
workspaceDir,
|
|
54936
55062
|
assetId: String(args.asset_id || ""),
|
|
@@ -55003,10 +55129,12 @@ function listMcpTools() {
|
|
|
55003
55129
|
return [
|
|
55004
55130
|
checkEvomemeLoginTool,
|
|
55005
55131
|
loginEvomemeTool,
|
|
55132
|
+
reinitProjectTool,
|
|
55006
55133
|
submitGameCodeTool,
|
|
55007
55134
|
uploadGameAssetTool,
|
|
55008
55135
|
generateGameImageTool,
|
|
55009
55136
|
cutoutGameImageTool,
|
|
55137
|
+
colorKeyTool,
|
|
55010
55138
|
generateGameVideoTool,
|
|
55011
55139
|
// ...listMeshTools(),
|
|
55012
55140
|
...listStageTools()
|
|
@@ -55022,14 +55150,21 @@ async function dispatchToolCall(name, rawArgs = {}) {
|
|
|
55022
55150
|
if (name === SUBMIT_GAME_CODE_TOOL_NAME) {
|
|
55023
55151
|
return handleSubmitGameCode(parseSubmitArgs(rawArgs));
|
|
55024
55152
|
}
|
|
55153
|
+
if (name === REINIT_PROJECT_TOOL_NAME) {
|
|
55154
|
+
const { workspace_dir, name: projectName } = parseSubmitArgs(rawArgs);
|
|
55155
|
+
return handleReinitProject({ workspace_dir, name: projectName });
|
|
55156
|
+
}
|
|
55025
55157
|
if (name === UPLOAD_GAME_ASSET_TOOL_NAME) {
|
|
55026
55158
|
return handleUploadGameAsset(parseUploadArgs(rawArgs));
|
|
55027
55159
|
}
|
|
55028
55160
|
if (name === GENERATE_GAME_IMAGE_TOOL_NAME) {
|
|
55029
|
-
return handleGenerateGameImage(
|
|
55161
|
+
return handleGenerateGameImage(rawArgs);
|
|
55030
55162
|
}
|
|
55031
55163
|
if (name === CUTOUT_GAME_IMAGE_TOOL_NAME) {
|
|
55032
|
-
return handleCutoutGameImage(
|
|
55164
|
+
return handleCutoutGameImage(rawArgs);
|
|
55165
|
+
}
|
|
55166
|
+
if (name === COLOR_KEY_TOOL_NAME) {
|
|
55167
|
+
return handleColorKey(rawArgs);
|
|
55033
55168
|
}
|
|
55034
55169
|
if (name === GENERATE_GAME_VIDEO_TOOL_NAME) {
|
|
55035
55170
|
return handleGenerateGameVideo(parseGenerateVideoArgs(rawArgs));
|
|
@@ -55071,23 +55206,6 @@ function parseUploadArgs(args) {
|
|
|
55071
55206
|
extension: typeof args.extension === "string" ? args.extension : void 0
|
|
55072
55207
|
};
|
|
55073
55208
|
}
|
|
55074
|
-
function parseGenerateImageArgs(args) {
|
|
55075
|
-
return {
|
|
55076
|
-
prompt: typeof args.prompt === "string" ? args.prompt : "",
|
|
55077
|
-
image_type: typeof args.image_type === "string" ? args.image_type : void 0,
|
|
55078
|
-
size: typeof args.size === "string" ? args.size : void 0,
|
|
55079
|
-
reference_image_url: typeof args.reference_image_url === "string" ? args.reference_image_url : Array.isArray(args.reference_image_url) ? args.reference_image_url.filter((value) => typeof value === "string") : void 0,
|
|
55080
|
-
image_model: typeof args.image_model === "string" ? args.image_model : void 0,
|
|
55081
|
-
background: typeof args.background === "string" ? args.background : void 0,
|
|
55082
|
-
workspace_dir: typeof args.workspace_dir === "string" ? args.workspace_dir : void 0
|
|
55083
|
-
};
|
|
55084
|
-
}
|
|
55085
|
-
function parseCutoutImageArgs(args) {
|
|
55086
|
-
return {
|
|
55087
|
-
image_url: typeof args.image_url === "string" ? args.image_url : "",
|
|
55088
|
-
workspace_dir: typeof args.workspace_dir === "string" ? args.workspace_dir : void 0
|
|
55089
|
-
};
|
|
55090
|
-
}
|
|
55091
55209
|
function parseGenerateVideoArgs(args) {
|
|
55092
55210
|
const references = Array.isArray(args.references) ? args.references.filter((value) => Boolean(value && typeof value === "object")).map((value) => ({
|
|
55093
55211
|
type: typeof value.type === "string" ? value.type : void 0,
|