@doufunao123/asset-gateway 0.23.0 → 0.25.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +133 -18
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -15,7 +15,7 @@ import { AssetForgeError } from "@doufunao123/assetforge-sdk";
15
15
 
16
16
  // src/meta.ts
17
17
  var CLI_NAME = "asset-gateway";
18
- var CLI_VERSION = "0.23.0";
18
+ var CLI_VERSION = "0.25.0";
19
19
  var CLI_DESCRIPTION = "Universal asset generation gateway CLI";
20
20
  var DEFAULT_GATEWAY_URL = "https://asset.origingame.dev";
21
21
 
@@ -598,7 +598,7 @@ function createDescribeCommand() {
598
598
 
599
599
  // src/commands/generate.ts
600
600
  import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
601
- import { dirname as dirname2, extname, join as join2 } from "path";
601
+ import { basename, dirname as dirname2, extname, join as join2 } from "path";
602
602
  import { AssetForgeError as AssetForgeError3 } from "@doufunao123/assetforge-sdk";
603
603
  import { Command as Command3 } from "commander";
604
604
  function inferExtension(assetType) {
@@ -747,6 +747,36 @@ async function saveNamedOutput(result, assetType, filePath) {
747
747
  }
748
748
  return null;
749
749
  }
750
+ async function saveOutputFiles(result, outputDir) {
751
+ const outputFiles = Array.isArray(result.output_files) ? result.output_files : [];
752
+ if (outputFiles.length === 0) {
753
+ return [];
754
+ }
755
+ mkdirSync2(outputDir, { recursive: true });
756
+ const saved = [];
757
+ for (const file of outputFiles) {
758
+ if (!isOutputFile(file)) {
759
+ continue;
760
+ }
761
+ const filePath = join2(outputDir, basename(file.name));
762
+ const response = await fetch(file.url);
763
+ if (!response.ok) {
764
+ continue;
765
+ }
766
+ writeFileSync2(filePath, Buffer.from(await response.arrayBuffer()));
767
+ saved.push(filePath);
768
+ }
769
+ if (saved.length > 0) {
770
+ const manifestPath = join2(outputDir, "manifest.json");
771
+ writeFileSync2(manifestPath, `${JSON.stringify(result, null, 2)}
772
+ `, "utf8");
773
+ saved.push(manifestPath);
774
+ }
775
+ return saved;
776
+ }
777
+ function isOutputFile(value) {
778
+ return typeof value === "object" && value !== null && typeof value.name === "string" && typeof value.url === "string" && typeof value.kind === "string";
779
+ }
750
780
  function parseFrameSize(raw) {
751
781
  const [width, height] = raw.split("x");
752
782
  const frameWidth = Number(width);
@@ -959,16 +989,32 @@ function createGenerateCommand() {
959
989
  })
960
990
  );
