@playcraft/cli 0.0.24 → 0.0.25
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/commands/prefab.js +214 -28
- package/package.json +3 -3
package/dist/commands/prefab.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { inspect } from 'node:util';
|
|
1
2
|
import { readFileSync, writeFileSync, readdirSync, statSync, existsSync } from 'fs';
|
|
2
3
|
import { join, resolve } from 'path';
|
|
3
4
|
import JSON5 from 'json5';
|
|
@@ -22,9 +23,50 @@ function detectProjectType(projectDir) {
|
|
|
22
23
|
process.exit(1);
|
|
23
24
|
throw new Error('Project type could not be detected');
|
|
24
25
|
}
|
|
26
|
+
const HUMAN_INSPECT = { colors: false, depth: 10, maxArrayLength: 200 };
|
|
27
|
+
const JSON_OPT_DESC = '以 JSON 输出(便于脚本解析;默认为人可读文本)';
|
|
28
|
+
/** 为子命令追加 `--json`(默认人类可读) */
|
|
29
|
+
function withJsonOption(cmd) {
|
|
30
|
+
return cmd.option('--json', JSON_OPT_DESC);
|
|
31
|
+
}
|
|
25
32
|
function outputJson(data) {
|
|
26
33
|
console.log(JSON.stringify(data, null, 2));
|
|
27
34
|
}
|
|
35
|
+
function formatHumanValue(value) {
|
|
36
|
+
if (value === null)
|
|
37
|
+
return 'null';
|
|
38
|
+
if (value === undefined)
|
|
39
|
+
return 'undefined';
|
|
40
|
+
if (typeof value === 'string')
|
|
41
|
+
return value;
|
|
42
|
+
if (typeof value === 'number' || typeof value === 'boolean')
|
|
43
|
+
return String(value);
|
|
44
|
+
return inspect(value, HUMAN_INSPECT);
|
|
45
|
+
}
|
|
46
|
+
function outputResult(json, data, printHuman) {
|
|
47
|
+
if (json) {
|
|
48
|
+
outputJson(data);
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
printHuman();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function projectTypeLabel(systemType) {
|
|
55
|
+
return systemType === 'external-theme' ? 'External(主题)' : 'PlayCanvas(Lite Creator)';
|
|
56
|
+
}
|
|
57
|
+
function describeFieldLine(f) {
|
|
58
|
+
const parts = [f.path, `类型: ${f.type}`];
|
|
59
|
+
if (f.description)
|
|
60
|
+
parts.push(f.description);
|
|
61
|
+
if (f.constraints)
|
|
62
|
+
parts.push(`(${f.constraints})`);
|
|
63
|
+
if (f.enumOptions?.length)
|
|
64
|
+
parts.push(`可选: ${f.enumOptions.join(', ')}`);
|
|
65
|
+
parts.push(`当前: ${formatHumanValue(f.currentValue)}`);
|
|
66
|
+
if (f.default !== undefined)
|
|
67
|
+
parts.push(`默认: ${formatHumanValue(f.default)}`);
|
|
68
|
+
return parts.join(' | ');
|
|
69
|
+
}
|
|
28
70
|
// ─── External Theme helpers ──────────────────────────────────────────────────
|
|
29
71
|
function loadThemeSchema(projectDir) {
|
|
30
72
|
const raw = readLocalFile(projectDir, THEME_SCHEMA_PATH);
|
|
@@ -189,6 +231,7 @@ export function registerPrefabCommands(program) {
|
|
|
189
231
|
const variantsHandler = (opts) => {
|
|
190
232
|
const projectDir = resolveProjectDir(opts);
|
|
191
233
|
const systemType = detectProjectType(projectDir);
|
|
234
|
+
const asJson = Boolean(opts.json);
|
|
192
235
|
if (systemType === 'external-theme') {
|
|
193
236
|
const themes = listLocalThemeIds(projectDir);
|
|
194
237
|
const activeId = resolveActiveThemeId(projectDir);
|
|
@@ -197,27 +240,51 @@ export function registerPrefabCommands(program) {
|
|
|
197
240
|
name: id,
|
|
198
241
|
isActive: id === activeId,
|
|
199
242
|
}));
|
|
200
|
-
|
|
243
|
+
const payload = { projectType: 'external', variants };
|
|
244
|
+
outputResult(asJson, payload, () => {
|
|
245
|
+
console.log(`项目类型: ${projectTypeLabel('external-theme')}`);
|
|
246
|
+
console.log('');
|
|
247
|
+
for (const v of variants) {
|
|
248
|
+
const mark = v.isActive ? ' *' : '';
|
|
249
|
+
console.log(` ${v.id}${mark}`);
|
|
250
|
+
}
|
|
251
|
+
if (variants.some((v) => v.isActive)) {
|
|
252
|
+
console.log('');
|
|
253
|
+
console.log('标 * 为当前 index.ts 中的活跃主题。');
|
|
254
|
+
}
|
|
255
|
+
});
|
|
201
256
|
}
|
|
202
257
|
else {
|
|
203
258
|
const scenes = listLocalScenes(projectDir);
|
|
204
|
-
|
|
259
|
+
const payload = { projectType: 'playcanvas', variants: scenes };
|
|
260
|
+
outputResult(asJson, payload, () => {
|
|
261
|
+
console.log(`项目类型: ${projectTypeLabel('lite-creator')}`);
|
|
262
|
+
console.log('');
|
|
263
|
+
if (scenes.length === 0) {
|
|
264
|
+
console.log('(无场景)');
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
for (const s of scenes) {
|
|
268
|
+
const gc = s.gameConfigPath ? ` [${s.gameConfigPath}]` : '';
|
|
269
|
+
console.log(` ${s.name} (${s.id})${gc}`);
|
|
270
|
+
}
|
|
271
|
+
});
|
|
205
272
|
}
|
|
206
273
|
};
|
|
207
|
-
prefab.command('variants')
|
|
274
|
+
withJsonOption(prefab.command('variants'))
|
|
208
275
|
.description('列出可用变体(External: 主题列表;PlayCanvas: 场景列表)')
|
|
209
276
|
.option('--project-dir <path>', '项目根目录(默认 cwd)')
|
|
210
277
|
.action(variantsHandler);
|
|
211
|
-
prefab.command('themes')
|
|
278
|
+
withJsonOption(prefab.command('themes'))
|
|
212
279
|
.description('variants 别名(对齐前端「主题列表」术语)')
|
|
213
280
|
.option('--project-dir <path>', '项目根目录(默认 cwd)')
|
|
214
281
|
.action(variantsHandler);
|
|
215
|
-
prefab.command('scenes')
|
|
282
|
+
withJsonOption(prefab.command('scenes'))
|
|
216
283
|
.description('variants 别名(对齐前端「场景列表」术语)')
|
|
217
284
|
.option('--project-dir <path>', '项目根目录(默认 cwd)')
|
|
218
285
|
.action(variantsHandler);
|
|
219
286
|
// ─── list ────────────────────────────────────────────────────
|
|
220
|
-
prefab.command('list')
|
|
287
|
+
withJsonOption(prefab.command('list'))
|
|
221
288
|
.description('列出所有 prefab 及状态')
|
|
222
289
|
.option('--variant <id>', '指定变体(External: themeId;PlayCanvas: sceneId)')
|
|
223
290
|
.option('--project-dir <path>', '项目根目录(默认 cwd)')
|
|
@@ -225,7 +292,12 @@ export function registerPrefabCommands(program) {
|
|
|
225
292
|
const projectDir = resolveProjectDir(opts);
|
|
226
293
|
const systemType = detectProjectType(projectDir);
|
|
227
294
|
const prefabs = loadPrefabs(projectDir, systemType, opts);
|
|
228
|
-
|
|
295
|
+
const asJson = Boolean(opts.json);
|
|
296
|
+
let variantNote = opts.variant ?? null;
|
|
297
|
+
if (systemType === 'external-theme' && !opts.variant) {
|
|
298
|
+
variantNote = resolveThemeId(projectDir, opts);
|
|
299
|
+
}
|
|
300
|
+
const payload = {
|
|
229
301
|
projectType: systemType === 'external-theme' ? 'external' : 'playcanvas',
|
|
230
302
|
variant: opts.variant ?? null,
|
|
231
303
|
total: prefabs.length,
|
|
@@ -237,10 +309,34 @@ export function registerPrefabCommands(program) {
|
|
|
237
309
|
isUsed: p.isUsed,
|
|
238
310
|
type: p.systemType,
|
|
239
311
|
})),
|
|
312
|
+
};
|
|
313
|
+
outputResult(asJson, payload, () => {
|
|
314
|
+
console.log(`项目类型: ${projectTypeLabel(systemType)}`);
|
|
315
|
+
console.log(`变体上下文: ${variantNote ?? '(默认)'}`);
|
|
316
|
+
console.log(`共 ${prefabs.length} 个 prefab,已启用 ${prefabs.filter((p) => p.isUsed).length} 个。`);
|
|
317
|
+
console.log('');
|
|
318
|
+
const keyW = Math.min(28, Math.max(8, ...prefabs.map((p) => p.key.length)));
|
|
319
|
+
for (let i = 0; i < prefabs.length; i++) {
|
|
320
|
+
const p = prefabs[i];
|
|
321
|
+
const status = p.isUsed ? '已启用' : '未启用';
|
|
322
|
+
const label = p.key.padEnd(keyW);
|
|
323
|
+
console.log(` ${label} ${status}`);
|
|
324
|
+
const detailIndent = ' ';
|
|
325
|
+
if (p.name && p.name !== p.key) {
|
|
326
|
+
console.log(`${detailIndent}名称: ${p.name}`);
|
|
327
|
+
}
|
|
328
|
+
const desc = p.description?.trim();
|
|
329
|
+
if (desc) {
|
|
330
|
+
console.log(`${detailIndent}说明: ${desc}`);
|
|
331
|
+
}
|
|
332
|
+
if (i < prefabs.length - 1) {
|
|
333
|
+
console.log('');
|
|
334
|
+
}
|
|
335
|
+
}
|
|
240
336
|
});
|
|
241
337
|
});
|
|
242
338
|
// ─── describe ────────────────────────────────────────────────
|
|
243
|
-
prefab.command('describe <key>')
|
|
339
|
+
withJsonOption(prefab.command('describe <key>'))
|
|
244
340
|
.description('显示 prefab 完整字段信息')
|
|
245
341
|
.option('--variant <id>', '指定变体')
|
|
246
342
|
.option('--project-dir <path>', '项目根目录(默认 cwd)')
|
|
@@ -253,14 +349,27 @@ export function registerPrefabCommands(program) {
|
|
|
253
349
|
console.error(`Error: prefab "${key}" 不存在。可用的 key: ${prefabs.map((p) => p.key).join(', ')}`);
|
|
254
350
|
process.exit(1);
|
|
255
351
|
}
|
|
352
|
+
const asJson = Boolean(opts.json);
|
|
256
353
|
if (found.systemType === 'external-theme' && found.jsonSchema) {
|
|
257
354
|
const fields = describeJsonSchemaFields(found.jsonSchema, found.currentValue);
|
|
258
|
-
|
|
355
|
+
const payload = {
|
|
259
356
|
key: found.key,
|
|
260
357
|
type: found.systemType,
|
|
261
358
|
isUsed: found.isUsed,
|
|
262
359
|
description: found.description,
|
|
263
360
|
fields,
|
|
361
|
+
};
|
|
362
|
+
outputResult(asJson, payload, () => {
|
|
363
|
+
console.log(`Prefab: ${found.key}`);
|
|
364
|
+
console.log(`类型: ${projectTypeLabel(found.systemType)}`);
|
|
365
|
+
console.log(`状态: ${found.isUsed ? '已启用' : '未启用'}`);
|
|
366
|
+
if (found.description)
|
|
367
|
+
console.log(`说明: ${found.description}`);
|
|
368
|
+
console.log('');
|
|
369
|
+
console.log('字段:');
|
|
370
|
+
for (const f of fields) {
|
|
371
|
+
console.log(` • ${describeFieldLine(f)}`);
|
|
372
|
+
}
|
|
264
373
|
});
|
|
265
374
|
}
|
|
266
375
|
else if (found.configSchema) {
|
|
@@ -268,27 +377,51 @@ export function registerPrefabCommands(program) {
|
|
|
268
377
|
? found.currentValue
|
|
269
378
|
: {};
|
|
270
379
|
const fields = describeConfigSchemaFields(found.configSchema, currentValues);
|
|
271
|
-
|
|
380
|
+
const payload = {
|
|
272
381
|
key: found.key,
|
|
273
382
|
type: found.systemType,
|
|
274
383
|
isUsed: found.isUsed,
|
|
275
384
|
description: found.description,
|
|
276
385
|
configPath: found.configPath,
|
|
277
386
|
fields,
|
|
387
|
+
};
|
|
388
|
+
outputResult(asJson, payload, () => {
|
|
389
|
+
console.log(`Prefab: ${found.key}`);
|
|
390
|
+
console.log(`类型: ${projectTypeLabel(found.systemType)}`);
|
|
391
|
+
console.log(`状态: ${found.isUsed ? '已启用' : '未启用'}`);
|
|
392
|
+
if (found.configPath)
|
|
393
|
+
console.log(`配置: ${found.configPath}`);
|
|
394
|
+
if (found.description)
|
|
395
|
+
console.log(`说明: ${found.description}`);
|
|
396
|
+
console.log('');
|
|
397
|
+
console.log('字段:');
|
|
398
|
+
for (const f of fields) {
|
|
399
|
+
console.log(` • ${describeFieldLine(f)}`);
|
|
400
|
+
}
|
|
278
401
|
});
|
|
279
402
|
}
|
|
280
403
|
else {
|
|
281
|
-
|
|
404
|
+
const payload = {
|
|
282
405
|
key: found.key,
|
|
283
406
|
type: found.systemType,
|
|
284
407
|
isUsed: found.isUsed,
|
|
285
408
|
description: found.description,
|
|
286
409
|
currentValue: found.currentValue,
|
|
410
|
+
};
|
|
411
|
+
outputResult(asJson, payload, () => {
|
|
412
|
+
console.log(`Prefab: ${found.key}`);
|
|
413
|
+
console.log(`类型: ${projectTypeLabel(found.systemType)}`);
|
|
414
|
+
console.log(`状态: ${found.isUsed ? '已启用' : '未启用'}`);
|
|
415
|
+
if (found.description)
|
|
416
|
+
console.log(`说明: ${found.description}`);
|
|
417
|
+
console.log('');
|
|
418
|
+
console.log('当前值:');
|
|
419
|
+
console.log(formatHumanValue(found.currentValue));
|
|
287
420
|
});
|
|
288
421
|
}
|
|
289
422
|
});
|
|
290
423
|
// ─── get ─────────────────────────────────────────────────────
|
|
291
|
-
prefab.command('get <key> [field]')
|
|
424
|
+
withJsonOption(prefab.command('get <key> [field]'))
|
|
292
425
|
.description('获取 prefab 或子字段的当前值')
|
|
293
426
|
.option('--variant <id>', '指定变体')
|
|
294
427
|
.option('--project-dir <path>', '项目根目录(默认 cwd)')
|
|
@@ -309,16 +442,27 @@ export function registerPrefabCommands(program) {
|
|
|
309
442
|
if (field) {
|
|
310
443
|
value = getByDotPath(value, field);
|
|
311
444
|
}
|
|
312
|
-
|
|
445
|
+
const payload = { key, field: field ?? null, value };
|
|
446
|
+
const asJson = Boolean(opts.json);
|
|
447
|
+
outputResult(asJson, payload, () => {
|
|
448
|
+
if (field) {
|
|
449
|
+
console.log(formatHumanValue(value));
|
|
450
|
+
}
|
|
451
|
+
else {
|
|
452
|
+
console.log(`${key}:`);
|
|
453
|
+
console.log(formatHumanValue(value));
|
|
454
|
+
}
|
|
455
|
+
});
|
|
313
456
|
});
|
|
314
457
|
// ─── set ─────────────────────────────────────────────────────
|
|
315
|
-
prefab.command('set <key> <field> <value>')
|
|
458
|
+
withJsonOption(prefab.command('set <key> <field> <value>'))
|
|
316
459
|
.description('修改 prefab 子字段值(带校验)')
|
|
317
460
|
.option('--variant <id>', '指定变体')
|
|
318
461
|
.option('--project-dir <path>', '项目根目录(默认 cwd)')
|
|
319
462
|
.action((key, field, rawValue, opts) => {
|
|
320
463
|
const projectDir = resolveProjectDir(opts);
|
|
321
464
|
const systemType = detectProjectType(projectDir);
|
|
465
|
+
const asJson = Boolean(opts.json);
|
|
322
466
|
if (systemType === 'external-theme') {
|
|
323
467
|
const themeId = resolveThemeId(projectDir, opts);
|
|
324
468
|
const schema = loadThemeSchema(projectDir);
|
|
@@ -352,7 +496,10 @@ export function registerPrefabCommands(program) {
|
|
|
352
496
|
}
|
|
353
497
|
const newData = mergeThemeDataKey(data, key, newValue);
|
|
354
498
|
writeThemeData(projectDir, themeId, newData);
|
|
355
|
-
|
|
499
|
+
const payload = { success: true, key, field, value: coerced };
|
|
500
|
+
outputResult(asJson, payload, () => {
|
|
501
|
+
console.log(`已更新 ${key}.${field} = ${formatHumanValue(coerced)}`);
|
|
502
|
+
});
|
|
356
503
|
}
|
|
357
504
|
else {
|
|
358
505
|
const configPath = resolveGameConfigPathForVariant(projectDir, opts.variant);
|
|
@@ -380,17 +527,21 @@ export function registerPrefabCommands(program) {
|
|
|
380
527
|
const newValues = { ...currentValues, [field]: coerced };
|
|
381
528
|
const updated = updateGameConfigValue(gameConfigJson, configKey, newValues);
|
|
382
529
|
writeGameConfig(projectDir, configPath, updated);
|
|
383
|
-
|
|
530
|
+
const payload = { success: true, key, field, value: coerced };
|
|
531
|
+
outputResult(asJson, payload, () => {
|
|
532
|
+
console.log(`已更新 ${key}.${field} = ${formatHumanValue(coerced)}`);
|
|
533
|
+
});
|
|
384
534
|
}
|
|
385
535
|
});
|
|
386
536
|
// ─── enable ──────────────────────────────────────────────────
|
|
387
|
-
prefab.command('enable <key>')
|
|
537
|
+
withJsonOption(prefab.command('enable <key>'))
|
|
388
538
|
.description('启用 prefab')
|
|
389
539
|
.option('--variant <id>', '指定变体')
|
|
390
540
|
.option('--project-dir <path>', '项目根目录(默认 cwd)')
|
|
391
541
|
.action((key, opts) => {
|
|
392
542
|
const projectDir = resolveProjectDir(opts);
|
|
393
543
|
const systemType = detectProjectType(projectDir);
|
|
544
|
+
const asJson = Boolean(opts.json);
|
|
394
545
|
if (systemType === 'external-theme') {
|
|
395
546
|
const themeId = resolveThemeId(projectDir, opts);
|
|
396
547
|
const schema = loadThemeSchema(projectDir);
|
|
@@ -403,39 +554,56 @@ export function registerPrefabCommands(program) {
|
|
|
403
554
|
const defaultValue = defaultValueFromJsonSchemaProperty(props[key]);
|
|
404
555
|
const newData = mergeThemeDataKey(data, key, defaultValue);
|
|
405
556
|
writeThemeData(projectDir, themeId, newData);
|
|
406
|
-
|
|
557
|
+
const payload = { success: true, key, enabled: true, defaultValue };
|
|
558
|
+
outputResult(asJson, payload, () => {
|
|
559
|
+
console.log(`已启用 prefab「${key}」,并写入 schema 默认值:`);
|
|
560
|
+
console.log(formatHumanValue(defaultValue));
|
|
561
|
+
});
|
|
407
562
|
}
|
|
408
563
|
else {
|
|
409
564
|
const configPath = resolveGameConfigPathForVariant(projectDir, opts.variant);
|
|
410
565
|
const gameConfigJson = loadGameConfig(projectDir, configPath);
|
|
411
566
|
const { extensions } = parseGameConfig(gameConfigJson);
|
|
412
567
|
if (extensions.includes(key)) {
|
|
413
|
-
|
|
568
|
+
const payload = { success: true, key, enabled: true, message: 'Already enabled' };
|
|
569
|
+
outputResult(asJson, payload, () => {
|
|
570
|
+
console.log(`扩展「${key}」已在配置中启用,无需变更。`);
|
|
571
|
+
});
|
|
414
572
|
return;
|
|
415
573
|
}
|
|
416
574
|
const updated = updateGameConfigExtensions(gameConfigJson, [...extensions, key]);
|
|
417
575
|
writeGameConfig(projectDir, configPath, updated);
|
|
418
|
-
|
|
576
|
+
const payload = { success: true, key, enabled: true };
|
|
577
|
+
outputResult(asJson, payload, () => {
|
|
578
|
+
console.log(`已启用扩展「${key}」并更新 Game 配置。`);
|
|
579
|
+
});
|
|
419
580
|
}
|
|
420
581
|
});
|
|
421
582
|
// ─── disable ─────────────────────────────────────────────────
|
|
422
|
-
prefab.command('disable <key>')
|
|
583
|
+
withJsonOption(prefab.command('disable <key>'))
|
|
423
584
|
.description('禁用 prefab')
|
|
424
585
|
.option('--variant <id>', '指定变体')
|
|
425
586
|
.option('--project-dir <path>', '项目根目录(默认 cwd)')
|
|
426
587
|
.action((key, opts) => {
|
|
427
588
|
const projectDir = resolveProjectDir(opts);
|
|
428
589
|
const systemType = detectProjectType(projectDir);
|
|
590
|
+
const asJson = Boolean(opts.json);
|
|
429
591
|
if (systemType === 'external-theme') {
|
|
430
592
|
const themeId = resolveThemeId(projectDir, opts);
|
|
431
593
|
const data = loadThemeData(projectDir, themeId);
|
|
432
594
|
if (!Object.prototype.hasOwnProperty.call(data, key)) {
|
|
433
|
-
|
|
595
|
+
const payload = { success: true, key, enabled: false, message: 'Already disabled' };
|
|
596
|
+
outputResult(asJson, payload, () => {
|
|
597
|
+
console.log(`Prefab「${key}」在主题数据中本就不存在,视为已禁用。`);
|
|
598
|
+
});
|
|
434
599
|
return;
|
|
435
600
|
}
|
|
436
601
|
const newData = deleteThemeDataKey(data, key);
|
|
437
602
|
writeThemeData(projectDir, themeId, newData);
|
|
438
|
-
|
|
603
|
+
const payload = { success: true, key, enabled: false };
|
|
604
|
+
outputResult(asJson, payload, () => {
|
|
605
|
+
console.log(`已禁用 prefab「${key}」并从主题数据中移除。`);
|
|
606
|
+
});
|
|
439
607
|
}
|
|
440
608
|
else {
|
|
441
609
|
const configPath = resolveGameConfigPathForVariant(projectDir, opts.variant);
|
|
@@ -443,21 +611,28 @@ export function registerPrefabCommands(program) {
|
|
|
443
611
|
const { extensions } = parseGameConfig(gameConfigJson);
|
|
444
612
|
const filtered = extensions.filter((n) => n !== key);
|
|
445
613
|
if (filtered.length === extensions.length) {
|
|
446
|
-
|
|
614
|
+
const payload = { success: true, key, enabled: false, message: 'Already disabled' };
|
|
615
|
+
outputResult(asJson, payload, () => {
|
|
616
|
+
console.log(`扩展「${key}」未在配置中启用,无需变更。`);
|
|
617
|
+
});
|
|
447
618
|
return;
|
|
448
619
|
}
|
|
449
620
|
const updated = updateGameConfigExtensions(gameConfigJson, filtered);
|
|
450
621
|
writeGameConfig(projectDir, configPath, updated);
|
|
451
|
-
|
|
622
|
+
const payload = { success: true, key, enabled: false };
|
|
623
|
+
outputResult(asJson, payload, () => {
|
|
624
|
+
console.log(`已禁用扩展「${key}」并更新 Game 配置。`);
|
|
625
|
+
});
|
|
452
626
|
}
|
|
453
627
|
});
|
|
454
628
|
// ─── switch ──────────────────────────────────────────────────
|
|
455
|
-
prefab.command('switch <variant>')
|
|
629
|
+
withJsonOption(prefab.command('switch <variant>'))
|
|
456
630
|
.description('切换活跃变体(External: 修改 index.ts;PlayCanvas: 指定场景上下文)')
|
|
457
631
|
.option('--project-dir <path>', '项目根目录(默认 cwd)')
|
|
458
632
|
.action((variant, opts) => {
|
|
459
633
|
const projectDir = resolveProjectDir(opts);
|
|
460
634
|
const systemType = detectProjectType(projectDir);
|
|
635
|
+
const asJson = Boolean(opts.json);
|
|
461
636
|
if (systemType === 'external-theme') {
|
|
462
637
|
const themes = listLocalThemeIds(projectDir);
|
|
463
638
|
if (!themes.includes(variant)) {
|
|
@@ -466,7 +641,14 @@ export function registerPrefabCommands(program) {
|
|
|
466
641
|
}
|
|
467
642
|
const content = buildThemeIndexTs(variant);
|
|
468
643
|
writeFileSync(join(projectDir, THEME_INDEX_PATH), content, 'utf-8');
|
|
469
|
-
|
|
644
|
+
const payload = {
|
|
645
|
+
success: true,
|
|
646
|
+
activeVariant: variant,
|
|
647
|
+
message: `Switched to theme "${variant}"`,
|
|
648
|
+
};
|
|
649
|
+
outputResult(asJson, payload, () => {
|
|
650
|
+
console.log(`已切换活跃主题为「${variant}」(已写入 ${THEME_INDEX_PATH})。`);
|
|
651
|
+
});
|
|
470
652
|
}
|
|
471
653
|
else {
|
|
472
654
|
const scenes = listLocalScenes(projectDir);
|
|
@@ -475,10 +657,14 @@ export function registerPrefabCommands(program) {
|
|
|
475
657
|
console.error(`Error: 场景 "${variant}" 不存在。可用: ${scenes.map((s) => `${s.name}(${s.id})`).join(', ')}`);
|
|
476
658
|
process.exit(1);
|
|
477
659
|
}
|
|
478
|
-
|
|
660
|
+
const payload = {
|
|
479
661
|
success: true,
|
|
480
662
|
activeVariant: found.id,
|
|
481
663
|
message: `PlayCanvas 场景上下文已设为 "${found.name}"。后续命令使用 --variant ${found.id} 来操作此场景的配置。`,
|
|
664
|
+
};
|
|
665
|
+
outputResult(asJson, payload, () => {
|
|
666
|
+
console.log(`PlayCanvas 场景上下文已设为「${found.name}」 (${found.id})。`);
|
|
667
|
+
console.log(`后续命令请使用 --variant ${found.id} 操作该场景的配置。`);
|
|
482
668
|
});
|
|
483
669
|
}
|
|
484
670
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@playcraft/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.25",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"release": "node scripts/release.js"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@playcraft/build": "^0.0.
|
|
26
|
-
"@playcraft/common": "^0.0.
|
|
25
|
+
"@playcraft/build": "^0.0.25",
|
|
26
|
+
"@playcraft/common": "^0.0.14",
|
|
27
27
|
"chokidar": "^4.0.3",
|
|
28
28
|
"commander": "^13.1.0",
|
|
29
29
|
"cors": "^2.8.6",
|