@fangyb/ahchat-bridge 0.1.32 → 0.1.34
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/cli.cjs +1765 -429
- package/dist/feedbackWorkerCli.cjs +421 -11
- package/dist/index.js +1754 -427
- package/dist/seedanceMcpCli.cjs +234 -40
- package/dist/seedreamMcpCli.cjs +31904 -0
- package/package.json +15 -13
package/dist/seedanceMcpCli.cjs
CHANGED
|
@@ -3258,8 +3258,8 @@ var require_utils = __commonJS({
|
|
|
3258
3258
|
}
|
|
3259
3259
|
return ind;
|
|
3260
3260
|
}
|
|
3261
|
-
function removeDotSegments(
|
|
3262
|
-
let input =
|
|
3261
|
+
function removeDotSegments(path2) {
|
|
3262
|
+
let input = path2;
|
|
3263
3263
|
const output = [];
|
|
3264
3264
|
let nextSlash = -1;
|
|
3265
3265
|
let len = 0;
|
|
@@ -3512,8 +3512,8 @@ var require_schemes = __commonJS({
|
|
|
3512
3512
|
wsComponent.secure = void 0;
|
|
3513
3513
|
}
|
|
3514
3514
|
if (wsComponent.resourceName) {
|
|
3515
|
-
const [
|
|
3516
|
-
wsComponent.path =
|
|
3515
|
+
const [path2, query] = wsComponent.resourceName.split("?");
|
|
3516
|
+
wsComponent.path = path2 && path2 !== "/" ? path2 : void 0;
|
|
3517
3517
|
wsComponent.query = query;
|
|
3518
3518
|
wsComponent.resourceName = void 0;
|
|
3519
3519
|
}
|
|
@@ -6952,12 +6952,12 @@ var require_dist = __commonJS({
|
|
|
6952
6952
|
throw new Error(`Unknown format "${name}"`);
|
|
6953
6953
|
return f;
|
|
6954
6954
|
};
|
|
6955
|
-
function addFormats(ajv, list,
|
|
6955
|
+
function addFormats(ajv, list, fs2, exportName) {
|
|
6956
6956
|
var _a3;
|
|
6957
6957
|
var _b;
|
|
6958
6958
|
(_a3 = (_b = ajv.opts.code).formats) !== null && _a3 !== void 0 ? _a3 : _b.formats = (0, codegen_1._)`require("ajv-formats/dist/formats").${exportName}`;
|
|
6959
6959
|
for (const f of list)
|
|
6960
|
-
ajv.addFormat(f,
|
|
6960
|
+
ajv.addFormat(f, fs2[f]);
|
|
6961
6961
|
}
|
|
6962
6962
|
module2.exports = exports2 = formatsPlugin;
|
|
6963
6963
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
@@ -7350,8 +7350,8 @@ function getErrorMap() {
|
|
|
7350
7350
|
// ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/helpers/parseUtil.js
|
|
7351
7351
|
init_cjs_shims();
|
|
7352
7352
|
var makeIssue = (params) => {
|
|
7353
|
-
const { data, path, errorMaps, issueData } = params;
|
|
7354
|
-
const fullPath = [...
|
|
7353
|
+
const { data, path: path2, errorMaps, issueData } = params;
|
|
7354
|
+
const fullPath = [...path2, ...issueData.path || []];
|
|
7355
7355
|
const fullIssue = {
|
|
7356
7356
|
...issueData,
|
|
7357
7357
|
path: fullPath
|
|
@@ -7470,11 +7470,11 @@ var errorUtil;
|
|
|
7470
7470
|
|
|
7471
7471
|
// ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v3/types.js
|
|
7472
7472
|
var ParseInputLazyPath = class {
|
|
7473
|
-
constructor(parent, value,
|
|
7473
|
+
constructor(parent, value, path2, key) {
|
|
7474
7474
|
this._cachedPath = [];
|
|
7475
7475
|
this.parent = parent;
|
|
7476
7476
|
this.data = value;
|
|
7477
|
-
this._path =
|
|
7477
|
+
this._path = path2;
|
|
7478
7478
|
this._key = key;
|
|
7479
7479
|
}
|
|
7480
7480
|
get path() {
|
|
@@ -11406,10 +11406,10 @@ function mergeDefs(...defs) {
|
|
|
11406
11406
|
function cloneDef(schema) {
|
|
11407
11407
|
return mergeDefs(schema._zod.def);
|
|
11408
11408
|
}
|
|
11409
|
-
function getElementAtPath(obj,
|
|
11410
|
-
if (!
|
|
11409
|
+
function getElementAtPath(obj, path2) {
|
|
11410
|
+
if (!path2)
|
|
11411
11411
|
return obj;
|
|
11412
|
-
return
|
|
11412
|
+
return path2.reduce((acc, key) => acc?.[key], obj);
|
|
11413
11413
|
}
|
|
11414
11414
|
function promiseAllObject(promisesObj) {
|
|
11415
11415
|
const keys = Object.keys(promisesObj);
|
|
@@ -11818,11 +11818,11 @@ function explicitlyAborted(x, startIndex = 0) {
|
|
|
11818
11818
|
}
|
|
11819
11819
|
return false;
|
|
11820
11820
|
}
|
|
11821
|
-
function prefixIssues(
|
|
11821
|
+
function prefixIssues(path2, issues) {
|
|
11822
11822
|
return issues.map((iss) => {
|
|
11823
11823
|
var _a3;
|
|
11824
11824
|
(_a3 = iss).path ?? (_a3.path = []);
|
|
11825
|
-
iss.path.unshift(
|
|
11825
|
+
iss.path.unshift(path2);
|
|
11826
11826
|
return iss;
|
|
11827
11827
|
});
|
|
11828
11828
|
}
|
|
@@ -11969,16 +11969,16 @@ function flattenError(error51, mapper = (issue2) => issue2.message) {
|
|
|
11969
11969
|
}
|
|
11970
11970
|
function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
11971
11971
|
const fieldErrors = { _errors: [] };
|
|
11972
|
-
const processError = (error52,
|
|
11972
|
+
const processError = (error52, path2 = []) => {
|
|
11973
11973
|
for (const issue2 of error52.issues) {
|
|
11974
11974
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
11975
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
11975
|
+
issue2.errors.map((issues) => processError({ issues }, [...path2, ...issue2.path]));
|
|
11976
11976
|
} else if (issue2.code === "invalid_key") {
|
|
11977
|
-
processError({ issues: issue2.issues }, [...
|
|
11977
|
+
processError({ issues: issue2.issues }, [...path2, ...issue2.path]);
|
|
11978
11978
|
} else if (issue2.code === "invalid_element") {
|
|
11979
|
-
processError({ issues: issue2.issues }, [...
|
|
11979
|
+
processError({ issues: issue2.issues }, [...path2, ...issue2.path]);
|
|
11980
11980
|
} else {
|
|
11981
|
-
const fullpath = [...
|
|
11981
|
+
const fullpath = [...path2, ...issue2.path];
|
|
11982
11982
|
if (fullpath.length === 0) {
|
|
11983
11983
|
fieldErrors._errors.push(mapper(issue2));
|
|
11984
11984
|
} else {
|
|
@@ -12005,17 +12005,17 @@ function formatError(error51, mapper = (issue2) => issue2.message) {
|
|
|
12005
12005
|
}
|
|
12006
12006
|
function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
12007
12007
|
const result = { errors: [] };
|
|
12008
|
-
const processError = (error52,
|
|
12008
|
+
const processError = (error52, path2 = []) => {
|
|
12009
12009
|
var _a3, _b;
|
|
12010
12010
|
for (const issue2 of error52.issues) {
|
|
12011
12011
|
if (issue2.code === "invalid_union" && issue2.errors.length) {
|
|
12012
|
-
issue2.errors.map((issues) => processError({ issues }, [...
|
|
12012
|
+
issue2.errors.map((issues) => processError({ issues }, [...path2, ...issue2.path]));
|
|
12013
12013
|
} else if (issue2.code === "invalid_key") {
|
|
12014
|
-
processError({ issues: issue2.issues }, [...
|
|
12014
|
+
processError({ issues: issue2.issues }, [...path2, ...issue2.path]);
|
|
12015
12015
|
} else if (issue2.code === "invalid_element") {
|
|
12016
|
-
processError({ issues: issue2.issues }, [...
|
|
12016
|
+
processError({ issues: issue2.issues }, [...path2, ...issue2.path]);
|
|
12017
12017
|
} else {
|
|
12018
|
-
const fullpath = [...
|
|
12018
|
+
const fullpath = [...path2, ...issue2.path];
|
|
12019
12019
|
if (fullpath.length === 0) {
|
|
12020
12020
|
result.errors.push(mapper(issue2));
|
|
12021
12021
|
continue;
|
|
@@ -12047,8 +12047,8 @@ function treeifyError(error51, mapper = (issue2) => issue2.message) {
|
|
|
12047
12047
|
}
|
|
12048
12048
|
function toDotPath(_path) {
|
|
12049
12049
|
const segs = [];
|
|
12050
|
-
const
|
|
12051
|
-
for (const seg of
|
|
12050
|
+
const path2 = _path.map((seg) => typeof seg === "object" ? seg.key : seg);
|
|
12051
|
+
for (const seg of path2) {
|
|
12052
12052
|
if (typeof seg === "number")
|
|
12053
12053
|
segs.push(`[${seg}]`);
|
|
12054
12054
|
else if (typeof seg === "symbol")
|
|
@@ -25262,13 +25262,13 @@ function resolveRef(ref, ctx) {
|
|
|
25262
25262
|
if (!ref.startsWith("#")) {
|
|
25263
25263
|
throw new Error("External $ref is not supported, only local refs (#/...) are allowed");
|
|
25264
25264
|
}
|
|
25265
|
-
const
|
|
25266
|
-
if (
|
|
25265
|
+
const path2 = ref.slice(1).split("/").filter(Boolean);
|
|
25266
|
+
if (path2.length === 0) {
|
|
25267
25267
|
return ctx.rootSchema;
|
|
25268
25268
|
}
|
|
25269
25269
|
const defsKey = ctx.version === "draft-2020-12" ? "$defs" : "definitions";
|
|
25270
|
-
if (
|
|
25271
|
-
const key =
|
|
25270
|
+
if (path2[0] === defsKey) {
|
|
25271
|
+
const key = path2[1];
|
|
25272
25272
|
if (!key || !ctx.defs[key]) {
|
|
25273
25273
|
throw new Error(`Reference not found: ${ref}`);
|
|
25274
25274
|
}
|
|
@@ -31231,6 +31231,63 @@ var StdioServerTransport = class {
|
|
|
31231
31231
|
}
|
|
31232
31232
|
};
|
|
31233
31233
|
|
|
31234
|
+
// src/seedanceMcpCli.ts
|
|
31235
|
+
var import_promises = __toESM(require("fs/promises"), 1);
|
|
31236
|
+
var import_node_path = __toESM(require("path"), 1);
|
|
31237
|
+
|
|
31238
|
+
// src/officialMcpQuota.ts
|
|
31239
|
+
init_cjs_shims();
|
|
31240
|
+
var OfficialMcpQuotaError = class extends Error {
|
|
31241
|
+
constructor(message) {
|
|
31242
|
+
super(message);
|
|
31243
|
+
this.name = "OfficialMcpQuotaError";
|
|
31244
|
+
}
|
|
31245
|
+
};
|
|
31246
|
+
async function consumeOfficialMcpDailyQuota(serverName, toolName) {
|
|
31247
|
+
const serverApiUrl = process.env.AHCHAT_SERVER_API_URL?.trim();
|
|
31248
|
+
const bridgeToken = process.env.AHCHAT_BRIDGE_TOKEN?.trim();
|
|
31249
|
+
if (!serverApiUrl || !bridgeToken) return;
|
|
31250
|
+
let response;
|
|
31251
|
+
try {
|
|
31252
|
+
response = await fetch(`${serverApiUrl.replace(/\/+$/, "")}/api/mcp/usage/consume`, {
|
|
31253
|
+
method: "POST",
|
|
31254
|
+
headers: {
|
|
31255
|
+
"Content-Type": "application/json",
|
|
31256
|
+
"X-AHChat-Bridge-Token": bridgeToken
|
|
31257
|
+
},
|
|
31258
|
+
body: JSON.stringify({ serverName, toolName })
|
|
31259
|
+
});
|
|
31260
|
+
} catch {
|
|
31261
|
+
throw new OfficialMcpQuotaError("\u6682\u65F6\u65E0\u6CD5\u6821\u9A8C\u5B98\u65B9\u5A92\u4F53 MCP \u6BCF\u65E5\u989D\u5EA6\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\u3002");
|
|
31262
|
+
}
|
|
31263
|
+
if (response.status === 404) return;
|
|
31264
|
+
const body = await readQuotaResponse(response);
|
|
31265
|
+
if (response.status === 429 || body.allowed === false) {
|
|
31266
|
+
throw new OfficialMcpQuotaError(formatQuotaExceededMessage(serverName, body));
|
|
31267
|
+
}
|
|
31268
|
+
if (!response.ok) {
|
|
31269
|
+
throw new OfficialMcpQuotaError(body.message || "\u5B98\u65B9\u5A92\u4F53 MCP \u6BCF\u65E5\u989D\u5EA6\u6821\u9A8C\u5931\u8D25\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\u3002");
|
|
31270
|
+
}
|
|
31271
|
+
}
|
|
31272
|
+
async function readQuotaResponse(response) {
|
|
31273
|
+
try {
|
|
31274
|
+
const value = await response.json();
|
|
31275
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
31276
|
+
return value;
|
|
31277
|
+
}
|
|
31278
|
+
} catch {
|
|
31279
|
+
}
|
|
31280
|
+
return {};
|
|
31281
|
+
}
|
|
31282
|
+
function formatQuotaExceededMessage(serverName, body) {
|
|
31283
|
+
if (body.message) return body.message;
|
|
31284
|
+
const label = serverName === "seedance" ? "\u751F\u89C6\u9891" : serverName === "seedream" ? "\u751F\u56FE" : "\u5B98\u65B9\u5A92\u4F53";
|
|
31285
|
+
if (typeof body.used === "number" && typeof body.limit === "number") {
|
|
31286
|
+
return `\u4ECA\u5929\u7684${label}\u989D\u5EA6\u5DF2\u7528\u5B8C\uFF08${body.used}/${body.limit}\uFF09\u3002\u8BF7\u660E\u5929\u518D\u8BD5\uFF0C\u6216\u8054\u7CFB\u8FD0\u8425\u8C03\u6574\u989D\u5EA6\u3002`;
|
|
31287
|
+
}
|
|
31288
|
+
return `\u4ECA\u5929\u7684${label}\u989D\u5EA6\u5DF2\u7528\u5B8C\u3002\u8BF7\u660E\u5929\u518D\u8BD5\uFF0C\u6216\u8054\u7CFB\u8FD0\u8425\u8C03\u6574\u989D\u5EA6\u3002`;
|
|
31289
|
+
}
|
|
31290
|
+
|
|
31234
31291
|
// src/seedanceMcpCli.ts
|
|
31235
31292
|
var SERVER_NAME = "ahchat-seedance-mcp";
|
|
31236
31293
|
var SERVER_VERSION = "0.1.0";
|
|
@@ -31292,7 +31349,7 @@ function createServer() {
|
|
|
31292
31349
|
const server = new McpServer(
|
|
31293
31350
|
{ name: SERVER_NAME, version: SERVER_VERSION },
|
|
31294
31351
|
{
|
|
31295
|
-
instructions: "AHChat official Seedance video generation MCP. Call seedance_create_task to submit a job, then seedance_check_task
|
|
31352
|
+
instructions: "AHChat official Seedance video generation MCP. Each user request should create exactly one video task. Call seedance_create_task once to submit a job, then seedance_check_task only when progress is requested. Generated URLs can expire; show or download them promptly."
|
|
31296
31353
|
}
|
|
31297
31354
|
);
|
|
31298
31355
|
server.registerTool(
|
|
@@ -31315,7 +31372,7 @@ function createServer() {
|
|
|
31315
31372
|
"seedance_create_task",
|
|
31316
31373
|
{
|
|
31317
31374
|
title: "Create Seedance video generation task",
|
|
31318
|
-
description: "Submit
|
|
31375
|
+
description: "Submit exactly one Seedance video generation task to the Volcengine Ark API and return the task_id immediately. In AHChat, do not submit alternate tasks, loop, or sleep afterwards; the media task card tracks status.",
|
|
31319
31376
|
inputSchema: createTaskInputShape,
|
|
31320
31377
|
annotations: {
|
|
31321
31378
|
readOnlyHint: false,
|
|
@@ -31328,6 +31385,7 @@ function createServer() {
|
|
|
31328
31385
|
if (validationError) return errorResult(validationError);
|
|
31329
31386
|
try {
|
|
31330
31387
|
const normalized = normalizeCreateTaskInput(input);
|
|
31388
|
+
await consumeOfficialMcpDailyQuota("seedance", "seedance_create_task");
|
|
31331
31389
|
const result = await createSeedanceTask(normalized);
|
|
31332
31390
|
const payload = {
|
|
31333
31391
|
state: "submitted",
|
|
@@ -31363,12 +31421,16 @@ function createServer() {
|
|
|
31363
31421
|
async (input) => {
|
|
31364
31422
|
try {
|
|
31365
31423
|
const parsed = checkTaskInputSchema.parse(input);
|
|
31366
|
-
const result = await checkSeedanceTask(parsed.task_id);
|
|
31424
|
+
const result = await withDownloadedSeedanceVideo(await checkSeedanceTask(parsed.task_id));
|
|
31367
31425
|
const payload = {
|
|
31368
31426
|
task_id: result.id,
|
|
31369
31427
|
status: result.status,
|
|
31370
31428
|
video_url: result.videoUrl,
|
|
31371
31429
|
last_frame_url: result.lastFrameUrl,
|
|
31430
|
+
local_path: result.localPath,
|
|
31431
|
+
file_name: result.fileName,
|
|
31432
|
+
mime_type: result.mimeType,
|
|
31433
|
+
download_error: result.downloadError,
|
|
31372
31434
|
fail_reason: result.failReason
|
|
31373
31435
|
};
|
|
31374
31436
|
return {
|
|
@@ -31495,12 +31557,139 @@ async function checkSeedanceTask(taskId) {
|
|
|
31495
31557
|
raw: obj
|
|
31496
31558
|
};
|
|
31497
31559
|
}
|
|
31560
|
+
async function withDownloadedSeedanceVideo(result) {
|
|
31561
|
+
if (!result.videoUrl) return result;
|
|
31562
|
+
try {
|
|
31563
|
+
const downloaded = await downloadGeneratedVideoToWorkdir(result.videoUrl, result.id);
|
|
31564
|
+
return {
|
|
31565
|
+
...result,
|
|
31566
|
+
localPath: downloaded.localPath,
|
|
31567
|
+
fileName: downloaded.fileName,
|
|
31568
|
+
mimeType: downloaded.mimeType
|
|
31569
|
+
};
|
|
31570
|
+
} catch (error51) {
|
|
31571
|
+
return {
|
|
31572
|
+
...result,
|
|
31573
|
+
downloadError: error51 instanceof Error ? error51.message : String(error51)
|
|
31574
|
+
};
|
|
31575
|
+
}
|
|
31576
|
+
}
|
|
31577
|
+
async function downloadGeneratedVideoToWorkdir(url2, taskId) {
|
|
31578
|
+
if (!/^https?:\/\//i.test(url2)) {
|
|
31579
|
+
throw new Error("generated video is not a downloadable URL");
|
|
31580
|
+
}
|
|
31581
|
+
const existingFileName = generatedVideoFileName(taskId, videoExtensionFromUrl(url2) ?? ".mp4");
|
|
31582
|
+
const existingPath = import_node_path.default.join(process.cwd(), existingFileName);
|
|
31583
|
+
if (await fileExists(existingPath)) {
|
|
31584
|
+
return {
|
|
31585
|
+
localPath: existingPath,
|
|
31586
|
+
fileName: existingFileName,
|
|
31587
|
+
mimeType: videoMimeTypeFromPath(existingPath) ?? "video/mp4"
|
|
31588
|
+
};
|
|
31589
|
+
}
|
|
31590
|
+
const response = await fetch(url2, { signal: AbortSignal.timeout(18e4) });
|
|
31591
|
+
if (!response.ok) {
|
|
31592
|
+
throw new Error(`download failed with HTTP ${response.status}`);
|
|
31593
|
+
}
|
|
31594
|
+
const buffer = Buffer.from(await response.arrayBuffer());
|
|
31595
|
+
const mimeType = videoMimeTypeFromContentType(response.headers.get("content-type")) ?? videoMimeTypeFromUrl(url2) ?? "video/mp4";
|
|
31596
|
+
const extension = videoExtensionForMimeType(mimeType);
|
|
31597
|
+
const fileName = generatedVideoFileName(taskId, extension);
|
|
31598
|
+
const filePath = import_node_path.default.join(process.cwd(), fileName);
|
|
31599
|
+
await import_promises.default.mkdir(process.cwd(), { recursive: true });
|
|
31600
|
+
try {
|
|
31601
|
+
await import_promises.default.writeFile(filePath, buffer, { flag: "wx" });
|
|
31602
|
+
} catch (error51) {
|
|
31603
|
+
if (!isFileExistsError(error51)) throw error51;
|
|
31604
|
+
}
|
|
31605
|
+
return { localPath: filePath, fileName, mimeType };
|
|
31606
|
+
}
|
|
31607
|
+
function generatedVideoFileName(taskId, extension) {
|
|
31608
|
+
const safeTaskId = taskId.replace(/[^A-Za-z0-9._-]+/g, "_").slice(0, 96) || "task";
|
|
31609
|
+
return `seedance-${safeTaskId}${extension}`;
|
|
31610
|
+
}
|
|
31611
|
+
async function fileExists(filePath) {
|
|
31612
|
+
try {
|
|
31613
|
+
await import_promises.default.access(filePath);
|
|
31614
|
+
return true;
|
|
31615
|
+
} catch {
|
|
31616
|
+
return false;
|
|
31617
|
+
}
|
|
31618
|
+
}
|
|
31619
|
+
function videoMimeTypeFromContentType(contentType) {
|
|
31620
|
+
if (!contentType) return null;
|
|
31621
|
+
return normalizeVideoMimeType(contentType.split(";")[0]?.trim() ?? "");
|
|
31622
|
+
}
|
|
31623
|
+
function videoMimeTypeFromUrl(url2) {
|
|
31624
|
+
try {
|
|
31625
|
+
return videoMimeTypeFromPath(new URL(url2).pathname);
|
|
31626
|
+
} catch {
|
|
31627
|
+
return videoMimeTypeFromPath(url2);
|
|
31628
|
+
}
|
|
31629
|
+
}
|
|
31630
|
+
function videoExtensionFromUrl(url2) {
|
|
31631
|
+
try {
|
|
31632
|
+
return videoExtensionFromPath(new URL(url2).pathname);
|
|
31633
|
+
} catch {
|
|
31634
|
+
return videoExtensionFromPath(url2);
|
|
31635
|
+
}
|
|
31636
|
+
}
|
|
31637
|
+
function videoMimeTypeFromPath(filePath) {
|
|
31638
|
+
switch (import_node_path.default.extname(filePath).toLowerCase()) {
|
|
31639
|
+
case ".mov":
|
|
31640
|
+
return "video/quicktime";
|
|
31641
|
+
case ".webm":
|
|
31642
|
+
return "video/webm";
|
|
31643
|
+
case ".m4v":
|
|
31644
|
+
return "video/x-m4v";
|
|
31645
|
+
case ".mp4":
|
|
31646
|
+
return "video/mp4";
|
|
31647
|
+
default:
|
|
31648
|
+
return null;
|
|
31649
|
+
}
|
|
31650
|
+
}
|
|
31651
|
+
function videoExtensionFromPath(filePath) {
|
|
31652
|
+
switch (import_node_path.default.extname(filePath).toLowerCase()) {
|
|
31653
|
+
case ".mov":
|
|
31654
|
+
case ".webm":
|
|
31655
|
+
case ".m4v":
|
|
31656
|
+
case ".mp4":
|
|
31657
|
+
return import_node_path.default.extname(filePath).toLowerCase();
|
|
31658
|
+
default:
|
|
31659
|
+
return null;
|
|
31660
|
+
}
|
|
31661
|
+
}
|
|
31662
|
+
function normalizeVideoMimeType(mimeType) {
|
|
31663
|
+
const normalized = mimeType.toLowerCase();
|
|
31664
|
+
if (normalized === "video/mp4" || normalized === "video/quicktime" || normalized === "video/webm" || normalized === "video/x-m4v") {
|
|
31665
|
+
return normalized;
|
|
31666
|
+
}
|
|
31667
|
+
return null;
|
|
31668
|
+
}
|
|
31669
|
+
function videoExtensionForMimeType(mimeType) {
|
|
31670
|
+
switch (mimeType) {
|
|
31671
|
+
case "video/quicktime":
|
|
31672
|
+
return ".mov";
|
|
31673
|
+
case "video/webm":
|
|
31674
|
+
return ".webm";
|
|
31675
|
+
case "video/x-m4v":
|
|
31676
|
+
return ".m4v";
|
|
31677
|
+
default:
|
|
31678
|
+
return ".mp4";
|
|
31679
|
+
}
|
|
31680
|
+
}
|
|
31681
|
+
function isFileExistsError(error51) {
|
|
31682
|
+
return Boolean(error51 && typeof error51 === "object" && error51.code === "EEXIST");
|
|
31683
|
+
}
|
|
31498
31684
|
async function parseJsonSafe(response) {
|
|
31499
31685
|
const text = await response.text();
|
|
31500
31686
|
if (!text) return void 0;
|
|
31501
31687
|
try {
|
|
31502
31688
|
return JSON.parse(text);
|
|
31503
|
-
} catch {
|
|
31689
|
+
} catch (error51) {
|
|
31690
|
+
writeStderr(
|
|
31691
|
+
`[${SERVER_NAME}] ARK API returned a non-JSON response body: ${error51 instanceof Error ? error51.message : String(error51)}`
|
|
31692
|
+
);
|
|
31504
31693
|
return text;
|
|
31505
31694
|
}
|
|
31506
31695
|
}
|
|
@@ -31579,22 +31768,27 @@ function errorResult(message) {
|
|
|
31579
31768
|
function usageGuide() {
|
|
31580
31769
|
return [
|
|
31581
31770
|
"AHChat Seedance workflow:",
|
|
31582
|
-
"1. Call seedance_create_task with prompt and optional reference media URLs.",
|
|
31583
|
-
"2.
|
|
31584
|
-
"3.
|
|
31771
|
+
"1. Call seedance_create_task with prompt and optional reference media URLs. Each user request creates exactly one video task.",
|
|
31772
|
+
"2. After submission, stop manual waiting. AHChat will track the task in the visible media card.",
|
|
31773
|
+
"3. Only call seedance_check_task once when the user explicitly asks for progress or when diagnostics are needed.",
|
|
31774
|
+
"4. When status is succeeded, keep the text reply short and let the media card show preview, download, copy, and regenerate actions. Signed URLs may expire.",
|
|
31585
31775
|
"",
|
|
31586
31776
|
"Common defaults: model=doubao-seedance-2-0-260128, duration=5, ratio=16:9, resolution=720p, generate_audio=true.",
|
|
31587
31777
|
"For vertical short video, set ratio=9:16. Reference media URLs must be reachable by Volcengine Ark."
|
|
31588
31778
|
].join("\n");
|
|
31589
31779
|
}
|
|
31780
|
+
function writeStderr(message) {
|
|
31781
|
+
process.stderr.write(`${message}
|
|
31782
|
+
`);
|
|
31783
|
+
}
|
|
31590
31784
|
async function main() {
|
|
31591
31785
|
const server = createServer();
|
|
31592
31786
|
const transport = new StdioServerTransport();
|
|
31593
31787
|
await server.connect(transport);
|
|
31594
|
-
|
|
31788
|
+
writeStderr(`${SERVER_NAME} v${SERVER_VERSION} running on stdio`);
|
|
31595
31789
|
}
|
|
31596
31790
|
main().catch((error51) => {
|
|
31597
31791
|
const message = error51 instanceof Error ? error51.stack ?? error51.message : String(error51);
|
|
31598
|
-
|
|
31792
|
+
writeStderr(`Fatal error in ${SERVER_NAME}: ${message}`);
|
|
31599
31793
|
process.exit(1);
|
|
31600
31794
|
});
|