@fastgpt-plugin/cli 0.2.0-alpha.1 → 0.2.0-alpha.2
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 +600 -41
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { registerHooks, stripTypeScriptTypes } from "node:module";
|
|
2
|
+
import { createRequire, registerHooks, stripTypeScriptTypes } from "node:module";
|
|
3
3
|
import fs from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
@@ -526,7 +526,7 @@ var CheckCommand = class extends BaseCommand {
|
|
|
526
526
|
//#endregion
|
|
527
527
|
//#region package.json
|
|
528
528
|
var name = "@fastgpt-plugin/cli";
|
|
529
|
-
var version = "0.2.0-alpha.
|
|
529
|
+
var version = "0.2.0-alpha.2";
|
|
530
530
|
|
|
531
531
|
//#endregion
|
|
532
532
|
//#region src/constants.ts
|
|
@@ -686,6 +686,40 @@ var CreateCommand = class extends BaseCommand {
|
|
|
686
686
|
}
|
|
687
687
|
};
|
|
688
688
|
|
|
689
|
+
//#endregion
|
|
690
|
+
//#region ../../packages/domain/src/value-objects/plugin-debug-session.vo.ts
|
|
691
|
+
const PLUGIN_DEBUG_SOURCE_KIND = "debug";
|
|
692
|
+
const PLUGIN_DEBUG_SESSION_SOURCE_TMB_ID_KEY = "tmbId";
|
|
693
|
+
const PLUGIN_DEBUG_SOURCE_PREFIX = `${PLUGIN_DEBUG_SOURCE_KIND}:`;
|
|
694
|
+
const PLUGIN_DEBUG_SESSION_SOURCE_FORMAT = `${PLUGIN_DEBUG_SOURCE_KIND}:${PLUGIN_DEBUG_SESSION_SOURCE_TMB_ID_KEY}:{tmbId}`;
|
|
695
|
+
const PluginDebugSessionIdSchema = z.string().min(1);
|
|
696
|
+
const PluginDebugSessionTmbIdSchema = z.string().min(1);
|
|
697
|
+
const PluginDebugSessionSourceSchema = z.string().min(1).refine((source) => parsePluginDebugSessionSource(source) !== null, { message: "Invalid plugin debug session source" });
|
|
698
|
+
const PluginDebugSessionStatusSchema = z.enum([
|
|
699
|
+
"enabled",
|
|
700
|
+
"connected",
|
|
701
|
+
"disconnected",
|
|
702
|
+
"revoked"
|
|
703
|
+
]);
|
|
704
|
+
const PluginDebugSessionSchema = z.object({
|
|
705
|
+
tmbId: PluginDebugSessionTmbIdSchema,
|
|
706
|
+
source: PluginDebugSessionSourceSchema,
|
|
707
|
+
status: PluginDebugSessionStatusSchema,
|
|
708
|
+
enabled: z.boolean(),
|
|
709
|
+
keyId: z.string().min(1),
|
|
710
|
+
connectionKeyHash: z.string().min(1),
|
|
711
|
+
connectionKey: z.string().min(1).optional(),
|
|
712
|
+
createdAt: z.number().int().positive(),
|
|
713
|
+
updatedAt: z.number().int().positive(),
|
|
714
|
+
refreshedAt: z.number().int().positive().optional(),
|
|
715
|
+
revokedAt: z.number().int().positive().optional()
|
|
716
|
+
});
|
|
717
|
+
function parsePluginDebugSessionSource(source) {
|
|
718
|
+
const parts = source.split(":");
|
|
719
|
+
if (parts.length !== 3 || parts[0] !== PLUGIN_DEBUG_SOURCE_KIND || parts[1] !== PLUGIN_DEBUG_SESSION_SOURCE_TMB_ID_KEY || !parts[2]) return null;
|
|
720
|
+
return { tmbId: parts[2] };
|
|
721
|
+
}
|
|
722
|
+
|
|
689
723
|
//#endregion
|
|
690
724
|
//#region src/debug/discover.ts
|
|
691
725
|
const IGNORED_DIRS = new Set([
|
|
@@ -997,7 +1031,11 @@ const RESOLVE_EXTENSIONS = [
|
|
|
997
1031
|
".cjs",
|
|
998
1032
|
".json"
|
|
999
1033
|
];
|
|
1034
|
+
const TRANSFORM_PROBE_SOURCE = "const __fastgptPluginTransformProbe__: number = 1;";
|
|
1000
1035
|
let hooksRegistered = false;
|
|
1036
|
+
let transformModeSupported;
|
|
1037
|
+
let cachedTypeScriptCompiler;
|
|
1038
|
+
const localRequire = createRequire(import.meta.url);
|
|
1001
1039
|
function ensureDebugImportHooks() {
|
|
1002
1040
|
if (hooksRegistered) return;
|
|
1003
1041
|
hooksRegistered = true;
|
|
@@ -1021,15 +1059,90 @@ function ensureDebugImportHooks() {
|
|
|
1021
1059
|
if (SOURCE_EXTENSIONS.includes(ext)) return {
|
|
1022
1060
|
format: "module",
|
|
1023
1061
|
shortCircuit: true,
|
|
1024
|
-
source:
|
|
1025
|
-
|
|
1026
|
-
|
|
1062
|
+
source: compileTypeScriptModuleSource(fs$1.readFileSync(fileURLToPath(parsed), "utf-8"), {
|
|
1063
|
+
filePath: fileURLToPath(parsed),
|
|
1064
|
+
workspaceRoot
|
|
1027
1065
|
})
|
|
1028
1066
|
};
|
|
1029
1067
|
return nextLoad(url, context);
|
|
1030
1068
|
}
|
|
1031
1069
|
});
|
|
1032
1070
|
}
|
|
1071
|
+
function compileTypeScriptModuleSource(sourceText, { filePath, workspaceRoot, stripTypeScriptTypesFn = stripTypeScriptTypes, typeScriptCompiler }) {
|
|
1072
|
+
if (supportsTransformMode(stripTypeScriptTypesFn)) try {
|
|
1073
|
+
return stripTypeScriptTypesFn(sourceText, {
|
|
1074
|
+
mode: "transform",
|
|
1075
|
+
sourceMap: false
|
|
1076
|
+
});
|
|
1077
|
+
} catch {}
|
|
1078
|
+
return transpileTypeScriptModuleSource(sourceText, {
|
|
1079
|
+
filePath,
|
|
1080
|
+
workspaceRoot,
|
|
1081
|
+
typeScriptCompiler
|
|
1082
|
+
});
|
|
1083
|
+
}
|
|
1084
|
+
function supportsTransformMode(stripTypeScriptTypesFn) {
|
|
1085
|
+
if (stripTypeScriptTypesFn === stripTypeScriptTypes) {
|
|
1086
|
+
if (transformModeSupported !== void 0) return transformModeSupported;
|
|
1087
|
+
transformModeSupported = canTransformTypeScript(stripTypeScriptTypesFn);
|
|
1088
|
+
return transformModeSupported;
|
|
1089
|
+
}
|
|
1090
|
+
return canTransformTypeScript(stripTypeScriptTypesFn);
|
|
1091
|
+
}
|
|
1092
|
+
function canTransformTypeScript(stripTypeScriptTypesFn) {
|
|
1093
|
+
try {
|
|
1094
|
+
stripTypeScriptTypesFn(TRANSFORM_PROBE_SOURCE, {
|
|
1095
|
+
mode: "transform",
|
|
1096
|
+
sourceMap: false
|
|
1097
|
+
});
|
|
1098
|
+
return true;
|
|
1099
|
+
} catch {
|
|
1100
|
+
return false;
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
function transpileTypeScriptModuleSource(sourceText, { filePath, workspaceRoot, typeScriptCompiler }) {
|
|
1104
|
+
const compiler = typeScriptCompiler ?? loadTypeScriptCompiler(filePath, workspaceRoot);
|
|
1105
|
+
const transpiled = compiler.transpileModule(sourceText, {
|
|
1106
|
+
fileName: filePath,
|
|
1107
|
+
reportDiagnostics: true,
|
|
1108
|
+
compilerOptions: {
|
|
1109
|
+
module: compiler.ModuleKind.ESNext,
|
|
1110
|
+
target: compiler.ScriptTarget.ES2022,
|
|
1111
|
+
moduleResolution: compiler.ModuleResolutionKind.Bundler,
|
|
1112
|
+
jsx: compiler.JsxEmit.ReactJSX,
|
|
1113
|
+
sourceMap: false,
|
|
1114
|
+
inlineSourceMap: false,
|
|
1115
|
+
inlineSources: false,
|
|
1116
|
+
isolatedModules: true,
|
|
1117
|
+
esModuleInterop: true,
|
|
1118
|
+
allowImportingTsExtensions: true,
|
|
1119
|
+
verbatimModuleSyntax: true
|
|
1120
|
+
}
|
|
1121
|
+
});
|
|
1122
|
+
const errors = transpiled.diagnostics?.filter((diagnostic) => diagnostic.category === compiler.DiagnosticCategory.Error) ?? [];
|
|
1123
|
+
if (errors.length > 0) {
|
|
1124
|
+
const formatted = errors.map((diagnostic) => formatDiagnosticMessage(compiler, diagnostic)).join("\n");
|
|
1125
|
+
throw new Error(`Failed to transpile TypeScript debug module: ${filePath}\n${formatted}`);
|
|
1126
|
+
}
|
|
1127
|
+
return transpiled.outputText;
|
|
1128
|
+
}
|
|
1129
|
+
function loadTypeScriptCompiler(filePath, workspaceRoot) {
|
|
1130
|
+
if (cachedTypeScriptCompiler) return cachedTypeScriptCompiler;
|
|
1131
|
+
const resolvePaths = [
|
|
1132
|
+
path.dirname(filePath),
|
|
1133
|
+
process.cwd(),
|
|
1134
|
+
workspaceRoot,
|
|
1135
|
+
path.dirname(fileURLToPath(import.meta.url))
|
|
1136
|
+
].filter((value) => Boolean(value));
|
|
1137
|
+
cachedTypeScriptCompiler = localRequire(localRequire.resolve("typescript", { paths: resolvePaths }));
|
|
1138
|
+
return cachedTypeScriptCompiler;
|
|
1139
|
+
}
|
|
1140
|
+
function formatDiagnosticMessage(compiler, diagnostic) {
|
|
1141
|
+
const message = compiler.flattenDiagnosticMessageText(diagnostic.messageText, "\n");
|
|
1142
|
+
if (!diagnostic.file || diagnostic.start === void 0) return message;
|
|
1143
|
+
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
|
1144
|
+
return `${line + 1}:${character + 1} ${message}`;
|
|
1145
|
+
}
|
|
1033
1146
|
function resolveSpecifier({ specifier, parentURL, workspaceRoot }) {
|
|
1034
1147
|
if (specifier.startsWith("node:")) return null;
|
|
1035
1148
|
if (specifier.startsWith("file:")) return toFileURL(resolveExistingPath(fileURLToPath(new URL(specifier))));
|
|
@@ -1191,9 +1304,188 @@ const InvokeMethodEnumSchema = z.enum([
|
|
|
1191
1304
|
]);
|
|
1192
1305
|
const InvokeMethodEnum = InvokeMethodEnumSchema.enum;
|
|
1193
1306
|
|
|
1307
|
+
//#endregion
|
|
1308
|
+
//#region ../../packages/domain/src/value-objects/error.vo.ts
|
|
1309
|
+
const DEFAULT_INTERNAL_REASON = {
|
|
1310
|
+
en: "Internal Server Error",
|
|
1311
|
+
"zh-CN": "服务器内部错误"
|
|
1312
|
+
};
|
|
1313
|
+
var RegisteredError = class extends Error {
|
|
1314
|
+
code;
|
|
1315
|
+
reason;
|
|
1316
|
+
httpStatus;
|
|
1317
|
+
telemetryKind;
|
|
1318
|
+
visibility;
|
|
1319
|
+
severity;
|
|
1320
|
+
data;
|
|
1321
|
+
constructor(definition, options = {}) {
|
|
1322
|
+
super(options.message ?? definition.message, { cause: normalizeErrorCause(options.cause) });
|
|
1323
|
+
this.name = "RegisteredError";
|
|
1324
|
+
this.code = definition.code;
|
|
1325
|
+
this.reason = options.reason ?? definition.reason;
|
|
1326
|
+
this.httpStatus = definition.httpStatus ?? 500;
|
|
1327
|
+
this.telemetryKind = definition.telemetryKind;
|
|
1328
|
+
this.visibility = definition.visibility ?? "public";
|
|
1329
|
+
this.severity = definition.severity ?? "expected";
|
|
1330
|
+
this.data = options.data;
|
|
1331
|
+
}
|
|
1332
|
+
};
|
|
1333
|
+
function createReasonError(reason, options = {}) {
|
|
1334
|
+
const cause = normalizeErrorCause(options.cause);
|
|
1335
|
+
const error = cause === void 0 ? new Error(reason.en) : new Error(reason.en, { cause });
|
|
1336
|
+
return Object.assign(error, { reason });
|
|
1337
|
+
}
|
|
1338
|
+
function normalizeToError(error, fallbackMessage = "Unknown error") {
|
|
1339
|
+
if (error instanceof Error) return error;
|
|
1340
|
+
if (typeof error === "string") return new Error(error);
|
|
1341
|
+
if (isI18nString(error)) return createReasonError(error);
|
|
1342
|
+
if (isResultFailureLike(error)) {
|
|
1343
|
+
const reason = isI18nString(error.reason) ? error.reason : void 0;
|
|
1344
|
+
const cause = normalizeToError(error.error, reason?.en ?? fallbackMessage);
|
|
1345
|
+
if (reason && isSameI18nString(reason, getErrorReason(cause))) return cause;
|
|
1346
|
+
return reason ? createReasonError(reason, { cause }) : new Error(fallbackMessage, { cause });
|
|
1347
|
+
}
|
|
1348
|
+
return new Error(getUnknownErrorMessage(error, fallbackMessage), { cause: error });
|
|
1349
|
+
}
|
|
1350
|
+
function getErrorReason(error, fallback) {
|
|
1351
|
+
if (error instanceof RegisteredError) return error.visibility === "internal" ? DEFAULT_INTERNAL_REASON : error.reason;
|
|
1352
|
+
if (isI18nString(error)) return error;
|
|
1353
|
+
const record = isRecord(error) ? error : void 0;
|
|
1354
|
+
if (record && isI18nString(record.reason)) return record.reason;
|
|
1355
|
+
if (record && isI18nString(record.error)) return record.error;
|
|
1356
|
+
if (fallback) return fallback;
|
|
1357
|
+
if (error instanceof Error) return {
|
|
1358
|
+
en: error.message,
|
|
1359
|
+
"zh-CN": error.message
|
|
1360
|
+
};
|
|
1361
|
+
if (typeof error === "string") return {
|
|
1362
|
+
en: error,
|
|
1363
|
+
"zh-CN": error
|
|
1364
|
+
};
|
|
1365
|
+
return DEFAULT_INTERNAL_REASON;
|
|
1366
|
+
}
|
|
1367
|
+
function serializeError(error, options) {
|
|
1368
|
+
return serializeErrorInner(error, {
|
|
1369
|
+
includeStack: options?.includeStack ?? false,
|
|
1370
|
+
depth: 0,
|
|
1371
|
+
seen: /* @__PURE__ */ new WeakSet()
|
|
1372
|
+
});
|
|
1373
|
+
}
|
|
1374
|
+
function normalizeErrorCause(cause) {
|
|
1375
|
+
if (cause === void 0 || cause instanceof Error) return cause;
|
|
1376
|
+
if (typeof cause === "string") return new Error(cause);
|
|
1377
|
+
if (isI18nString(cause)) return createReasonError(cause);
|
|
1378
|
+
if (isResultFailureLike(cause)) return normalizeToError(cause);
|
|
1379
|
+
return cause;
|
|
1380
|
+
}
|
|
1381
|
+
function serializeErrorInner(error, state) {
|
|
1382
|
+
if (state.depth > 5) return {
|
|
1383
|
+
name: "Error",
|
|
1384
|
+
message: "Error cause depth exceeded"
|
|
1385
|
+
};
|
|
1386
|
+
if (error instanceof RegisteredError) return {
|
|
1387
|
+
name: error.name,
|
|
1388
|
+
code: error.code,
|
|
1389
|
+
message: error.message,
|
|
1390
|
+
reason: error.reason,
|
|
1391
|
+
httpStatus: error.httpStatus,
|
|
1392
|
+
telemetryKind: error.telemetryKind,
|
|
1393
|
+
visibility: error.visibility,
|
|
1394
|
+
data: error.data,
|
|
1395
|
+
...state.includeStack && error.stack !== void 0 ? { stack: error.stack } : {},
|
|
1396
|
+
...error.cause !== void 0 ? { cause: serializeErrorInner(error.cause, nextSerializeState(state, error)) } : {}
|
|
1397
|
+
};
|
|
1398
|
+
if (error instanceof Error) {
|
|
1399
|
+
const reason = getI18nStringField(error, "reason");
|
|
1400
|
+
return {
|
|
1401
|
+
name: error.name,
|
|
1402
|
+
code: getStringField(error, "code"),
|
|
1403
|
+
message: error.message,
|
|
1404
|
+
...reason !== void 0 ? { reason } : {},
|
|
1405
|
+
data: getUnknownField(error, "data"),
|
|
1406
|
+
...state.includeStack && error.stack !== void 0 ? { stack: error.stack } : {},
|
|
1407
|
+
...error.cause !== void 0 ? { cause: serializeErrorInner(error.cause, nextSerializeState(state, error)) } : {}
|
|
1408
|
+
};
|
|
1409
|
+
}
|
|
1410
|
+
if (typeof error === "string") return {
|
|
1411
|
+
name: "Error",
|
|
1412
|
+
message: error
|
|
1413
|
+
};
|
|
1414
|
+
return {
|
|
1415
|
+
name: "Error",
|
|
1416
|
+
message: getUnknownErrorMessage(error, "Unknown error")
|
|
1417
|
+
};
|
|
1418
|
+
}
|
|
1419
|
+
function nextSerializeState(state, error) {
|
|
1420
|
+
if (state.seen.has(error)) return {
|
|
1421
|
+
...state,
|
|
1422
|
+
depth: 6
|
|
1423
|
+
};
|
|
1424
|
+
state.seen.add(error);
|
|
1425
|
+
return {
|
|
1426
|
+
...state,
|
|
1427
|
+
depth: state.depth + 1
|
|
1428
|
+
};
|
|
1429
|
+
}
|
|
1430
|
+
function getUnknownErrorMessage(error, fallback) {
|
|
1431
|
+
if (error === null || error === void 0) return fallback;
|
|
1432
|
+
if (isRecord(error)) {
|
|
1433
|
+
const message = error.message ?? error.msg;
|
|
1434
|
+
if (typeof message === "string" && message.length > 0) return message;
|
|
1435
|
+
}
|
|
1436
|
+
return String(error);
|
|
1437
|
+
}
|
|
1438
|
+
function getStringField(error, field) {
|
|
1439
|
+
const value = error[field];
|
|
1440
|
+
return typeof value === "string" ? value : void 0;
|
|
1441
|
+
}
|
|
1442
|
+
function getI18nStringField(error, field) {
|
|
1443
|
+
const value = error[field];
|
|
1444
|
+
return isI18nString(value) ? value : void 0;
|
|
1445
|
+
}
|
|
1446
|
+
function getUnknownField(error, field) {
|
|
1447
|
+
return error[field];
|
|
1448
|
+
}
|
|
1449
|
+
function isI18nString(value) {
|
|
1450
|
+
return isRecord(value) && typeof value.en === "string" && (value["zh-CN"] === void 0 || typeof value["zh-CN"] === "string") && (value["zh-Hant"] === void 0 || typeof value["zh-Hant"] === "string");
|
|
1451
|
+
}
|
|
1452
|
+
function isSameI18nString(left, right) {
|
|
1453
|
+
return left.en === right.en && left["zh-CN"] === right["zh-CN"] && left["zh-Hant"] === right["zh-Hant"];
|
|
1454
|
+
}
|
|
1455
|
+
function isRecord(value) {
|
|
1456
|
+
return Boolean(value && typeof value === "object");
|
|
1457
|
+
}
|
|
1458
|
+
function isResultFailureLike(value) {
|
|
1459
|
+
return isRecord(value) && "error" in value && ("reason" in value || isRecord(value.error));
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1194
1462
|
//#endregion
|
|
1195
1463
|
//#region ../../packages/domain/src/value-objects/result.vo.ts
|
|
1196
1464
|
const successResult = (data) => [data, null];
|
|
1465
|
+
function failureResult(reasonOrFailure, error) {
|
|
1466
|
+
if (isResultFailure(reasonOrFailure)) return [null, toResultFailure(reasonOrFailure.reason, reasonOrFailure.error, reasonOrFailure)];
|
|
1467
|
+
if (reasonOrFailure instanceof Error) return [null, toResultFailure(getErrorReason(reasonOrFailure), reasonOrFailure)];
|
|
1468
|
+
return [null, toResultFailure(reasonOrFailure, error === void 0 ? createReasonError(reasonOrFailure) : createLegacyFailureError(reasonOrFailure, error))];
|
|
1469
|
+
}
|
|
1470
|
+
function isResultFailure(value) {
|
|
1471
|
+
return Boolean(value && typeof value === "object" && "reason" in value && "error" in value);
|
|
1472
|
+
}
|
|
1473
|
+
function createLegacyFailureError(reason, cause) {
|
|
1474
|
+
return createReasonError(reason, { cause: normalizeToError(cause, reason.en) });
|
|
1475
|
+
}
|
|
1476
|
+
function toResultFailure(reason, error, existing) {
|
|
1477
|
+
const serialized = serializeError(error);
|
|
1478
|
+
const code = existing?.code ?? serialized.code;
|
|
1479
|
+
const message = existing?.message ?? serialized.message;
|
|
1480
|
+
const data = existing && "data" in existing ? existing.data : serialized.data;
|
|
1481
|
+
return {
|
|
1482
|
+
reason,
|
|
1483
|
+
error,
|
|
1484
|
+
...code !== void 0 ? { code } : {},
|
|
1485
|
+
...message !== void 0 ? { message } : {},
|
|
1486
|
+
...data !== void 0 ? { data } : {}
|
|
1487
|
+
};
|
|
1488
|
+
}
|
|
1197
1489
|
|
|
1198
1490
|
//#endregion
|
|
1199
1491
|
//#region ../../packages/domain/src/value-objects/stream.vo.ts
|
|
@@ -1690,7 +1982,7 @@ function createIncomingStream({ source, streamName, streamId, traceId, meta }) {
|
|
|
1690
1982
|
};
|
|
1691
1983
|
}
|
|
1692
1984
|
function toStreamData(source) {
|
|
1693
|
-
if (isStreamDataLike$
|
|
1985
|
+
if (isStreamDataLike$2(source)) return source;
|
|
1694
1986
|
const output = StreamData.create();
|
|
1695
1987
|
(async () => {
|
|
1696
1988
|
try {
|
|
@@ -1702,7 +1994,7 @@ function toStreamData(source) {
|
|
|
1702
1994
|
})();
|
|
1703
1995
|
return output;
|
|
1704
1996
|
}
|
|
1705
|
-
function isStreamDataLike$
|
|
1997
|
+
function isStreamDataLike$2(source) {
|
|
1706
1998
|
return source instanceof StreamData || typeof source === "object" && source !== null && typeof source.values === "function" && typeof source.consume === "function";
|
|
1707
1999
|
}
|
|
1708
2000
|
|
|
@@ -1737,7 +2029,7 @@ async function loadDebugSession({ entryDir, uploadDir }) {
|
|
|
1737
2029
|
else process.env.RUNTIME_MODE = previousRuntimeMode;
|
|
1738
2030
|
}
|
|
1739
2031
|
}
|
|
1740
|
-
async function runDebugTool({ runtime, snapshot, toolId, input, secrets, systemVar }) {
|
|
2032
|
+
async function runDebugTool({ runtime, snapshot, toolId, input, secrets, systemVar, traceId }) {
|
|
1741
2033
|
const targetTool = pickTargetTool(snapshot, toolId);
|
|
1742
2034
|
const mergedSystemVar = createDebugSystemVar(snapshot, targetTool.id, systemVar);
|
|
1743
2035
|
const response = await runtime.invokePlugin("run", {
|
|
@@ -1745,7 +2037,7 @@ async function runDebugTool({ runtime, snapshot, toolId, input, secrets, systemV
|
|
|
1745
2037
|
systemVar: mergedSystemVar,
|
|
1746
2038
|
...snapshot.isToolSet ? { childId: targetTool.id } : {},
|
|
1747
2039
|
...secrets ? { secrets } : {}
|
|
1748
|
-
}, { traceId: randomUUID() });
|
|
2040
|
+
}, { traceId: traceId ?? randomUUID() });
|
|
1749
2041
|
if (!response.output) throw new Error("调试运行未返回输出流。");
|
|
1750
2042
|
const streamMessages = [];
|
|
1751
2043
|
let finalResponse;
|
|
@@ -1805,7 +2097,7 @@ function createDebugSnapshot(tool, location) {
|
|
|
1805
2097
|
author: getOptionalString(userManifest.author),
|
|
1806
2098
|
tags: toStringArray(userManifest.tags),
|
|
1807
2099
|
permissions: toStringArray(userManifest.permission),
|
|
1808
|
-
secretSchema: ensurePlainObject(secretSchema),
|
|
2100
|
+
secretSchema: ensurePlainObject$1(secretSchema),
|
|
1809
2101
|
isToolSet: children.length > 0,
|
|
1810
2102
|
tools
|
|
1811
2103
|
};
|
|
@@ -1818,8 +2110,8 @@ function createSingleToolSnapshot(tool, userManifest) {
|
|
|
1818
2110
|
name: pickLocalizedText(userManifest.name),
|
|
1819
2111
|
description: pickLocalizedText(userManifest.description),
|
|
1820
2112
|
toolDescription: pickToolDescription(getOptionalString(userManifest.toolDescription), userManifest.description),
|
|
1821
|
-
inputSchema: ensurePlainObject(z.toJSONSchema(handler.inputSchema)),
|
|
1822
|
-
outputSchema: ensurePlainObject(z.toJSONSchema(handler.outputSchema))
|
|
2113
|
+
inputSchema: ensurePlainObject$1(z.toJSONSchema(handler.inputSchema)),
|
|
2114
|
+
outputSchema: ensurePlainObject$1(z.toJSONSchema(handler.outputSchema))
|
|
1823
2115
|
};
|
|
1824
2116
|
}
|
|
1825
2117
|
function createChildToolSnapshot(tool, child) {
|
|
@@ -1830,8 +2122,8 @@ function createChildToolSnapshot(tool, child) {
|
|
|
1830
2122
|
name: pickLocalizedText(child.name),
|
|
1831
2123
|
description: pickLocalizedText(child.description),
|
|
1832
2124
|
toolDescription: pickToolDescription(child.toolDescription, child.description),
|
|
1833
|
-
inputSchema: ensurePlainObject(z.toJSONSchema(handler.inputSchema)),
|
|
1834
|
-
outputSchema: ensurePlainObject(z.toJSONSchema(handler.outputSchema))
|
|
2125
|
+
inputSchema: ensurePlainObject$1(z.toJSONSchema(handler.inputSchema)),
|
|
2126
|
+
outputSchema: ensurePlainObject$1(z.toJSONSchema(handler.outputSchema))
|
|
1835
2127
|
};
|
|
1836
2128
|
}
|
|
1837
2129
|
function pickTargetTool(snapshot, toolId) {
|
|
@@ -1843,10 +2135,10 @@ function pickTargetTool(snapshot, toolId) {
|
|
|
1843
2135
|
}
|
|
1844
2136
|
function createVirtualHostHandler(uploadDir) {
|
|
1845
2137
|
return async ({ method, args, input }) => {
|
|
1846
|
-
const invokeArgs = ensurePlainObject(args);
|
|
2138
|
+
const invokeArgs = ensurePlainObject$1(args);
|
|
1847
2139
|
switch (method) {
|
|
1848
2140
|
case InvokeMethodEnum.uploadFile: {
|
|
1849
|
-
const buffer = await readSourceToBuffer(input);
|
|
2141
|
+
const buffer = await readSourceToBuffer$1(input);
|
|
1850
2142
|
const fileName = sanitizeFileName(typeof invokeArgs.fileName === "string" && invokeArgs.fileName.trim().length > 0 ? invokeArgs.fileName : "debug-upload.bin");
|
|
1851
2143
|
const contentType = typeof invokeArgs.contentType === "string" && invokeArgs.contentType.trim().length > 0 ? invokeArgs.contentType : "application/octet-stream";
|
|
1852
2144
|
const saveDir = path.resolve(uploadDir);
|
|
@@ -1866,17 +2158,17 @@ function createVirtualHostHandler(uploadDir) {
|
|
|
1866
2158
|
}
|
|
1867
2159
|
};
|
|
1868
2160
|
}
|
|
1869
|
-
async function readSourceToBuffer(source) {
|
|
2161
|
+
async function readSourceToBuffer$1(source) {
|
|
1870
2162
|
if (!source) return Buffer.alloc(0);
|
|
1871
2163
|
const chunks = [];
|
|
1872
|
-
const iterable = isStreamDataLike(source) ? source.values() : source;
|
|
1873
|
-
for await (const chunk of iterable) chunks.push(toBuffer(chunk));
|
|
2164
|
+
const iterable = isStreamDataLike$1(source) ? source.values() : source;
|
|
2165
|
+
for await (const chunk of iterable) chunks.push(toBuffer$1(chunk));
|
|
1874
2166
|
return Buffer.concat(chunks);
|
|
1875
2167
|
}
|
|
1876
|
-
function isStreamDataLike(source) {
|
|
2168
|
+
function isStreamDataLike$1(source) {
|
|
1877
2169
|
return source instanceof StreamData || typeof source === "object" && source !== null && typeof source.values === "function" && typeof source.consume === "function";
|
|
1878
2170
|
}
|
|
1879
|
-
function toBuffer(value) {
|
|
2171
|
+
function toBuffer$1(value) {
|
|
1880
2172
|
if (Buffer.isBuffer(value)) return value;
|
|
1881
2173
|
if (value instanceof Uint8Array) return Buffer.from(value);
|
|
1882
2174
|
if (typeof value === "string") return Buffer.from(value);
|
|
@@ -1914,7 +2206,7 @@ function toStringArray(value) {
|
|
|
1914
2206
|
const items = value.filter((item) => typeof item === "string");
|
|
1915
2207
|
return items.length > 0 ? items : void 0;
|
|
1916
2208
|
}
|
|
1917
|
-
function ensurePlainObject(value) {
|
|
2209
|
+
function ensurePlainObject$1(value) {
|
|
1918
2210
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
1919
2211
|
}
|
|
1920
2212
|
function sanitizeFileName(fileName) {
|
|
@@ -1945,6 +2237,7 @@ async function assertPathExists(targetPath, message) {
|
|
|
1945
2237
|
|
|
1946
2238
|
//#endregion
|
|
1947
2239
|
//#region src/debug/gateway.ts
|
|
2240
|
+
const GATEWAY_DUPLICATE_CONNECTION_CODE = "connection_gateway.session_already_bound";
|
|
1948
2241
|
async function connectDebugGateway({ targets, options, onLog }) {
|
|
1949
2242
|
if (targets.length === 0) throw new Error("Gateway debug targets cannot be empty");
|
|
1950
2243
|
if (options.reconnect) return connectReconnectingDebugGateway({
|
|
@@ -1963,19 +2256,32 @@ async function connectReconnectingDebugGateway({ targets, options, onLog }) {
|
|
|
1963
2256
|
let current = null;
|
|
1964
2257
|
let currentSession = null;
|
|
1965
2258
|
let latestTargets = targets;
|
|
2259
|
+
let hasAttemptedConnection = false;
|
|
2260
|
+
let currentOptions = options;
|
|
2261
|
+
const resolveReconnectOptions = options.resolveReconnectOptions;
|
|
1966
2262
|
const intervalMs = Math.max(100, options.reconnectIntervalMs ?? 2e3);
|
|
1967
2263
|
const closedPromise = (async () => {
|
|
1968
2264
|
while (!closed) {
|
|
1969
2265
|
try {
|
|
2266
|
+
const attemptOptions = hasAttemptedConnection && resolveReconnectOptions ? await resolveReconnectOptions() : currentOptions;
|
|
2267
|
+
hasAttemptedConnection = true;
|
|
2268
|
+
currentOptions = {
|
|
2269
|
+
...attemptOptions,
|
|
2270
|
+
resolveReconnectOptions
|
|
2271
|
+
};
|
|
1970
2272
|
current = await connectSingleDebugGateway({
|
|
1971
2273
|
targets: latestTargets,
|
|
1972
|
-
options,
|
|
2274
|
+
options: currentOptions,
|
|
1973
2275
|
onLog
|
|
1974
2276
|
});
|
|
1975
2277
|
currentSession = current.session;
|
|
1976
2278
|
await current.closed;
|
|
1977
2279
|
} catch (error) {
|
|
1978
2280
|
if (closed) return;
|
|
2281
|
+
if (isDuplicateConnectionError(error)) {
|
|
2282
|
+
closed = true;
|
|
2283
|
+
throw error;
|
|
2284
|
+
}
|
|
1979
2285
|
onLog?.(`Connection Gateway 调试通道断开: ${formatErrorMessage(error)}`);
|
|
1980
2286
|
} finally {
|
|
1981
2287
|
current = null;
|
|
@@ -2030,7 +2336,7 @@ async function connectSingleDebugGateway({ targets, options, onLog }) {
|
|
|
2030
2336
|
}
|
|
2031
2337
|
if (message.type === "heartbeat") return;
|
|
2032
2338
|
if (message.type === "error") {
|
|
2033
|
-
const error =
|
|
2339
|
+
const error = createGatewayError(message.code, message.message);
|
|
2034
2340
|
if (!session) boundReject(error);
|
|
2035
2341
|
onLog?.(`Connection Gateway 错误: ${message.code} ${message.message}`);
|
|
2036
2342
|
return;
|
|
@@ -2088,6 +2394,7 @@ async function handleGatewayEnvelope({ socket, session, targetsByPluginId, envel
|
|
|
2088
2394
|
if (!pluginId) throw new Error("Gateway debug request missing pluginId");
|
|
2089
2395
|
const target = targetsByPluginId.get(pluginId);
|
|
2090
2396
|
if (!target) throw new Error(`Gateway debug target not found: ${source} ${pluginId}`);
|
|
2397
|
+
const traceId = envelope.traceId ?? requiredRequestId(envelope);
|
|
2091
2398
|
onLog?.(`收到远程调试请求: ${source} ${pluginId} ${envelope.requestId ?? "-"}`);
|
|
2092
2399
|
await sendEnvelope(socket, {
|
|
2093
2400
|
protocol: "connection-gateway.v1",
|
|
@@ -2101,15 +2408,21 @@ async function handleGatewayEnvelope({ socket, session, targetsByPluginId, envel
|
|
|
2101
2408
|
createdAt: Date.now(),
|
|
2102
2409
|
payload: { kind: "plugin-debug.accepted" }
|
|
2103
2410
|
});
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2411
|
+
target.invokeBridge?.bind(traceId, { invokeToken: request.payload.systemVar.invokeToken });
|
|
2412
|
+
try {
|
|
2413
|
+
const result = await runDebugTool({
|
|
2414
|
+
runtime: target.runtime,
|
|
2415
|
+
snapshot: target.snapshot,
|
|
2416
|
+
toolId: request.payload.childId,
|
|
2417
|
+
input: request.payload.input,
|
|
2418
|
+
secrets: request.payload.secrets,
|
|
2419
|
+
systemVar: request.payload.systemVar,
|
|
2420
|
+
traceId
|
|
2421
|
+
});
|
|
2422
|
+
for (const message of result.streamMessages) await sendStreamChunk(socket, session, envelope, message);
|
|
2423
|
+
} finally {
|
|
2424
|
+
target.invokeBridge?.release(traceId);
|
|
2425
|
+
}
|
|
2113
2426
|
await sendEnvelope(socket, {
|
|
2114
2427
|
protocol: "connection-gateway.v1",
|
|
2115
2428
|
sessionId: session.id,
|
|
@@ -2212,11 +2525,244 @@ function delay(ms) {
|
|
|
2212
2525
|
function formatErrorMessage(error) {
|
|
2213
2526
|
return error instanceof Error ? error.message : String(error);
|
|
2214
2527
|
}
|
|
2528
|
+
function createGatewayError(code, message) {
|
|
2529
|
+
const error = new Error(message);
|
|
2530
|
+
Object.assign(error, { code });
|
|
2531
|
+
return error;
|
|
2532
|
+
}
|
|
2533
|
+
function isDuplicateConnectionError(error) {
|
|
2534
|
+
return error instanceof Error && ("code" in error ? error.code === GATEWAY_DUPLICATE_CONNECTION_CODE : false);
|
|
2535
|
+
}
|
|
2215
2536
|
function parseWsServerMessage(data) {
|
|
2216
2537
|
const text = typeof data === "string" ? data : data instanceof ArrayBuffer ? Buffer.from(data).toString("utf8") : ArrayBuffer.isView(data) ? Buffer.from(data.buffer, data.byteOffset, data.byteLength).toString("utf8") : String(data);
|
|
2217
2538
|
return ConnectionGatewayWsServerMessageSchema.parse(JSON.parse(text));
|
|
2218
2539
|
}
|
|
2219
2540
|
|
|
2541
|
+
//#endregion
|
|
2542
|
+
//#region ../../packages/infrastructure/src/plugin/invoke/invoke.impl.ts
|
|
2543
|
+
var InvokeManager = class {
|
|
2544
|
+
constructor(deps) {
|
|
2545
|
+
this.deps = deps;
|
|
2546
|
+
}
|
|
2547
|
+
async getWecomCorpToken() {
|
|
2548
|
+
const [result, responseErr] = await this.requestFastGPT({
|
|
2549
|
+
path: "/api/proApi/support/wecom/getCorpToken",
|
|
2550
|
+
init: { method: "GET" },
|
|
2551
|
+
failureReason: {
|
|
2552
|
+
en: "Get wecom corp token failed",
|
|
2553
|
+
"zh-CN": "获取企业微信企业令牌失败"
|
|
2554
|
+
},
|
|
2555
|
+
invalidJsonReason: {
|
|
2556
|
+
en: "Invalid wecom corp token output",
|
|
2557
|
+
"zh-CN": "获取企业微信企业令牌返回数据格式错误"
|
|
2558
|
+
}
|
|
2559
|
+
});
|
|
2560
|
+
if (responseErr) return failureResult(responseErr);
|
|
2561
|
+
return successResult(result);
|
|
2562
|
+
}
|
|
2563
|
+
async userInfo() {
|
|
2564
|
+
const [result, responseErr] = await this.requestFastGPT({
|
|
2565
|
+
path: "/api/invoke/userInfo",
|
|
2566
|
+
init: { method: "GET" },
|
|
2567
|
+
failureReason: {
|
|
2568
|
+
en: "Invoke user info failed",
|
|
2569
|
+
"zh-CN": "反向调用用户信息失败"
|
|
2570
|
+
},
|
|
2571
|
+
invalidJsonReason: {
|
|
2572
|
+
en: "Invalid invoke user info output",
|
|
2573
|
+
"zh-CN": "反向调用用户信息返回数据格式错误"
|
|
2574
|
+
}
|
|
2575
|
+
});
|
|
2576
|
+
if (responseErr) return failureResult(responseErr);
|
|
2577
|
+
try {
|
|
2578
|
+
return successResult(InvokeUserInfoOutputSchema.parse(result));
|
|
2579
|
+
} catch (error) {
|
|
2580
|
+
return failureResult({
|
|
2581
|
+
en: "Invalid invoke user info output",
|
|
2582
|
+
"zh-CN": "反向调用用户信息返回数据格式错误"
|
|
2583
|
+
}, error);
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
async uploadFile(input) {
|
|
2587
|
+
let request;
|
|
2588
|
+
try {
|
|
2589
|
+
request = await this.buildUploadFileRequest(input);
|
|
2590
|
+
} catch (error) {
|
|
2591
|
+
return failureResult({
|
|
2592
|
+
en: "Invoke upload file failed",
|
|
2593
|
+
"zh-CN": "反向调用上传文件失败"
|
|
2594
|
+
}, error);
|
|
2595
|
+
}
|
|
2596
|
+
const [result, responseErr] = await this.requestFastGPT({
|
|
2597
|
+
path: "/api/invoke/fileUpload",
|
|
2598
|
+
init: {
|
|
2599
|
+
method: "POST",
|
|
2600
|
+
body: request.formData
|
|
2601
|
+
},
|
|
2602
|
+
failureReason: {
|
|
2603
|
+
en: "Invoke upload file failed",
|
|
2604
|
+
"zh-CN": "反向调用上传文件失败"
|
|
2605
|
+
},
|
|
2606
|
+
invalidJsonReason: {
|
|
2607
|
+
en: "Invalid invoke upload file output",
|
|
2608
|
+
"zh-CN": "反向调用上传文件返回数据格式错误"
|
|
2609
|
+
}
|
|
2610
|
+
});
|
|
2611
|
+
if (responseErr) return failureResult(responseErr);
|
|
2612
|
+
try {
|
|
2613
|
+
return successResult(InvokeUploadFileOutputSchema.parse({ accessURL: result.url }));
|
|
2614
|
+
} catch (error) {
|
|
2615
|
+
return failureResult({
|
|
2616
|
+
en: "Invalid invoke upload file output",
|
|
2617
|
+
"zh-CN": "反向调用上传文件返回数据格式错误"
|
|
2618
|
+
}, error);
|
|
2619
|
+
}
|
|
2620
|
+
}
|
|
2621
|
+
buildUrl(path) {
|
|
2622
|
+
return new URL(path, this.deps.fastgptBaseUrl).toString();
|
|
2623
|
+
}
|
|
2624
|
+
async buildUploadFileRequest(input) {
|
|
2625
|
+
const formData = new FormData();
|
|
2626
|
+
const fileBuffer = await this.toBuffer(input.file);
|
|
2627
|
+
const fileName = input.fileName ?? randomUUID();
|
|
2628
|
+
const contentType = input.contentType ?? "application/octet-stream";
|
|
2629
|
+
const blobPart = new Uint8Array(fileBuffer.byteLength);
|
|
2630
|
+
blobPart.set(fileBuffer);
|
|
2631
|
+
formData.append("file", new Blob([blobPart], { type: contentType }), fileName);
|
|
2632
|
+
if (input.fileName) formData.append("fileName", input.fileName);
|
|
2633
|
+
if (input.contentType) formData.append("contentType", input.contentType);
|
|
2634
|
+
return {
|
|
2635
|
+
formData,
|
|
2636
|
+
meta: {
|
|
2637
|
+
fileName,
|
|
2638
|
+
contentType
|
|
2639
|
+
}
|
|
2640
|
+
};
|
|
2641
|
+
}
|
|
2642
|
+
async toBuffer(file) {
|
|
2643
|
+
if (Buffer.isBuffer(file)) return file;
|
|
2644
|
+
if (file instanceof Readable$1) {
|
|
2645
|
+
const chunks = [];
|
|
2646
|
+
for await (const chunk of file) chunks.push(this.toBufferChunk(chunk));
|
|
2647
|
+
return Buffer.concat(chunks);
|
|
2648
|
+
}
|
|
2649
|
+
return Buffer.from(file);
|
|
2650
|
+
}
|
|
2651
|
+
toBufferChunk(chunk) {
|
|
2652
|
+
if (Buffer.isBuffer(chunk)) return chunk;
|
|
2653
|
+
if (chunk instanceof Uint8Array) return Buffer.from(chunk);
|
|
2654
|
+
if (chunk instanceof ArrayBuffer) return Buffer.from(chunk);
|
|
2655
|
+
if (ArrayBuffer.isView(chunk)) return Buffer.from(chunk.buffer, chunk.byteOffset, chunk.byteLength);
|
|
2656
|
+
if (typeof chunk === "string") return Buffer.from(chunk);
|
|
2657
|
+
if (typeof chunk === "number") return Buffer.from([chunk]);
|
|
2658
|
+
if (this.isSerializedBufferChunk(chunk)) return Buffer.from(chunk.data);
|
|
2659
|
+
throw new TypeError(`Unsupported upload file stream chunk type: ${Object.prototype.toString.call(chunk)}`);
|
|
2660
|
+
}
|
|
2661
|
+
isSerializedBufferChunk(value) {
|
|
2662
|
+
return this.isRecord(value) && value.type === "Buffer" && Array.isArray(value.data) && value.data.every((item) => Number.isInteger(item) && Number.isSafeInteger(item) && item >= 0 && item <= 255);
|
|
2663
|
+
}
|
|
2664
|
+
async requestFastGPT({ path, init, failureReason, invalidJsonReason }) {
|
|
2665
|
+
const headers = new Headers(init?.headers);
|
|
2666
|
+
headers.set("Authorization", `Bearer ${this.deps.token}`);
|
|
2667
|
+
let response;
|
|
2668
|
+
try {
|
|
2669
|
+
response = await fetch(this.buildUrl(path), {
|
|
2670
|
+
...init,
|
|
2671
|
+
headers
|
|
2672
|
+
});
|
|
2673
|
+
} catch (error) {
|
|
2674
|
+
return failureResult(failureReason, error);
|
|
2675
|
+
}
|
|
2676
|
+
if (!response.ok) return failureResult(failureReason, await this.readErrorResponse(response));
|
|
2677
|
+
let payload;
|
|
2678
|
+
try {
|
|
2679
|
+
payload = await response.json();
|
|
2680
|
+
} catch (error) {
|
|
2681
|
+
return failureResult(invalidJsonReason, error);
|
|
2682
|
+
}
|
|
2683
|
+
return this.parseResponse(payload, failureReason);
|
|
2684
|
+
}
|
|
2685
|
+
parseResponse(payload, fallbackReason) {
|
|
2686
|
+
if (!this.isRecord(payload)) return successResult(payload);
|
|
2687
|
+
if (payload.success === false) return failureResult({
|
|
2688
|
+
en: this.getResponseMessage(payload) ?? fallbackReason.en,
|
|
2689
|
+
"zh-CN": this.getResponseMessage(payload) ?? fallbackReason["zh-CN"]
|
|
2690
|
+
}, payload);
|
|
2691
|
+
if (typeof payload.code === "number" && payload.code >= 400) return failureResult({
|
|
2692
|
+
en: this.getResponseMessage(payload) ?? fallbackReason.en,
|
|
2693
|
+
"zh-CN": this.getResponseMessage(payload) ?? fallbackReason["zh-CN"]
|
|
2694
|
+
}, payload);
|
|
2695
|
+
return successResult("data" in payload ? payload.data : payload);
|
|
2696
|
+
}
|
|
2697
|
+
async readErrorResponse(response) {
|
|
2698
|
+
return {
|
|
2699
|
+
status: response.status,
|
|
2700
|
+
statusText: response.statusText,
|
|
2701
|
+
body: (await response.text().catch(() => "")).slice(0, 1e3)
|
|
2702
|
+
};
|
|
2703
|
+
}
|
|
2704
|
+
getResponseMessage(payload) {
|
|
2705
|
+
return typeof payload.message === "string" ? payload.message : void 0;
|
|
2706
|
+
}
|
|
2707
|
+
isRecord(value) {
|
|
2708
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
2709
|
+
}
|
|
2710
|
+
};
|
|
2711
|
+
|
|
2712
|
+
//#endregion
|
|
2713
|
+
//#region src/debug/remote-invoke.ts
|
|
2714
|
+
var RemoteDebugInvokeBridge = class {
|
|
2715
|
+
sessions = /* @__PURE__ */ new Map();
|
|
2716
|
+
constructor(fastgptBaseUrl) {
|
|
2717
|
+
this.fastgptBaseUrl = fastgptBaseUrl;
|
|
2718
|
+
}
|
|
2719
|
+
attach(runtime) {
|
|
2720
|
+
runtime.setHostRequestHandler((request) => this.handleHostRequest(request));
|
|
2721
|
+
}
|
|
2722
|
+
bind(traceId, input) {
|
|
2723
|
+
this.sessions.set(traceId, { invokeToken: input.invokeToken });
|
|
2724
|
+
}
|
|
2725
|
+
release(traceId) {
|
|
2726
|
+
this.sessions.delete(traceId);
|
|
2727
|
+
}
|
|
2728
|
+
async handleHostRequest({ method, args, input, traceId }) {
|
|
2729
|
+
if (!traceId) throw new Error("远程调试反向调用缺少 traceId。");
|
|
2730
|
+
const session = this.sessions.get(traceId);
|
|
2731
|
+
if (!session) throw new Error("远程调试反向调用会话不存在或已结束。");
|
|
2732
|
+
const invoke = new InvokeManager({
|
|
2733
|
+
token: session.invokeToken,
|
|
2734
|
+
fastgptBaseUrl: this.fastgptBaseUrl
|
|
2735
|
+
});
|
|
2736
|
+
switch (method) {
|
|
2737
|
+
case InvokeMethodEnum.uploadFile: return invoke.uploadFile({
|
|
2738
|
+
...ensurePlainObject(args),
|
|
2739
|
+
file: input ? await readSourceToBuffer(input) : Buffer.alloc(0)
|
|
2740
|
+
});
|
|
2741
|
+
case InvokeMethodEnum.userInfo: return invoke.userInfo();
|
|
2742
|
+
case InvokeMethodEnum.wecomCorpToken: return invoke.getWecomCorpToken();
|
|
2743
|
+
default: throw new Error(`远程调试宿主暂不支持反向调用: ${String(method)}`);
|
|
2744
|
+
}
|
|
2745
|
+
}
|
|
2746
|
+
};
|
|
2747
|
+
function ensurePlainObject(value) {
|
|
2748
|
+
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
2749
|
+
}
|
|
2750
|
+
async function readSourceToBuffer(source) {
|
|
2751
|
+
const chunks = [];
|
|
2752
|
+
const iterable = isStreamDataLike(source) ? source.values() : source;
|
|
2753
|
+
for await (const chunk of iterable) chunks.push(toBuffer(chunk));
|
|
2754
|
+
return Buffer.concat(chunks);
|
|
2755
|
+
}
|
|
2756
|
+
function isStreamDataLike(source) {
|
|
2757
|
+
return source instanceof StreamData || typeof source === "object" && source !== null && typeof source.values === "function" && typeof source.consume === "function";
|
|
2758
|
+
}
|
|
2759
|
+
function toBuffer(value) {
|
|
2760
|
+
if (Buffer.isBuffer(value)) return value;
|
|
2761
|
+
if (value instanceof Uint8Array) return Buffer.from(value);
|
|
2762
|
+
if (typeof value === "string") return Buffer.from(value);
|
|
2763
|
+
return Buffer.from(JSON.stringify(value));
|
|
2764
|
+
}
|
|
2765
|
+
|
|
2220
2766
|
//#endregion
|
|
2221
2767
|
//#region src/debug/remote-session.ts
|
|
2222
2768
|
async function runRemoteDebugSession({ entriesInput, options, commandName, migrationHint }) {
|
|
@@ -2247,6 +2793,7 @@ async function runRemoteDebugSessionOnce({ entriesInput, options, commandName })
|
|
|
2247
2793
|
commandName,
|
|
2248
2794
|
targets
|
|
2249
2795
|
});
|
|
2796
|
+
attachRemoteInvokeBridges(targets, gatewayOptions.fastgptBaseUrl);
|
|
2250
2797
|
const reporter = createRemoteDebugReporter({
|
|
2251
2798
|
commandName,
|
|
2252
2799
|
options,
|
|
@@ -2284,6 +2831,7 @@ async function runWatchRemoteDebugSession({ entriesInput, options, commandName }
|
|
|
2284
2831
|
commandName,
|
|
2285
2832
|
targets: initialTargets
|
|
2286
2833
|
});
|
|
2834
|
+
attachRemoteInvokeBridges(initialTargets, gatewayOptions.fastgptBaseUrl);
|
|
2287
2835
|
const reporter = createRemoteDebugReporter({
|
|
2288
2836
|
commandName,
|
|
2289
2837
|
options,
|
|
@@ -2305,6 +2853,7 @@ async function runWatchRemoteDebugSession({ entriesInput, options, commandName }
|
|
|
2305
2853
|
reloadPending = false;
|
|
2306
2854
|
try {
|
|
2307
2855
|
const nextTargets = await loadTargets(entries, options);
|
|
2856
|
+
attachRemoteInvokeBridges(nextTargets, gatewayOptions.fastgptBaseUrl);
|
|
2308
2857
|
gateway?.updateTargets(nextTargets);
|
|
2309
2858
|
reporter.log(`检测到插件文件变化,已热更新 ${nextTargets.length} 个本地插件。`);
|
|
2310
2859
|
} catch (error) {
|
|
@@ -2369,6 +2918,13 @@ async function loadTargets(entries, options) {
|
|
|
2369
2918
|
if (duplicatePluginIds.length > 0) throw new Error(`gateway pluginId 重复: ${duplicatePluginIds.join(", ")}`);
|
|
2370
2919
|
return targets;
|
|
2371
2920
|
}
|
|
2921
|
+
function attachRemoteInvokeBridges(targets, fastgptBaseUrl) {
|
|
2922
|
+
targets.forEach((target) => {
|
|
2923
|
+
const invokeBridge = new RemoteDebugInvokeBridge(fastgptBaseUrl);
|
|
2924
|
+
invokeBridge.attach(target.runtime);
|
|
2925
|
+
target.invokeBridge = invokeBridge;
|
|
2926
|
+
});
|
|
2927
|
+
}
|
|
2372
2928
|
function watchDebugEntries(entries, onChange) {
|
|
2373
2929
|
const watchers = entries.map((entry) => fsWatch(entry, {
|
|
2374
2930
|
recursive: true,
|
|
@@ -2428,12 +2984,12 @@ async function promptConnectLink({ commandName, targets, defaultValue, errorMess
|
|
|
2428
2984
|
"",
|
|
2429
2985
|
...errorMessage ? [`Last error ${errorMessage}`, ""] : [],
|
|
2430
2986
|
"Paste the FastGPT connection key or connect link to start the WSS debug session.",
|
|
2987
|
+
...defaultValue ? ["Press Enter to reuse the current value, or type a new one to replace it.", ""] : [],
|
|
2431
2988
|
""
|
|
2432
2989
|
].join("\n"));
|
|
2433
2990
|
return (await input({
|
|
2434
2991
|
message: "FastGPT connection key",
|
|
2435
2992
|
default: defaultValue,
|
|
2436
|
-
prefill: defaultValue ? "editable" : void 0,
|
|
2437
2993
|
validate(value) {
|
|
2438
2994
|
return value.trim().length > 0 || "请输入 FastGPT connection key";
|
|
2439
2995
|
}
|
|
@@ -2778,9 +3334,11 @@ async function resolveConnectGatewayOptions(options) {
|
|
|
2778
3334
|
connectToken: info.connectToken,
|
|
2779
3335
|
userId: info.tmbId,
|
|
2780
3336
|
source: info.source,
|
|
3337
|
+
fastgptBaseUrl: info.fastgptBaseUrl,
|
|
2781
3338
|
tokenTtlMs: Math.max(1, info.expiresAt - Date.now()),
|
|
2782
3339
|
reconnect: options.noReconnect ? false : options.reconnect ?? true,
|
|
2783
|
-
reconnectIntervalMs: toPositiveInt(options.reconnectIntervalMs ?? process.env.CONNECTION_GATEWAY_RECONNECT_INTERVAL_MS ?? "2000", "reconnect-interval-ms")
|
|
3340
|
+
reconnectIntervalMs: toPositiveInt(options.reconnectIntervalMs ?? process.env.CONNECTION_GATEWAY_RECONNECT_INTERVAL_MS ?? "2000", "reconnect-interval-ms"),
|
|
3341
|
+
resolveReconnectOptions: () => resolveConnectGatewayOptions(options)
|
|
2784
3342
|
};
|
|
2785
3343
|
}
|
|
2786
3344
|
function resolveUploadDir({ entryDir, index, total, uploadDir }) {
|
|
@@ -2793,10 +3351,12 @@ const ConnectInfoSchema = z.object({
|
|
|
2793
3351
|
transport: z.literal("websocket"),
|
|
2794
3352
|
source: z.string().min(1),
|
|
2795
3353
|
connectToken: z.string().min(1),
|
|
3354
|
+
fastgptBaseUrl: z.string().min(1).optional(),
|
|
2796
3355
|
expiresAt: z.number().int().positive()
|
|
2797
3356
|
});
|
|
2798
3357
|
async function exchangeConnectLink(connectInput) {
|
|
2799
|
-
const
|
|
3358
|
+
const exchangeUrl = isHttpUrl(connectInput) ? connectInput : resolveConnectionKeyExchangeUrl();
|
|
3359
|
+
const response = isHttpUrl(connectInput) ? await fetch(exchangeUrl) : await fetch(exchangeUrl, {
|
|
2800
3360
|
method: "POST",
|
|
2801
3361
|
headers: { "Content-Type": "application/json" },
|
|
2802
3362
|
body: JSON.stringify({ connectionKey: connectInput })
|
|
@@ -2807,6 +3367,7 @@ async function exchangeConnectLink(connectInput) {
|
|
|
2807
3367
|
const info = ConnectInfoSchema.parse(payload.data ?? payload);
|
|
2808
3368
|
return {
|
|
2809
3369
|
...info,
|
|
3370
|
+
fastgptBaseUrl: info.fastgptBaseUrl ?? new URL(exchangeUrl).origin,
|
|
2810
3371
|
tmbId: parseTmbIdFromDebugSource(info.source)
|
|
2811
3372
|
};
|
|
2812
3373
|
}
|
|
@@ -2826,11 +3387,9 @@ function resolveConnectionKeyExchangeUrl() {
|
|
|
2826
3387
|
return new URL("/api/plugin/debug-sessions/connection-key:exchange", baseUrl).toString();
|
|
2827
3388
|
}
|
|
2828
3389
|
function parseTmbIdFromDebugSource(source) {
|
|
2829
|
-
const
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
if (!tmbId) throw new Error(`debug source 缺少 tmbId: ${source}`);
|
|
2833
|
-
return tmbId;
|
|
3390
|
+
const parsed = parsePluginDebugSessionSource(source);
|
|
3391
|
+
if (!parsed) throw new Error(`debug source 缺少 tmbId: ${source}`);
|
|
3392
|
+
return parsed.tmbId;
|
|
2834
3393
|
}
|
|
2835
3394
|
function normalizeGatewayWsUrl(gatewayUrl) {
|
|
2836
3395
|
const parsed = new URL(gatewayUrl);
|