@playcraft/cli 0.0.33 → 0.0.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.
@@ -343,12 +343,12 @@ export async function buildCommand(projectPath, options) {
343
343
  console.log(`\n🎬 选中场景: 全部场景`);
344
344
  }
345
345
  else if (scenesInput === 'default') {
346
- // 打包默认场景
346
+ // 打包默认场景(manifest.scenes 首位 = 当前活跃场景)
347
347
  const projectScenes = await detectProjectScenes(resolvedProjectPath);
348
- const defaultScene = projectScenes.find(s => s.isMain === true) || projectScenes[0];
348
+ const defaultScene = projectScenes[0];
349
349
  if (defaultScene) {
350
350
  selectedScenes = [defaultScene.name || String(defaultScene.id)];
351
- console.log(`\n🎬 选中场景: ${defaultScene.name || defaultScene.id}${defaultScene.isMain ? ' (默认场景)' : ' (第一个场景)'}`);
351
+ console.log(`\n🎬 选中场景: ${defaultScene.name || defaultScene.id} (默认场景)`);
352
352
  }
353
353
  else {
354
354
  console.log(`\n⚠️ 未找到默认场景,将打包所有场景`);
@@ -2,7 +2,7 @@ import { inspect } from 'node:util';
2
2
  import { readFileSync, writeFileSync, readdirSync, statSync, existsSync } from 'fs';
3
3
  import { join, resolve } from 'path';
4
4
  import JSON5 from 'json5';
5
- import { THEME_SCHEMA_PATH, THEME_INDEX_PATH, THEME_DIR, DEFAULT_GAME_PATH, MANIFEST_PATH, ASSETS_JSON_PATH, LITE_CREATOR_EXTENSIONS_DIR, themeDataPath, scenePath, defaultValueFromJsonSchemaProperty, buildThemeIndexTs, parseThemeIndexImportPath, parseThemePrefabs, mergeThemeDataKey, deleteThemeDataKey, parseExtensionMetaData, parseGameConfig, buildExtensionPrefabs, updateGameConfigValue, updateGameConfigExtensions, findConfigKeyCaseInsensitive, parseConfigKey, listScenesFromManifest, listScenesWithGameConfig, resolveGameConfigPath, validateThemeValue, validateConfigValue, describeJsonSchemaFields, describeConfigSchemaFields, getPrefabFieldDescriptors, getPrefabFieldDiffs, prefabHasSchemaDiff, } from '@playcraft/common/prefab';
5
+ import { THEME_SCHEMA_PATH, THEME_INDEX_PATH, THEME_DIR, DEFAULT_GAME_PATH, MANIFEST_PATH, ASSETS_JSON_PATH, LITE_CREATOR_EXTENSIONS_DIR, themeDataPath, scenePath, defaultValueFromJsonSchemaProperty, buildThemeIndexTs, parseThemeIndexImportPath, parseThemePrefabs, mergeThemeDataKey, deleteThemeDataKey, parseExtensionMetaData, parseGameConfig, buildExtensionPrefabs, updateGameConfigValue, updateGameConfigExtensions, findConfigKeyCaseInsensitive, parseConfigKey, listScenesFromManifest, listScenesWithGameConfig, resolveGameConfigPath, getActiveSceneIdFromManifest, reorderManifestDefaultScene, validateThemeValue, validateConfigValue, describeJsonSchemaFields, describeConfigSchemaFields, getPrefabFieldDescriptors, getPrefabFieldDiffs, prefabHasSchemaDiff, } from '@playcraft/common/prefab';
6
6
  const DEFAULT_PAGE_LIMIT = 50;
7
7
  /** 场景在 manifest / CLI 中列出但解析不到 GameConfig 时的人读标签 */
8
8
  const NO_SCENE_GAMECONFIG_LABEL = '(无场景级 GameConfig)';
@@ -243,33 +243,16 @@ function resolveThemeId(projectDir, opts) {
243
243
  }
244
244
  // ─── PlayCanvas / LiteCreator helpers ────────────────────────────────────────
245
245
  /**
246
- * manifest 中的主场景 ID(与编辑器「当前入口场景」对齐)。
246
+ * 当前活跃场景 ID = manifest.scenes[0]。
247
247
  *
248
- * 优先级:1) isMain: true 2) 仅有一个场景时自动视为当前活跃场景 3) 无法确定则 null
248
+ * Remix 编辑器和后端 `setDefaultScene`(将目标场景移到首位)的 SSOT 一致。
249
249
  */
250
250
  function getMainSceneId(projectDir) {
251
251
  if (!fileExists(projectDir, MANIFEST_PATH))
252
252
  return null;
253
253
  try {
254
254
  const manifestJson = JSON.parse(readLocalFile(projectDir, MANIFEST_PATH));
255
- const scenes = manifestJson.scenes;
256
- if (!Array.isArray(scenes) || scenes.length === 0)
257
- return null;
258
- const mainScene = scenes.find((s) => !!s && typeof s === 'object' && s.isMain === true);
259
- if (mainScene != null && (mainScene.id != null || mainScene.uniqueId != null)) {
260
- return String(mainScene.id ?? mainScene.uniqueId);
261
- }
262
- if (scenes.length === 1) {
263
- const only = scenes[0];
264
- if (only && typeof only === 'object') {
265
- const o = only;
266
- if (o.id != null)
267
- return String(o.id);
268
- if (o.uniqueId != null)
269
- return String(o.uniqueId);
270
- }
271
- }
272
- return null;
255
+ return getActiveSceneIdFromManifest(manifestJson);
273
256
  }
274
257
  catch {
275
258
  return null;
@@ -332,7 +315,7 @@ function writeMetaDataDefaults(projectDir, extensionName, values) {
332
315
  }
333
316
  });
334
317
  }
335
- /** 仅按场景 ID 解析 GameConfig(不查主场景)。 */
318
+ /** 仅按场景 ID 解析 GameConfig(不查活跃场景)。 */
336
319
  function resolveGameConfigPathForSceneId(projectDir, sceneId) {
337
320
  if (!fileExists(projectDir, scenePath(sceneId)))
338
321
  return null;
@@ -344,7 +327,7 @@ function resolveGameConfigPathForSceneId(projectDir, sceneId) {
344
327
  }
345
328
  /**
346
329
  * 解析当前变体下的 GameConfig 路径。无法解析时返回 null(list 回退 DefaultGame 扩展;set 可写 MetaData)。
347
- * 未传 variantId 时用 manifest 主场景(isMain / 单场景)。
330
+ * 未传 variantId 时用 manifest 首位场景(当前活跃场景)。
348
331
  */
349
332
  function resolveGameConfigPathForVariant(projectDir, variantId) {
350
333
  const sceneId = variantId ?? getMainSceneId(projectDir);
@@ -362,10 +345,10 @@ function liteCreatorVariantHumanNote(projectDir, explicitVariant) {
362
345
  const gc = resolveGameConfigPathForVariant(projectDir, undefined);
363
346
  if (mainId != null) {
364
347
  return gc != null
365
- ? `主场景 ${mainId} → ${gc}`
366
- : `主场景 ${mainId}(未解析到 GameConfig;list 读 ${DEFAULT_GAME_PATH} 扩展,set 写 MetaData)`;
348
+ ? `活跃场景 ${mainId} → ${gc}`
349
+ : `活跃场景 ${mainId}(未解析到 GameConfig;list 读 ${DEFAULT_GAME_PATH} 扩展,set 写 MetaData)`;
367
350
  }
368
- return `无主场景标记 → 扩展列表:${DEFAULT_GAME_PATH};set / set-batch:各扩展 MetaData.json`;
351
+ return `无场景 → 扩展列表:${DEFAULT_GAME_PATH};set / set-batch:各扩展 MetaData.json`;
369
352
  }
370
353
  function listLocalScenes(projectDir) {
371
354
  if (!fileExists(projectDir, MANIFEST_PATH))
@@ -382,7 +365,7 @@ function listLocalScenes(projectDir) {
382
365
  }
383
366
  return listScenesFromManifest(manifestJson);
384
367
  }
385
- /** 列表展示:补全 GameConfig 路径,并用主场景 ID 标记 isActive(与未指定 --variant 的 prefab 上下文一致)。 */
368
+ /** 列表展示:补全 GameConfig 路径,并用活跃场景 ID 标记 isActive(与未指定 --variant 的 prefab 上下文一致)。 */
386
369
  function annotatePlaycanvasScenesForMainScene(projectDir, scenes) {
387
370
  const mainSceneId = getMainSceneId(projectDir);
388
371
  const annotated = scenes.map((s) => {
@@ -569,13 +552,13 @@ export function registerPrefabCommands(program) {
569
552
  }
570
553
  if (scenes.some((v) => v.isActive)) {
571
554
  console.log('');
572
- console.log('标 *:manifest 主场景(isMain,或仅 1 个场景时自动认定)。' +
573
- ' 未带 --variant:优先该场景 GameConfig;若无路径则 list 读 DefaultGame 扩展、set 写 MetaData。');
555
+ console.log('标 *:manifest 首位场景(当前活跃场景,与 Remix 编辑器一致)。' +
556
+ ' 未带 --variant:优先该场景 GameConfig;若无路径则 list 读 DefaultGame 扩展、set 写 MetaData。' +
557
+ ' 可用 `prefab switch <sceneId>` 切换活跃场景。');
574
558
  }
575
559
  else {
576
560
  console.log('');
577
- console.log('无主场景:多场景请在 manifest 设 isMain。未带 --variant 时扩展来自 ' +
578
- `${DEFAULT_GAME_PATH},set / set-batch 写入各扩展 MetaData.json。`);
561
+ console.log(`无场景:未带 --variant 时扩展来自 ${DEFAULT_GAME_PATH},set / set-batch 写入各扩展 MetaData.json。`);
579
562
  }
580
563
  });
581
564
  }
@@ -1282,14 +1265,19 @@ export function registerPrefabCommands(program) {
1282
1265
  console.error(`Error: 场景 "${variant}" 不存在。可用: ${scenes.map((s) => `${s.name}(${s.id})`).join(', ')}`);
1283
1266
  process.exit(1);
1284
1267
  }
1268
+ const manifestRaw = readLocalFile(projectDir, MANIFEST_PATH);
1269
+ const manifestJson = JSON.parse(manifestRaw);
1270
+ const reordered = reorderManifestDefaultScene(manifestJson, found.id);
1271
+ if (reordered && reordered !== manifestJson) {
1272
+ writeFileSync(join(projectDir, MANIFEST_PATH), JSON.stringify(reordered, null, 2), 'utf-8');
1273
+ }
1285
1274
  const payload = {
1286
1275
  success: true,
1287
1276
  activeVariant: found.id,
1288
- message: `PlayCanvas 场景上下文已设为 "${found.name}"。后续命令使用 --variant ${found.id} 来操作此场景的配置。`,
1277
+ message: `PlayCanvas 场景已切换为 "${found.name}" 并写入 manifest.json。`,
1289
1278
  };
1290
1279
  outputResult(asJson, payload, () => {
1291
- console.log(`PlayCanvas 场景上下文已设为「${found.name}」 (${found.id})。`);
1292
- console.log(`后续命令请使用 --variant ${found.id} 操作该场景的配置。`);
1280
+ console.log(`已切换活跃场景为「${found.name}」 (${found.id}),manifest.json 已更新。`);
1293
1281
  });
1294
1282
  }
1295
1283
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@playcraft/cli",
3
- "version": "0.0.33",
3
+ "version": "0.0.34",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "bin": {
@@ -23,7 +23,7 @@
23
23
  "release": "node scripts/release.js"
24
24
  },
25
25
  "dependencies": {
26
- "@playcraft/build": "^0.0.34",
26
+ "@playcraft/build": "^0.0.35",
27
27
  "@playcraft/common": "^0.0.22",
28
28
  "chokidar": "^4.0.3",
29
29
  "commander": "^13.1.0",