961
991
  command.addCommand(
962
- new Command3("model").description("Generate a 3D model with Meshy AI").option("--image <input>", "Reference image path or URL").option("--format <fmt>", "Output format: glb, fbx, obj, usdz, stl, 3mf", "glb").option("--prompt <text>", "Model description prompt").option("--ai-model <name>", "Meshy model: meshy-5, meshy-6, latest").option("--polycount <n>", "Target polygon count").option("--pbr", "Enable PBR textures").option("--hd-texture", "Request 4K texture output").option("--pose-mode <mode>", "Character pose mode: a-pose or t-pose").option("--auto-size", "Estimate real-world size automatically").option("--negative-prompt <text>", "Negative prompt").option("--multiview <inputs>", "Comma-separated multiview image paths or URLs").option("--output-dir <dir>", "Directory to save output", ".").action(async function(options) {
992
+ new Command3("model").description(
993
+ "Generate a 3D model with Meshy AI. Default --quality=preview returns a single preview mesh (fast); --quality=full chains preview \u2192 refine \u2192 remesh to deliver a production-ready mesh."
994
+ ).option("--image <input>", "Reference image path or URL").option("--format <fmt>", "Output format: glb, fbx, obj, usdz, stl, 3mf", "glb").option("--prompt <text>", "Model description prompt").option(
995
+ "--quality <mode>",
996
+ "Pipeline mode: preview (single stage, ~30s) or full (chained: preview \u2192 refine \u2192 remesh, ~5-10min)"
997
+ ).option("--ai-model <name>", "Meshy model: meshy-5, meshy-6, latest").option("--polycount <n>", "Target polygon count (full quality only)").option("--pbr", "Enable PBR textures").option("--hd-texture", "Request 4K texture output (requires --ai-model meshy-6)").option("--pose-mode <mode>", "Character pose mode: a-pose or t-pose").option("--auto-size", "Estimate real-world size automatically").option("--negative-prompt <text>", "Negative prompt").option("--multiview <inputs>", "Comma-separated multiview image paths or URLs").option("--output-dir <dir>", "Directory to save output", ".").option(
998
+ "--async",
999
+ "Submit asynchronously; return job_id immediately without waiting. Poll with: asset-gateway job status <id>"
1000
+ ).action(async function(options) {
963
1001
  try {
964
1002
  assertHas3dInput(options.prompt, options.image, options.multiview);
1003
+ if (options.hdTexture && options.aiModel && options.aiModel !== "meshy-6") {
1004
+ throw new Error(
1005
+ "--hd-texture requires --ai-model meshy-6 (got '" + options.aiModel + "'); preview would succeed but refine would 400 and waste credits"
1006
+ );
1007
+ }
965
1008
  const ctx = createContext(this);
966
1009
  const params = {};
967
1010
  if (options.negativePrompt) params.negative_prompt = options.negativePrompt;
968
1011
  if (options.multiview) {
969
1012
  params.multiview = parseCommaSeparatedValues(options.multiview).map((value) => toInputFile(value)).filter((value) => Boolean(value));
970
1013
  }
971
- const data = await ctx.client.model3d(options.prompt ?? "", {
1014
+ if (options.quality) {
1015
+ params.model3d_quality = options.quality;
1016
+ }
1017
+ const sdkOptions = {
972
1018
  input: toInputFile(options.image),
973
1019
  format: options.format,
974
1020
  ai_model: options.aiModel,
@@ -978,7 +1024,19 @@ function createGenerateCommand() {
978
1024
  pose_mode: options.poseMode,
979
1025
  auto_size: options.autoSize ? true : void 0,
980
1026
  params: Object.keys(params).length > 0 ? toJsonObject(params) : void 0
981
- });
1027
+ };
1028
+ if (options.async) {
1029
+ const ack = await ctx.client.model3d(options.prompt ?? "", {
1030
+ ...sdkOptions,
1031
+ async: true
1032
+ });
1033
+ printSuccess("generate.model", ack, ctx);
1034
+ return;
1035
+ }
1036
+ const data = await ctx.client.model3d(
1037
+ options.prompt ?? "",
1038
+ sdkOptions
1039
+ );
982
1040
  const localPath = await saveOutput(data, "model3d", options.outputDir, options.format);
983
1041
  if (localPath) data.local_path = localPath;
984
1042
  printSuccess("generate.model", data, ctx);
@@ -988,12 +1046,20 @@ function createGenerateCommand() {
988
1046
  })
989
1047
  );
990
1048
  command.addCommand(
991
- new Command3("character").description("Generate a fully processed 3D character with Meshy AI").option("--prompt <text>", "Character description prompt").option("--image <input>", "Reference image path or URL").option("--images <inputs>", "Comma-separated reference image paths or URLs").option("--format <fmt>", "Output format: glb, fbx, obj, usdz, stl, 3mf", "glb").option("--polycount <n>", "Target polygon count").option("--pbr", "Enable PBR textures").option("--hd-texture", "Request 4K texture output").option("--pose-mode <mode>", "Character pose mode: a-pose or t-pose").option("--ai-model <name>", "Meshy model: meshy-5, meshy-6, latest").option("--auto-size", "Estimate real-world size automatically").option("--output-dir <dir>", "Directory to save output", ".").action(async function(options) {
1049
+ new Command3("character").description("Generate a fully processed 3D character with Meshy AI (chained preview \u2192 refine \u2192 remesh \u2192 rig)").option("--prompt <text>", "Character description prompt").option("--image <input>", "Reference image path or URL").option("--images <inputs>", "Comma-separated reference image paths or URLs").option("--format <fmt>", "Output format: glb, fbx, obj, usdz, stl, 3mf", "glb").option("--polycount <n>", "Target polygon count").option("--pbr", "Enable PBR textures").option("--hd-texture", "Request 4K texture output (requires --ai-model meshy-6)").option("--pose-mode <mode>", "Character pose mode: a-pose or t-pose").option("--ai-model <name>", "Meshy model: meshy-5, meshy-6, latest").option("--auto-size", "Estimate real-world size automatically").option("--output-dir <dir>", "Directory to save output", ".").option(
1050
+ "--async",
1051
+ "Submit asynchronously; return job_id immediately without waiting. Poll with: asset-gateway job status <id>"
1052
+ ).action(async function(options) {
992
1053
  try {
993
1054
  assertHas3dInput(options.prompt, options.image, options.images);
1055
+ if (options.hdTexture && options.aiModel && options.aiModel !== "meshy-6") {
1056
+ throw new Error(
1057
+ "--hd-texture requires --ai-model meshy-6 (got '" + options.aiModel + "'); preview would succeed but refine would 400 and waste credits"
1058
+ );
1059
+ }
994
1060
  const ctx = createContext(this);
995
1061
  const images = parseCommaSeparatedValues(options.images).map((value) => toInputFile(value)).filter((value) => Boolean(value));
996
- const data = await ctx.client.character(options.prompt ?? "", {
1062
+ const sdkOptions = {
997
1063
  input: toInputFile(options.image),
998
1064
  images: images.length > 0 ? images : void 0,
999
1065
  format: options.format,
@@ -1003,7 +1069,19 @@ function createGenerateCommand() {
1003
1069
  pose_mode: options.poseMode,
1004
1070
  ai_model: options.aiModel,
1005
1071
  auto_size: options.autoSize ? true : void 0
1006
- });
1072
+ };
1073
+ if (options.async) {
1074
+ const ack = await ctx.client.character(options.prompt ?? "", {
1075
+ ...sdkOptions,
1076
+ async: true
1077
+ });
1078
+ printSuccess("generate.character", ack, ctx);
1079
+ return;
1080
+ }
1081
+ const data = await ctx.client.character(
1082
+ options.prompt ?? "",
1083
+ sdkOptions
1084
+ );
1007
1085
  const localPath = await saveOutput(data, "character", options.outputDir, options.format);
1008
1086
  if (localPath) data.local_path = localPath;
1009
1087
  printSuccess("generate.character", data, ctx);
@@ -1013,12 +1091,20 @@ function createGenerateCommand() {
1013
1091
  })
1014
1092
  );
1015
1093
  command.addCommand(
1016
- new Command3("prop").description("Generate a fully processed 3D prop with Meshy AI").option("--prompt <text>", "Prop description prompt").option("--image <input>", "Reference image path or URL").option("--images <inputs>", "Comma-separated reference image paths or URLs").option("--format <fmt>", "Output format: glb, fbx, obj, usdz, stl, 3mf", "glb").option("--polycount <n>", "Target polygon count").option("--pbr", "Enable PBR textures").option("--hd-texture", "Request 4K texture output").option("--ai-model <name>", "Meshy model: meshy-5, meshy-6, latest").option("--auto-size", "Estimate real-world size automatically").option("--texture-prompt <text>", "Optional texture prompt for the final material pass").option("--output-dir <dir>", "Directory to save output", ".").action(async function(options) {
1094
+ new Command3("prop").description("Generate a fully processed 3D prop with Meshy AI (chained preview \u2192 refine \u2192 remesh)").option("--prompt <text>", "Prop description prompt").option("--image <input>", "Reference image path or URL").option("--images <inputs>", "Comma-separated reference image paths or URLs").option("--format <fmt>", "Output format: glb, fbx, obj, usdz, stl, 3mf", "glb").option("--polycount <n>", "Target polygon count").option("--pbr", "Enable PBR textures").option("--hd-texture", "Request 4K texture output (requires --ai-model meshy-6)").option("--ai-model <name>", "Meshy model: meshy-5, meshy-6, latest").option("--auto-size", "Estimate real-world size automatically").option("--texture-prompt <text>", "Optional texture prompt for the final material pass").option("--output-dir <dir>", "Directory to save output", ".").option(
1095
+ "--async",
1096
+ "Submit asynchronously; return job_id immediately without waiting. Poll with: asset-gateway job status <id>"
1097
+ ).action(async function(options) {
1017
1098
  try {
1018
1099
  assertHas3dInput(options.prompt, options.image, options.images);
1100
+ if (options.hdTexture && options.aiModel && options.aiModel !== "meshy-6") {
1101
+ throw new Error(
1102
+ "--hd-texture requires --ai-model meshy-6 (got '" + options.aiModel + "'); preview would succeed but refine would 400 and waste credits"
1103
+ );
1104
+ }
1019
1105
  const ctx = createContext(this);
1020
1106
  const images = parseCommaSeparatedValues(options.images).map((value) => toInputFile(value)).filter((value) => Boolean(value));
1021
- const data = await ctx.client.prop(options.prompt ?? "", {
1107
+ const sdkOptions = {
1022
1108
  input: toInputFile(options.image),
1023
1109
  images: images.length > 0 ? images : void 0,
1024
1110
  format: options.format,
@@ -1028,7 +1114,19 @@ function createGenerateCommand() {
1028
1114
  ai_model: options.aiModel,
1029
1115
  auto_size: options.autoSize ? true : void 0,
1030
1116
  texture_prompt: options.texturePrompt
1031
- });
1117
+ };
1118
+ if (options.async) {
1119
+ const ack = await ctx.client.prop(options.prompt ?? "", {
1120
+ ...sdkOptions,
1121
+ async: true
1122
+ });
1123
+ printSuccess("generate.prop", ack, ctx);
1124
+ return;
1125
+ }
1126
+ const data = await ctx.client.prop(
1127
+ options.prompt ?? "",
1128
+ sdkOptions
1129
+ );
1032
1130
  const localPath = await saveOutput(data, "prop", options.outputDir, options.format);
1033
1131
  if (localPath) data.local_path = localPath;
1034
1132
  printSuccess("generate.prop", data, ctx);
@@ -1094,8 +1192,13 @@ function createGenerateCommand() {
1094
1192
  quality: options.quality,
1095
1193
  display_name: options.displayName
1096
1194
  });
1097
- const localPath = await saveOutput(data, "world", options.outputDir);
1098
- if (localPath) data.local_path = localPath;
1195
+ const localPaths = await saveOutputFiles(data, options.outputDir);
1196
+ if (localPaths.length > 0) {
1197
+ data.local_paths = localPaths;
1198
+ } else {
1199
+ const localPath = await saveOutput(data, "world", options.outputDir);
1200
+ if (localPath) data.local_path = localPath;
1201
+ }
1099
1202
  printSuccess("generate.world", data, ctx);
1100
1203
  } catch (error2) {
1101
1204
  printError("generate.world", error2);
@@ -1140,12 +1243,18 @@ import { Command as Command4 } from "commander";
1140
1243
  function createJobCommand() {
1141
1244
  const command = new Command4("job").description("Job management");
1142
1245
  command.addCommand(
1143
- new Command4("list").description("List jobs").option("--status <status>", "Filter by status").option("--limit <n>", "Maximum number of jobs to return").action(async function(options) {
1246
+ new Command4("list").description("List jobs").option("--job-kind <kind>", "Filter by job kind").option("--status <status>", "Filter by status").option("--asset-type <type>", "Filter by asset type").option("--provider-id <id>", "Filter by provider ID").option("--since <iso>", "Filter jobs created at or after an ISO8601 timestamp").option("--provider-task-id <id>", "Filter by provider task ID").option("--limit <n>", "Maximum number of jobs to return").option("--offset <n>", "Offset for pagination").action(async function(options) {
1144
1247
  try {
1145
1248
  const ctx = createContext(this);
1146
1249
  const data = await ctx.client.job.list({
1250
+ job_kind: options.jobKind,
1147
1251
  status: options.status,
1148
- limit: options.limit ? Number(options.limit) : void 0
1252
+ asset_type: options.assetType,
1253
+ provider_id: options.providerId,
1254
+ since: options.since,
1255
+ provider_task_id: options.providerTaskId,
1256
+ limit: options.limit ? Number(options.limit) : void 0,
1257
+ offset: options.offset ? Number(options.offset) : void 0
1149
1258
  });
1150
1259
  printSuccess("job.list", data, ctx);
1151
1260
  } catch (error2) {
@@ -1187,7 +1296,7 @@ function createLibraryCommand() {
1187
1296
  "Search and manage the asset library"
1188
1297
  );
1189
1298
  command.addCommand(
1190
- new Command5("search").description("Search the asset library").argument("[query]", "Search query").option("-q, --query <query>", "Search query").option("-t, --type <type>", "Filter by asset type (audio, music, image, etc.)").option("--tags <tags>", "Filter by tags (comma-separated)").option("--source <source>", "Filter by source (manual, generated, imported)").option("--pack-id <id>", "Filter by library pack ID").option("--mode <mode>", "Search mode (fts, vector, hybrid)").option("--style <style>", "Filter by visual style").option("--composition <composition>", "Filter by composition").option("--lighting <lighting>", "Filter by lighting").option("--color-tone <tone>", "Filter by color tone").option("--mood <mood>", "Filter by mood (comma-separated)").option("--theme <theme>", "Filter by theme (comma-separated)").option("--era <era>", "Filter by era").option("--gameplay-role <role>", "Filter by gameplay role").option("--rig-name <rig>", "Filter by exact rig name").option("--compatible-rig <rig>", "Filter by compatible rig").option("--no-rerank", "Disable LLM reranking").option("-n, --limit <limit>", "Max results", "20").option("--offset <offset>", "Offset for pagination", "0").action(async function(query) {
1299
+ new Command5("search").description("Search the asset library").argument("[query]", "Search query").option("-q, --query <query>", "Search query").option("-t, --type <type>", "Filter by asset type (audio, music, image, etc.)").option("--tags <tags>", "Filter by tags (comma-separated)").option("--source <source>", "Filter by source (manual, generated, imported)").option("--pack-id <id>", "Filter by library pack ID").option("--mode <mode>", "Search mode (fts, vector, hybrid)").option("--style <style>", "Filter by visual style").option("--composition <composition>", "Filter by composition").option("--lighting <lighting>", "Filter by lighting").option("--color-tone <tone>", "Filter by color tone").option("--mood <mood>", "Filter by mood (comma-separated)").option("--theme <theme>", "Filter by theme (comma-separated)").option("--era <era>", "Filter by era").option("--gameplay-role <role>", "Filter by gameplay role").option("--enrichment-status <status>", "Filter by enrichment status").option("--min-long-edge-px <px>", "Minimum long edge in pixels").option("--min-width-px <px>", "Minimum width in pixels").option("--min-height-px <px>", "Minimum height in pixels").option("--max-file-size-bytes <bytes>", "Maximum file size in bytes").option("--license <license>", "Filter by asset license").option("--rig-name <rig>", "Filter by exact rig name").option("--compatible-rig <rig>", "Filter by compatible rig").option("--no-rerank", "Disable LLM reranking").option("-n, --limit <limit>", "Max results", "20").option("--offset <offset>", "Offset for pagination", "0").action(async function(query) {
1191
1300
  const ctx = createContext(this);
1192
1301
  const opts = this.opts();
1193
1302
  try {
@@ -1206,6 +1315,12 @@ function createLibraryCommand() {
1206
1315
  theme: opts.theme,
1207
1316
  era: opts.era,
1208
1317
  gameplay_role: opts.gameplayRole,
1318
+ enrichment_status: opts.enrichmentStatus,
1319
+ min_long_edge_px: opts.minLongEdgePx ? Number(opts.minLongEdgePx) : void 0,
1320
+ min_width_px: opts.minWidthPx ? Number(opts.minWidthPx) : void 0,
1321
+ min_height_px: opts.minHeightPx ? Number(opts.minHeightPx) : void 0,
1322
+ max_file_size_bytes: opts.maxFileSizeBytes ? Number(opts.maxFileSizeBytes) : void 0,
1323
+ license: opts.license,
1209
1324
  rig_name: opts.rigName,
1210
1325
  compatible_rig: opts.compatibleRig,
1211
1326
  rerank: opts.rerank,
@@ -1838,7 +1953,7 @@ function createProviderCommand() {
1838
1953
 
1839
1954
  // src/commands/upload.ts
1840
1955
  import { readFile as readFile3 } from "fs/promises";
1841
- import { basename } from "path";
1956
+ import { basename as basename2 } from "path";
1842
1957
  import { AssetForgeError as AssetForgeError6 } from "@doufunao123/assetforge-sdk";
1843
1958
  import { Command as Command10 } from "commander";
1844
1959
  function createUploadCommand() {
@@ -1848,7 +1963,7 @@ function createUploadCommand() {
1848
1963
  const ctx = createContext(this);
1849
1964
  try {
1850
1965
  const content = await readLocalFile(filePath);
1851
- const data = await ctx.client.assets.upload(content, { filename: basename(filePath) });
1966
+ const data = await ctx.client.assets.upload(content, { filename: basename2(filePath) });
1852
1967
  printSuccess("asset.upload", data, ctx);
1853
1968
  } catch (error2) {
1854
1969
  printError("asset.upload", error2, ctx.human);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@doufunao123/asset-gateway",
3
- "version": "0.23.0",
3
+ "version": "0.25.0",
4
4
  "description": "Universal asset generation gateway CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -27,7 +27,7 @@
27
27
  "node": ">=20"
28
28
  },
29
29
  "dependencies": {
30
- "@doufunao123/assetforge-sdk": "^0.9.0",
30
+ "@doufunao123/assetforge-sdk": "^0.11.0",
31
31
  "commander": "^13.1.0"
32
32
  },
33
33
  "devDependencies": {