@coze-arch/cli 0.0.1-alpha.3002ee → 0.0.1-alpha.6a5120
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/lib/__templates__/expo/.cozeproj/scripts/deploy_build.sh +4 -3
- package/lib/__templates__/expo/.cozeproj/scripts/deploy_run.sh +8 -40
- package/lib/__templates__/expo/_npmrc +1 -1
- package/lib/__templates__/expo/client/contexts/AuthContext.tsx +14 -107
- package/lib/__templates__/expo/client/screens/home/index.tsx +1 -4
- package/lib/__templates__/expo/client/screens/home/styles.ts +1 -273
- package/lib/__templates__/expo/client/utils/index.ts +1 -2
- package/lib/__templates__/expo/package.json +1 -1
- package/lib/__templates__/expo/pnpm-lock.yaml +87 -5
- package/lib/__templates__/expo/src/index.ts +2 -2
- package/lib/__templates__/expo/template.config.js +1 -1
- package/lib/__templates__/nextjs/.coze +3 -3
- package/lib/__templates__/nextjs/_npmrc +1 -1
- package/lib/__templates__/nextjs/package.json +8 -3
- package/lib/__templates__/nextjs/pnpm-lock.yaml +2495 -1122
- package/lib/__templates__/nextjs/scripts/dev.sh +1 -1
- package/lib/__templates__/nextjs/src/app/layout.tsx +0 -4
- package/lib/__templates__/nextjs/template.config.js +1 -1
- package/lib/__templates__/templates.json +1 -1
- package/lib/__templates__/vite/.coze +3 -3
- package/lib/__templates__/vite/README.md +204 -26
- package/lib/__templates__/vite/_npmrc +1 -1
- package/lib/__templates__/vite/template.config.js +3 -3
- package/lib/cli.js +349 -211
- package/package.json +3 -2
- package/lib/__templates__/nextjs/.babelrc +0 -15
- package/lib/__templates__/nextjs/server.mjs +0 -50
package/lib/cli.js
CHANGED
|
@@ -5,12 +5,13 @@ var commander = require('commander');
|
|
|
5
5
|
var path = require('path');
|
|
6
6
|
var fs = require('fs');
|
|
7
7
|
var shelljs = require('shelljs');
|
|
8
|
+
var perf_hooks = require('perf_hooks');
|
|
8
9
|
var fs$1 = require('fs/promises');
|
|
9
10
|
var toml = require('@iarna/toml');
|
|
10
11
|
var jsYaml = require('js-yaml');
|
|
11
|
-
var perf_hooks = require('perf_hooks');
|
|
12
12
|
var addFormats = require('ajv-formats');
|
|
13
13
|
var Ajv = require('ajv');
|
|
14
|
+
var minimist = require('minimist');
|
|
14
15
|
var changeCase = require('change-case');
|
|
15
16
|
var ejs = require('ejs');
|
|
16
17
|
|
|
@@ -269,6 +270,329 @@ const createLogger = (options = {}) =>
|
|
|
269
270
|
// 导出默认实例
|
|
270
271
|
const logger = createLogger();
|
|
271
272
|
|
|
273
|
+
/**
|
|
274
|
+
* 时间统计工具
|
|
275
|
+
*/
|
|
276
|
+
class TimeTracker {
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
constructor() {
|
|
281
|
+
this.startTime = perf_hooks.performance.now();
|
|
282
|
+
this.lastTime = this.startTime;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* 记录阶段耗时
|
|
287
|
+
* @param phaseName 阶段名称
|
|
288
|
+
*/
|
|
289
|
+
logPhase(phaseName) {
|
|
290
|
+
const now = perf_hooks.performance.now();
|
|
291
|
+
const phaseTime = now - this.lastTime;
|
|
292
|
+
this.lastTime = now;
|
|
293
|
+
|
|
294
|
+
logger.verbose(`⏱ ${phaseName}: ${phaseTime.toFixed(2)}ms`);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* 记录总耗时
|
|
299
|
+
*/
|
|
300
|
+
logTotal() {
|
|
301
|
+
const totalTime = perf_hooks.performance.now() - this.startTime;
|
|
302
|
+
logger.verbose(`⏱ Total time: ${totalTime.toFixed(2)}ms`);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* 获取当前耗时(不输出日志)
|
|
307
|
+
* @returns 从开始到现在的总耗时(毫秒)
|
|
308
|
+
*/
|
|
309
|
+
getElapsedTime() {
|
|
310
|
+
return perf_hooks.performance.now() - this.startTime;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* 获取模板配置文件路径
|
|
316
|
+
* @returns templates.json 的绝对路径
|
|
317
|
+
*/
|
|
318
|
+
const getTemplatesConfigPath = () => {
|
|
319
|
+
const configPath = path.resolve(getTemplatesDir(), 'templates.json');
|
|
320
|
+
logger.verbose(`Templates config path: ${configPath}`);
|
|
321
|
+
logger.verbose(`Config file exists: ${fs.existsSync(configPath)}`);
|
|
322
|
+
return configPath;
|
|
323
|
+
};
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* 获取模板目录路径
|
|
327
|
+
* @returns __templates__ 目录的绝对路径
|
|
328
|
+
*/
|
|
329
|
+
const getTemplatesDir = () => {
|
|
330
|
+
const templatesDir = path.resolve(__dirname, './__templates__');
|
|
331
|
+
logger.verbose(`Templates directory: ${templatesDir}`);
|
|
332
|
+
logger.verbose(`Templates directory exists: ${fs.existsSync(templatesDir)}`);
|
|
333
|
+
return templatesDir;
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
/**
|
|
337
|
+
* 加载模板配置文件
|
|
338
|
+
* 支持 .ts 和 .js 文件(通过 sucrase 注册)
|
|
339
|
+
*
|
|
340
|
+
* @param templatePath - 模板目录路径
|
|
341
|
+
* @returns 模板配置对象
|
|
342
|
+
*/
|
|
343
|
+
|
|
344
|
+
const loadTemplateConfig = async (
|
|
345
|
+
templatePath,
|
|
346
|
+
) => {
|
|
347
|
+
logger.verbose(`Loading template config from: ${templatePath}`);
|
|
348
|
+
|
|
349
|
+
const tsConfigPath = path.join(templatePath, 'template.config.ts');
|
|
350
|
+
const jsConfigPath = path.join(templatePath, 'template.config.js');
|
|
351
|
+
|
|
352
|
+
logger.verbose('Checking for config files:');
|
|
353
|
+
logger.verbose(` - TypeScript: ${tsConfigPath}`);
|
|
354
|
+
logger.verbose(` - JavaScript: ${jsConfigPath}`);
|
|
355
|
+
|
|
356
|
+
let configPath;
|
|
357
|
+
|
|
358
|
+
const [tsExists, jsExists] = await Promise.all([
|
|
359
|
+
fs$1.access(tsConfigPath).then(
|
|
360
|
+
() => true,
|
|
361
|
+
() => false,
|
|
362
|
+
),
|
|
363
|
+
fs$1.access(jsConfigPath).then(
|
|
364
|
+
() => true,
|
|
365
|
+
() => false,
|
|
366
|
+
),
|
|
367
|
+
]);
|
|
368
|
+
|
|
369
|
+
logger.verbose('Config file existence check:');
|
|
370
|
+
logger.verbose(` - template.config.ts: ${tsExists}`);
|
|
371
|
+
logger.verbose(` - template.config.js: ${jsExists}`);
|
|
372
|
+
|
|
373
|
+
if (tsExists) {
|
|
374
|
+
configPath = tsConfigPath;
|
|
375
|
+
} else if (jsExists) {
|
|
376
|
+
configPath = jsConfigPath;
|
|
377
|
+
} else {
|
|
378
|
+
throw new Error(
|
|
379
|
+
`Template config not found in ${templatePath}.\n` +
|
|
380
|
+
'Expected: template.config.ts or template.config.js',
|
|
381
|
+
);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
logger.verbose(`Using config file: ${configPath}`);
|
|
385
|
+
|
|
386
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports, security/detect-non-literal-require -- Sucrase handles .ts files at runtime, path is validated above
|
|
387
|
+
const config = require(configPath);
|
|
388
|
+
|
|
389
|
+
logger.verbose('Template config loaded successfully');
|
|
390
|
+
|
|
391
|
+
return config.default || config;
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* 加载模板列表配置
|
|
396
|
+
*
|
|
397
|
+
* @param configPath - templates.json 配置文件路径
|
|
398
|
+
* @returns 模板列表配置
|
|
399
|
+
*/
|
|
400
|
+
const loadTemplatesConfig = async (
|
|
401
|
+
configPath,
|
|
402
|
+
) => {
|
|
403
|
+
logger.verbose(`Loading templates config from: ${configPath}`);
|
|
404
|
+
|
|
405
|
+
const content = await fs$1.readFile(configPath, 'utf-8');
|
|
406
|
+
// eslint-disable-next-line no-restricted-syntax -- Static config file loaded at build time, safeJsonParse not needed
|
|
407
|
+
const config = JSON.parse(content) ;
|
|
408
|
+
|
|
409
|
+
logger.verbose(
|
|
410
|
+
`Found ${config.templates.length} templates: ${config.templates.map(t => t.name).join(', ')}`,
|
|
411
|
+
);
|
|
412
|
+
|
|
413
|
+
return config;
|
|
414
|
+
};
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* 根据模板名称查找模板元信息
|
|
418
|
+
*
|
|
419
|
+
* @param templatesConfig - 模板列表配置
|
|
420
|
+
* @param templateName - 模板名称
|
|
421
|
+
* @returns 模板元信息
|
|
422
|
+
*/
|
|
423
|
+
const findTemplate = (
|
|
424
|
+
templatesConfig,
|
|
425
|
+
templateName,
|
|
426
|
+
) => {
|
|
427
|
+
const template = templatesConfig.templates.find(t => t.name === templateName);
|
|
428
|
+
|
|
429
|
+
if (!template) {
|
|
430
|
+
const availableTemplates = templatesConfig.templates
|
|
431
|
+
.map(t => t.name)
|
|
432
|
+
.join(', ');
|
|
433
|
+
throw new Error(
|
|
434
|
+
`Template "${templateName}" not found.\n` +
|
|
435
|
+
`Available templates: ${availableTemplates}\n` +
|
|
436
|
+
'Use --template <name> to specify a template.',
|
|
437
|
+
);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
return template;
|
|
441
|
+
};
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* 获取模板的完整路径
|
|
445
|
+
*
|
|
446
|
+
* @param basePath - 模板目录(templates.json 所在目录)
|
|
447
|
+
* @param templateMetadata - 模板元信息
|
|
448
|
+
* @returns 模板完整路径
|
|
449
|
+
*/
|
|
450
|
+
const getTemplatePath = async (
|
|
451
|
+
basePath,
|
|
452
|
+
templateMetadata,
|
|
453
|
+
) => {
|
|
454
|
+
logger.verbose('Resolving template path:');
|
|
455
|
+
logger.verbose(` - Base path: ${basePath}`);
|
|
456
|
+
logger.verbose(` - Template location: ${templateMetadata.location}`);
|
|
457
|
+
|
|
458
|
+
// location 是相对于 templates.json 文件的路径
|
|
459
|
+
const templatePath = path.join(basePath, templateMetadata.location);
|
|
460
|
+
|
|
461
|
+
logger.verbose(` - Resolved path: ${templatePath}`);
|
|
462
|
+
|
|
463
|
+
try {
|
|
464
|
+
await fs$1.access(templatePath);
|
|
465
|
+
logger.verbose(' - Template directory exists: ✓');
|
|
466
|
+
// eslint-disable-next-line @coze-arch/use-error-in-catch -- Error handling done in throw statement
|
|
467
|
+
} catch (e) {
|
|
468
|
+
logger.error(' - Template directory does not exist: ✗');
|
|
469
|
+
throw new Error(`Template directory not found: ${templatePath}`);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
return templatePath;
|
|
473
|
+
};
|
|
474
|
+
|
|
475
|
+
/**
|
|
476
|
+
* 对单个模板执行 pnpm install
|
|
477
|
+
*/
|
|
478
|
+
const warmupTemplate = (templatePath, templateName) => {
|
|
479
|
+
logger.info(`\nWarming up template: ${templateName}`);
|
|
480
|
+
logger.info(` Path: ${templatePath}`);
|
|
481
|
+
|
|
482
|
+
const result = shelljs.exec('pnpm install', {
|
|
483
|
+
cwd: templatePath,
|
|
484
|
+
silent: true,
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
// 输出 stdout
|
|
488
|
+
if (result.stdout) {
|
|
489
|
+
process.stdout.write(result.stdout);
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// 输出 stderr
|
|
493
|
+
if (result.stderr) {
|
|
494
|
+
process.stderr.write(result.stderr);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
if (result.code === 0) {
|
|
498
|
+
logger.success(` ✓ ${templateName} warmed up successfully`);
|
|
499
|
+
} else {
|
|
500
|
+
const errorMessage = [
|
|
501
|
+
`pnpm install failed for ${templateName} with exit code ${result.code}`,
|
|
502
|
+
result.stderr ? `\nStderr:\n${result.stderr}` : '',
|
|
503
|
+
result.stdout ? `\nStdout:\n${result.stdout}` : '',
|
|
504
|
+
]
|
|
505
|
+
.filter(Boolean)
|
|
506
|
+
.join('');
|
|
507
|
+
|
|
508
|
+
throw new Error(errorMessage);
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
/**
|
|
513
|
+
* 执行 warmup 命令的内部实现
|
|
514
|
+
*/
|
|
515
|
+
const executeWarmup = async (
|
|
516
|
+
options
|
|
517
|
+
|
|
518
|
+
,
|
|
519
|
+
|
|
520
|
+
command,
|
|
521
|
+
) => {
|
|
522
|
+
const timer = new TimeTracker();
|
|
523
|
+
|
|
524
|
+
try {
|
|
525
|
+
const { template: templateFilter } = options;
|
|
526
|
+
|
|
527
|
+
logger.info('Starting template warmup...');
|
|
528
|
+
timer.logPhase('Initialization');
|
|
529
|
+
|
|
530
|
+
// 加载模板配置
|
|
531
|
+
const configPath = getTemplatesConfigPath();
|
|
532
|
+
const templatesConfig = await loadTemplatesConfig(configPath);
|
|
533
|
+
|
|
534
|
+
logger.verbose(
|
|
535
|
+
`Found ${templatesConfig.templates.length} templates in config`,
|
|
536
|
+
);
|
|
537
|
+
|
|
538
|
+
// 过滤模板
|
|
539
|
+
const templatesToWarmup = templateFilter
|
|
540
|
+
? templatesConfig.templates.filter(t => t.name === templateFilter)
|
|
541
|
+
: templatesConfig.templates;
|
|
542
|
+
|
|
543
|
+
if (templatesToWarmup.length === 0) {
|
|
544
|
+
if (templateFilter) {
|
|
545
|
+
logger.warn(`Template "${templateFilter}" not found`);
|
|
546
|
+
logger.info(
|
|
547
|
+
`Available templates: ${templatesConfig.templates.map(t => t.name).join(', ')}`,
|
|
548
|
+
);
|
|
549
|
+
} else {
|
|
550
|
+
logger.warn('No templates found');
|
|
551
|
+
}
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
logger.info(
|
|
556
|
+
`\nWill warm up ${templatesToWarmup.length} template(s): ${templatesToWarmup.map(t => t.name).join(', ')}`,
|
|
557
|
+
);
|
|
558
|
+
|
|
559
|
+
// 获取模板基础路径
|
|
560
|
+
const basePath = configPath.replace(/\/templates\.json$/, '');
|
|
561
|
+
|
|
562
|
+
// 对每个模板执行 pnpm install
|
|
563
|
+
for (const templateMetadata of templatesToWarmup) {
|
|
564
|
+
const templatePath = await getTemplatePath(basePath, templateMetadata);
|
|
565
|
+
warmupTemplate(templatePath, templateMetadata.name);
|
|
566
|
+
timer.logPhase(`Warmup ${templateMetadata.name}`);
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
logger.success('\n✅ All templates warmed up successfully!');
|
|
570
|
+
logger.info(
|
|
571
|
+
'\nNext time you run `coze init`, it will be much faster as node_modules are pre-installed.',
|
|
572
|
+
);
|
|
573
|
+
|
|
574
|
+
timer.logTotal();
|
|
575
|
+
} catch (error) {
|
|
576
|
+
timer.logTotal();
|
|
577
|
+
logger.error('Failed to warmup templates:');
|
|
578
|
+
logger.error(error instanceof Error ? error.message : String(error));
|
|
579
|
+
process.exit(1);
|
|
580
|
+
}
|
|
581
|
+
};
|
|
582
|
+
|
|
583
|
+
/**
|
|
584
|
+
* 注册 warmup 命令到 program
|
|
585
|
+
*/
|
|
586
|
+
const registerCommand$2 = program => {
|
|
587
|
+
program
|
|
588
|
+
.command('warmup')
|
|
589
|
+
.description('Pre-install dependencies for templates to speed up init')
|
|
590
|
+
.option('-t, --template <name>', 'Warmup a specific template only')
|
|
591
|
+
.action(async (options, command) => {
|
|
592
|
+
await executeWarmup(options);
|
|
593
|
+
});
|
|
594
|
+
};
|
|
595
|
+
|
|
272
596
|
function _optionalChain$3(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
273
597
|
// Safe JSON parsing utilities with type safety and error handling
|
|
274
598
|
// Provides fallback values, validation, and error monitoring capabilities
|
|
@@ -628,69 +952,6 @@ const registerCommand$1 = program => {
|
|
|
628
952
|
});
|
|
629
953
|
};
|
|
630
954
|
|
|
631
|
-
/**
|
|
632
|
-
* 时间统计工具
|
|
633
|
-
*/
|
|
634
|
-
class TimeTracker {
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
constructor() {
|
|
639
|
-
this.startTime = perf_hooks.performance.now();
|
|
640
|
-
this.lastTime = this.startTime;
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
/**
|
|
644
|
-
* 记录阶段耗时
|
|
645
|
-
* @param phaseName 阶段名称
|
|
646
|
-
*/
|
|
647
|
-
logPhase(phaseName) {
|
|
648
|
-
const now = perf_hooks.performance.now();
|
|
649
|
-
const phaseTime = now - this.lastTime;
|
|
650
|
-
this.lastTime = now;
|
|
651
|
-
|
|
652
|
-
logger.verbose(`⏱ ${phaseName}: ${phaseTime.toFixed(2)}ms`);
|
|
653
|
-
}
|
|
654
|
-
|
|
655
|
-
/**
|
|
656
|
-
* 记录总耗时
|
|
657
|
-
*/
|
|
658
|
-
logTotal() {
|
|
659
|
-
const totalTime = perf_hooks.performance.now() - this.startTime;
|
|
660
|
-
logger.verbose(`⏱ Total time: ${totalTime.toFixed(2)}ms`);
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
/**
|
|
664
|
-
* 获取当前耗时(不输出日志)
|
|
665
|
-
* @returns 从开始到现在的总耗时(毫秒)
|
|
666
|
-
*/
|
|
667
|
-
getElapsedTime() {
|
|
668
|
-
return perf_hooks.performance.now() - this.startTime;
|
|
669
|
-
}
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
/**
|
|
673
|
-
* 获取模板配置文件路径
|
|
674
|
-
* @returns templates.json 的绝对路径
|
|
675
|
-
*/
|
|
676
|
-
const getTemplatesConfigPath = () => {
|
|
677
|
-
const configPath = path.resolve(getTemplatesDir(), 'templates.json');
|
|
678
|
-
logger.verbose(`Templates config path: ${configPath}`);
|
|
679
|
-
logger.verbose(`Config file exists: ${fs.existsSync(configPath)}`);
|
|
680
|
-
return configPath;
|
|
681
|
-
};
|
|
682
|
-
|
|
683
|
-
/**
|
|
684
|
-
* 获取模板目录路径
|
|
685
|
-
* @returns __templates__ 目录的绝对路径
|
|
686
|
-
*/
|
|
687
|
-
const getTemplatesDir = () => {
|
|
688
|
-
const templatesDir = path.resolve(__dirname, './__templates__');
|
|
689
|
-
logger.verbose(`Templates directory: ${templatesDir}`);
|
|
690
|
-
logger.verbose(`Templates directory exists: ${fs.existsSync(templatesDir)}`);
|
|
691
|
-
return templatesDir;
|
|
692
|
-
};
|
|
693
|
-
|
|
694
955
|
/**
|
|
695
956
|
* 创建 AJV 验证器实例
|
|
696
957
|
*/
|
|
@@ -739,149 +1000,12 @@ const validateParams = (
|
|
|
739
1000
|
return params ;
|
|
740
1001
|
};
|
|
741
1002
|
|
|
742
|
-
/**
|
|
743
|
-
* 加载模板配置文件
|
|
744
|
-
* 支持 .ts 和 .js 文件(通过 sucrase 注册)
|
|
745
|
-
*
|
|
746
|
-
* @param templatePath - 模板目录路径
|
|
747
|
-
* @returns 模板配置对象
|
|
748
|
-
*/
|
|
749
|
-
|
|
750
|
-
const loadTemplateConfig = async (
|
|
751
|
-
templatePath,
|
|
752
|
-
) => {
|
|
753
|
-
logger.verbose(`Loading template config from: ${templatePath}`);
|
|
754
|
-
|
|
755
|
-
const tsConfigPath = path.join(templatePath, 'template.config.ts');
|
|
756
|
-
const jsConfigPath = path.join(templatePath, 'template.config.js');
|
|
757
|
-
|
|
758
|
-
logger.verbose('Checking for config files:');
|
|
759
|
-
logger.verbose(` - TypeScript: ${tsConfigPath}`);
|
|
760
|
-
logger.verbose(` - JavaScript: ${jsConfigPath}`);
|
|
761
|
-
|
|
762
|
-
let configPath;
|
|
763
|
-
|
|
764
|
-
const [tsExists, jsExists] = await Promise.all([
|
|
765
|
-
fs$1.access(tsConfigPath).then(
|
|
766
|
-
() => true,
|
|
767
|
-
() => false,
|
|
768
|
-
),
|
|
769
|
-
fs$1.access(jsConfigPath).then(
|
|
770
|
-
() => true,
|
|
771
|
-
() => false,
|
|
772
|
-
),
|
|
773
|
-
]);
|
|
774
|
-
|
|
775
|
-
logger.verbose('Config file existence check:');
|
|
776
|
-
logger.verbose(` - template.config.ts: ${tsExists}`);
|
|
777
|
-
logger.verbose(` - template.config.js: ${jsExists}`);
|
|
778
|
-
|
|
779
|
-
if (tsExists) {
|
|
780
|
-
configPath = tsConfigPath;
|
|
781
|
-
} else if (jsExists) {
|
|
782
|
-
configPath = jsConfigPath;
|
|
783
|
-
} else {
|
|
784
|
-
throw new Error(
|
|
785
|
-
`Template config not found in ${templatePath}.\n` +
|
|
786
|
-
'Expected: template.config.ts or template.config.js',
|
|
787
|
-
);
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
logger.verbose(`Using config file: ${configPath}`);
|
|
791
|
-
|
|
792
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports, security/detect-non-literal-require -- Sucrase handles .ts files at runtime, path is validated above
|
|
793
|
-
const config = require(configPath);
|
|
794
|
-
|
|
795
|
-
logger.verbose('Template config loaded successfully');
|
|
796
|
-
|
|
797
|
-
return config.default || config;
|
|
798
|
-
};
|
|
799
|
-
|
|
800
|
-
/**
|
|
801
|
-
* 加载模板列表配置
|
|
802
|
-
*
|
|
803
|
-
* @param configPath - templates.json 配置文件路径
|
|
804
|
-
* @returns 模板列表配置
|
|
805
|
-
*/
|
|
806
|
-
const loadTemplatesConfig = async (
|
|
807
|
-
configPath,
|
|
808
|
-
) => {
|
|
809
|
-
logger.verbose(`Loading templates config from: ${configPath}`);
|
|
810
|
-
|
|
811
|
-
const content = await fs$1.readFile(configPath, 'utf-8');
|
|
812
|
-
// eslint-disable-next-line no-restricted-syntax -- Static config file loaded at build time, safeJsonParse not needed
|
|
813
|
-
const config = JSON.parse(content) ;
|
|
814
|
-
|
|
815
|
-
logger.verbose(
|
|
816
|
-
`Found ${config.templates.length} templates: ${config.templates.map(t => t.name).join(', ')}`,
|
|
817
|
-
);
|
|
818
|
-
|
|
819
|
-
return config;
|
|
820
|
-
};
|
|
821
|
-
|
|
822
|
-
/**
|
|
823
|
-
* 根据模板名称查找模板元信息
|
|
824
|
-
*
|
|
825
|
-
* @param templatesConfig - 模板列表配置
|
|
826
|
-
* @param templateName - 模板名称
|
|
827
|
-
* @returns 模板元信息
|
|
828
|
-
*/
|
|
829
|
-
const findTemplate = (
|
|
830
|
-
templatesConfig,
|
|
831
|
-
templateName,
|
|
832
|
-
) => {
|
|
833
|
-
const template = templatesConfig.templates.find(t => t.name === templateName);
|
|
834
|
-
|
|
835
|
-
if (!template) {
|
|
836
|
-
const availableTemplates = templatesConfig.templates
|
|
837
|
-
.map(t => t.name)
|
|
838
|
-
.join(', ');
|
|
839
|
-
throw new Error(
|
|
840
|
-
`Template "${templateName}" not found.\n` +
|
|
841
|
-
`Available templates: ${availableTemplates}\n` +
|
|
842
|
-
'Use --template <name> to specify a template.',
|
|
843
|
-
);
|
|
844
|
-
}
|
|
845
|
-
|
|
846
|
-
return template;
|
|
847
|
-
};
|
|
848
|
-
|
|
849
|
-
/**
|
|
850
|
-
* 获取模板的完整路径
|
|
851
|
-
*
|
|
852
|
-
* @param basePath - 模板目录(templates.json 所在目录)
|
|
853
|
-
* @param templateMetadata - 模板元信息
|
|
854
|
-
* @returns 模板完整路径
|
|
855
|
-
*/
|
|
856
|
-
const getTemplatePath = async (
|
|
857
|
-
basePath,
|
|
858
|
-
templateMetadata,
|
|
859
|
-
) => {
|
|
860
|
-
logger.verbose('Resolving template path:');
|
|
861
|
-
logger.verbose(` - Base path: ${basePath}`);
|
|
862
|
-
logger.verbose(` - Template location: ${templateMetadata.location}`);
|
|
863
|
-
|
|
864
|
-
// location 是相对于 templates.json 文件的路径
|
|
865
|
-
const templatePath = path.join(basePath, templateMetadata.location);
|
|
866
|
-
|
|
867
|
-
logger.verbose(` - Resolved path: ${templatePath}`);
|
|
868
|
-
|
|
869
|
-
try {
|
|
870
|
-
await fs$1.access(templatePath);
|
|
871
|
-
logger.verbose(' - Template directory exists: ✓');
|
|
872
|
-
// eslint-disable-next-line @coze-arch/use-error-in-catch -- Error handling done in throw statement
|
|
873
|
-
} catch (e) {
|
|
874
|
-
logger.error(' - Template directory does not exist: ✗');
|
|
875
|
-
throw new Error(`Template directory not found: ${templatePath}`);
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
return templatePath;
|
|
879
|
-
};
|
|
880
|
-
|
|
881
1003
|
/**
|
|
882
1004
|
* 从 Commander 解析透传参数
|
|
883
1005
|
* 将 kebab-case 的 CLI 参数转换为 camelCase
|
|
884
1006
|
*
|
|
1007
|
+
* 使用 minimist 解析 process.argv,自动处理类型转换
|
|
1008
|
+
*
|
|
885
1009
|
* @param command - Commander 命令实例
|
|
886
1010
|
* @param knownOptions - 已知的选项集合(不需要透传的选项)
|
|
887
1011
|
* @returns 参数对象
|
|
@@ -890,20 +1014,34 @@ const parsePassThroughParams = (
|
|
|
890
1014
|
command,
|
|
891
1015
|
knownOptions = new Set(),
|
|
892
1016
|
) => {
|
|
893
|
-
|
|
1017
|
+
// 使用 minimist 解析所有参数
|
|
1018
|
+
// eslint-disable-next-line @typescript-eslint/no-magic-numbers -- slice(2) to skip node and script path
|
|
1019
|
+
const parsed = minimist(process.argv.slice(2));
|
|
894
1020
|
|
|
895
|
-
|
|
896
|
-
|
|
1021
|
+
// 过滤掉已知选项和位置参数(_)
|
|
1022
|
+
const filtered = Object.entries(parsed).reduce(
|
|
897
1023
|
(params, [key, value]) => {
|
|
898
|
-
|
|
1024
|
+
// 跳过 minimist 的位置参数数组
|
|
1025
|
+
if (key === '_') {
|
|
899
1026
|
return params;
|
|
900
1027
|
}
|
|
901
1028
|
|
|
1029
|
+
// 跳过已知选项(支持原始格式和 camelCase 格式)
|
|
1030
|
+
if (knownOptions.has(key) || knownOptions.has(changeCase.camelCase(key))) {
|
|
1031
|
+
return params;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
// 将 kebab-case 转换为 camelCase
|
|
902
1035
|
const camelKey = changeCase.camelCase(key);
|
|
903
|
-
|
|
1036
|
+
// eslint-disable-next-line security/detect-object-injection -- camelKey is sanitized by camelCase
|
|
1037
|
+
params[camelKey] = value;
|
|
1038
|
+
|
|
1039
|
+
return params;
|
|
904
1040
|
},
|
|
905
|
-
|
|
1041
|
+
{},
|
|
906
1042
|
);
|
|
1043
|
+
|
|
1044
|
+
return filtered;
|
|
907
1045
|
};
|
|
908
1046
|
|
|
909
1047
|
/**
|
|
@@ -1581,14 +1719,14 @@ const registerCommand = program => {
|
|
|
1581
1719
|
});
|
|
1582
1720
|
};
|
|
1583
1721
|
|
|
1584
|
-
var version = "0.0.1-alpha.
|
|
1722
|
+
var version = "0.0.1-alpha.6a5120";
|
|
1585
1723
|
var packageJson = {
|
|
1586
1724
|
version: version};
|
|
1587
1725
|
|
|
1588
1726
|
const commands = [
|
|
1589
1727
|
registerCommand,
|
|
1590
1728
|
registerCommand$1,
|
|
1591
|
-
|
|
1729
|
+
registerCommand$2,
|
|
1592
1730
|
];
|
|
1593
1731
|
|
|
1594
1732
|
const main = () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coze-arch/cli",
|
|
3
|
-
"version": "0.0.1-alpha.
|
|
3
|
+
"version": "0.0.1-alpha.6a5120",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "coze coding devtools cli",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,7 +19,6 @@
|
|
|
19
19
|
"scripts": {
|
|
20
20
|
"prebuild": "tsx scripts/prebuild.ts",
|
|
21
21
|
"build": "tsx scripts/build.ts",
|
|
22
|
-
"generate-templates": "tsx scripts/generate-templates-config.ts",
|
|
23
22
|
"lint": "eslint ./ --cache",
|
|
24
23
|
"postpublish": "bash scripts/sync-npmmirror.sh",
|
|
25
24
|
"test": "vitest --run --passWithNoTests",
|
|
@@ -38,6 +37,7 @@
|
|
|
38
37
|
"commander": "~12.1.0",
|
|
39
38
|
"ejs": "^3.1.10",
|
|
40
39
|
"js-yaml": "^4.1.0",
|
|
40
|
+
"minimist": "^1.2.5",
|
|
41
41
|
"shelljs": "^0.10.0"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
@@ -51,6 +51,7 @@
|
|
|
51
51
|
"@types/ejs": "^3.1.5",
|
|
52
52
|
"@types/iarna__toml": "^2.0.5",
|
|
53
53
|
"@types/js-yaml": "^4.0.9",
|
|
54
|
+
"@types/minimist": "^1.2.5",
|
|
54
55
|
"@types/node": "^24",
|
|
55
56
|
"@types/shelljs": "^0.10.0",
|
|
56
57
|
"@vitest/coverage-v8": "~4.0.16",
|