@nasl/cli 0.3.2 → 0.3.4

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/bin/nasl.mjs CHANGED
@@ -29148,7 +29148,7 @@ async function createAxios(options) {
29148
29148
  const instance = axios.create({
29149
29149
  baseURL,
29150
29150
  headers,
29151
- timeout: 120000,
29151
+ timeout: 480000,
29152
29152
  });
29153
29153
  const oldPost = instance.post;
29154
29154
  instance.post = async (url, data, config) => {
@@ -29227,41 +29227,33 @@ async function checkApi(fullNaturalTS, options) {
29227
29227
  }
29228
29228
 
29229
29229
  /**
29230
- * 创建应用同步
29230
+ * 创建应用(POST /nasl/app/create)
29231
29231
  */
29232
- async function createAppSyncApi(fullNaturalTS, options) {
29233
- const url = new URL(options.serverBaseURL);
29234
- const origin = url.origin + '/app-ai-creator';
29235
- const axios = await createAxios({ serverBaseURL: origin, ideVersion: options.ideVersion });
29236
- try {
29237
- const res = await axios.post('/api/createAppSync', {
29238
- fullNaturalTS,
29239
- packageName: options.packageName,
29240
- appName: options.appName,
29241
- hostname: url.hostname,
29242
- enableAuthTemplate: false,
29243
- ideVersion: options.ideVersion,
29244
- fullVersion: `${options.ideVersion}.0`,
29245
- });
29246
- if (res.data.success) {
29247
- return {
29248
- success: true,
29249
- appId: res.data.data?.appId,
29250
- appURL: res.data.data?.appURL,
29251
- message: res.data.data?.message,
29252
- };
29253
- }
29254
- else {
29255
- return {
29256
- success: false,
29257
- error: res.data.message || '应用创建失败',
29258
- };
29259
- }
29260
- }
29261
- catch (error) {
29262
- console.log(error);
29263
- throw error;
29264
- }
29232
+ async function createApp(fullNaturalTS, options, appName, packageName) {
29233
+ const axiosInstance = await createAxios(options);
29234
+ const res = await axiosInstance.post('/app/create', {
29235
+ fullNaturalTS,
29236
+ packageName,
29237
+ appName,
29238
+ ideVersion: options.ideVersion,
29239
+ }, {
29240
+ headers: { ...buildNaslHeaders(options), 'Content-Type': 'application/json' },
29241
+ });
29242
+ return res.data.result;
29243
+ }
29244
+ /**
29245
+ * 更新应用(POST /nasl/app/update)
29246
+ */
29247
+ async function updateApp(fullNaturalTS, options, appId) {
29248
+ const axiosInstance = await createAxios(options);
29249
+ const res = await axiosInstance.post('/app/update', {
29250
+ fullNaturalTS,
29251
+ appId,
29252
+ ideVersion: options.ideVersion,
29253
+ }, {
29254
+ headers: { ...buildNaslHeaders(options), 'Content-Type': 'application/json' },
29255
+ });
29256
+ return res.data.result;
29265
29257
  }
29266
29258
 
29267
29259
  async function installDependenciesApi(dependenciesJSON, options) {
@@ -38935,78 +38927,94 @@ async function build(entry, options) {
38935
38927
  }
38936
38928
 
38937
38929
  /**
38938
- * 获取 specs 下第1个文件夹的名字
38930
+ * specs/ 目录取第一个子文件夹名;若无则退回项目根目录名
38939
38931
  */
38940
- function getFirstSpecFolderName(projectRoot) {
38941
- const dirname = path$1.basename(projectRoot);
38932
+ function getSpecBaseName(projectRoot) {
38942
38933
  const specsDir = path$1.join(projectRoot, 'specs');
38943
- if (!libExports.existsSync(specsDir))
38944
- return dirname;
38945
- const entries = libExports.readdirSync(specsDir, { withFileTypes: true });
38946
- const folders = entries
38947
- .filter(entry => entry.isDirectory())
38948
- .map(entry => entry.name);
38949
- if (folders.length === 0)
38950
- return dirname;
38951
- return folders[0];
38934
+ if (libExports.existsSync(specsDir)) {
38935
+ const folders = libExports.readdirSync(specsDir, { withFileTypes: true })
38936
+ .filter(e => e.isDirectory())
38937
+ .map(e => e.name);
38938
+ if (folders.length > 0)
38939
+ return folders[0];
38940
+ }
38941
+ return path$1.basename(projectRoot);
38952
38942
  }
38953
38943
  /**
38954
- * 创建应用在 IDE 中
38944
+ * 从项目目录推导出合法的应用名称和包名
38945
+ */
38946
+ function deriveAppNames(projectRoot) {
38947
+ const baseName = getSpecBaseName(projectRoot);
38948
+ const suffix = dayjs().format('MMDDHHmmss');
38949
+ let cleaned = baseName.replace(/[^a-zA-Z0-9]/g, '').replace(/^\d+/, '').slice(0, 12);
38950
+ if (!cleaned)
38951
+ cleaned = 'app';
38952
+ return {
38953
+ appName: `${cleaned}_${suffix}`,
38954
+ packageName: `${cleaned}${suffix}`,
38955
+ };
38956
+ }
38957
+
38958
+ /**
38959
+ * 使用 readline 询问用户确认
38955
38960
  */
38961
+ function askForConfirmation(question) {
38962
+ const rl = readline.createInterface({
38963
+ input: process.stdin,
38964
+ output: process.stdout,
38965
+ });
38966
+ return new Promise((resolve) => {
38967
+ rl.question(question, (answer) => {
38968
+ rl.close();
38969
+ const a = answer.trim().toLowerCase();
38970
+ resolve(!a || a === 'y' || a === 'yes' || a === '是');
38971
+ });
38972
+ });
38973
+ }
38974
+
38956
38975
  async function createAppInIde(entry, options) {
38957
38976
  const logger = options?.logger || defaultLogger;
38958
- logger.info('开始创建应用在 IDE 中...');
38959
- // 收集需要处理的文件
38960
- const { collectedFiles, config } = await resolveNASLFiles(entry, logger, false, options?.verbose);
38961
- if (config.useOPENAPI) {
38962
- logger.error('create-app-in-ide 暂不支持 useOPENAPI 模式');
38963
- logger.exit(1);
38977
+ // ── 扫描 ─────────────────────────────────────────────
38978
+ const { collectedFiles, config, mergedDependencies } = await resolveNASLFiles(entry, logger, false, options?.verbose);
38979
+ // ── 展示参数 ──────────────────────────────────────────
38980
+ const { appName, packageName } = deriveAppNames(getProjectRoot());
38981
+ logger.newLine();
38982
+ logger.info(`应用名称: ${appName}`);
38983
+ logger.info(`包名: ${packageName}`);
38984
+ logger.info(`IDE 版本: ${config.ideVersion}`);
38985
+ logger.info(`租户名称: ${config.tenantName || 'defaulttenant'}`);
38986
+ // ── 确认 ──────────────────────────────────────────────
38987
+ if (!options?.quiet) {
38988
+ logger.newLine();
38989
+ const confirmed = await askForConfirmation('即将在 IDE 中创建新的应用,请确认是否继续?(Y/n): ');
38990
+ if (!confirmed) {
38991
+ logger.info('已取消操作');
38992
+ process.exit(0);
38993
+ }
38964
38994
  }
38965
- // 生成 fullNaturalTS
38995
+ // ── 执行 ──────────────────────────────────────────────
38966
38996
  logger.newLine();
38967
38997
  logger.info('正在生成 NaturalTS 代码...');
38968
- let fullNaturalTS = '';
38998
+ let fullNaturalTS;
38969
38999
  try {
38970
39000
  fullNaturalTS = composeToString(collectedFiles);
39001
+ fullNaturalTS = prependDependencies(fullNaturalTS, mergedDependencies);
38971
39002
  }
38972
39003
  catch (error) {
38973
39004
  logger.error(`生成 NaturalTS 代码失败: ${error.message}`);
38974
39005
  throw error;
38975
39006
  }
38976
- // 获取 specs 下第1个文件夹
38977
- const projectRoot = getProjectRoot();
38978
- const firstSpecFolderName = getFirstSpecFolderName(projectRoot);
38979
- const suffix = dayjs().format('MMDDHHmmss');
38980
- let cleaned = firstSpecFolderName.replace(/[^a-zA-Z0-9]/g, '').replace(/^\d+/, '').slice(0, 12);
38981
- if (!cleaned)
38982
- cleaned = 'app';
38983
- const appName = `${cleaned}_${suffix}`;
38984
- const packageName = `${cleaned}${suffix}`;
38985
- logger.info(`应用名称: ${appName}`);
38986
- logger.info(`包名: ${packageName}`);
38987
- logger.info(`IDE 版本: ${config.ideVersion}`);
38988
- logger.info(`完整版本: ${config.ideVersion}.0`);
38989
- // 调用创建应用 API
38990
- logger.newLine();
38991
39007
  logger.info('正在调用创建应用服务...');
38992
39008
  try {
38993
- const result = await createAppSyncApi(fullNaturalTS, {
38994
- packageName: packageName,
38995
- appName: appName,
38996
- serverBaseURL: config.serverBaseURL,
38997
- ideVersion: config.ideVersion,
38998
- });
39009
+ const result = await createApp(fullNaturalTS, config, appName, packageName);
38999
39010
  if (result.success) {
39000
39011
  logger.success('应用创建成功!');
39001
- if (result.appURL) {
39012
+ if (result.appURL)
39002
39013
  logger.info(`应用 URL: ${result.appURL}`);
39003
- }
39004
- if (result.appId) {
39014
+ if (result.appId)
39005
39015
  logger.info(`应用 ID: ${result.appId}`);
39006
- }
39007
- if (result.message) {
39016
+ if (result.message)
39008
39017
  logger.info(result.message);
39009
- }
39010
39018
  }
39011
39019
  else {
39012
39020
  logger.error(`应用创建失败: ${result.error || '未知错误'}`);
@@ -39019,6 +39027,57 @@ async function createAppInIde(entry, options) {
39019
39027
  }
39020
39028
  }
39021
39029
 
39030
+ async function updateAppInIde(appId, entry, options) {
39031
+ const logger = options?.logger || defaultLogger;
39032
+ // ── 扫描 ─────────────────────────────────────────────
39033
+ const { collectedFiles, config, mergedDependencies } = await resolveNASLFiles(entry, logger, false, options?.verbose);
39034
+ // ── 展示参数 ──────────────────────────────────────────
39035
+ logger.newLine();
39036
+ logger.info(`应用 ID: ${appId}`);
39037
+ logger.info(`IDE 版本: ${config.ideVersion}`);
39038
+ logger.info(`租户名称: ${config.tenantName || 'defaulttenant'}`);
39039
+ // ── 确认 ──────────────────────────────────────────────
39040
+ if (!options?.quiet) {
39041
+ logger.newLine();
39042
+ const confirmed = await askForConfirmation(`即将更新应用 ${appId},请确认是否继续?(Y/n): `);
39043
+ if (!confirmed) {
39044
+ logger.info('已取消操作');
39045
+ process.exit(0);
39046
+ }
39047
+ }
39048
+ // ── 执行 ──────────────────────────────────────────────
39049
+ logger.newLine();
39050
+ logger.info('正在生成 NaturalTS 代码...');
39051
+ let fullNaturalTS;
39052
+ try {
39053
+ fullNaturalTS = composeToString(collectedFiles);
39054
+ fullNaturalTS = prependDependencies(fullNaturalTS, mergedDependencies);
39055
+ }
39056
+ catch (error) {
39057
+ logger.error(`生成 NaturalTS 代码失败: ${error.message}`);
39058
+ throw error;
39059
+ }
39060
+ logger.info('正在调用更新应用服务...');
39061
+ try {
39062
+ const result = await updateApp(fullNaturalTS, config, appId);
39063
+ if (result.success) {
39064
+ logger.success('应用更新成功!');
39065
+ if (result.appURL)
39066
+ logger.info(`应用 URL: ${result.appURL}`);
39067
+ if (result.message)
39068
+ logger.info(result.message);
39069
+ }
39070
+ else {
39071
+ logger.error(`应用更新失败: ${result.error || '未知错误'}`);
39072
+ throw new Error(result.error || '应用更新失败');
39073
+ }
39074
+ }
39075
+ catch (error) {
39076
+ logger.error(`调用更新应用服务失败: ${error.message}`);
39077
+ throw error;
39078
+ }
39079
+ }
39080
+
39022
39081
  /**
39023
39082
  * 编译 NASL 代码
39024
39083
  * TODO: 实现具体的 API 调用逻辑
@@ -39384,27 +39443,11 @@ async function installByJSON(json, options) {
39384
39443
  logger.success(`成功写入 ${writtenCount} 个依赖文件到 ${config.srcDir} 目录`);
39385
39444
  }
39386
39445
 
39387
- var version = "0.3.2";
39446
+ var version = "0.3.4";
39388
39447
  var pkg = {
39389
39448
  version: version};
39390
39449
 
39391
39450
  const program = new Command();
39392
- /**
39393
- * 使用 readline 询问用户确认
39394
- */
39395
- function askForConfirmation(question) {
39396
- const rl = readline.createInterface({
39397
- input: process.stdin,
39398
- output: process.stdout,
39399
- });
39400
- return new Promise((resolve) => {
39401
- rl.question(question, (answer) => {
39402
- rl.close();
39403
- const normalizedAnswer = answer.trim().toLowerCase();
39404
- resolve(!normalizedAnswer || normalizedAnswer === 'y' || normalizedAnswer === 'yes' || normalizedAnswer === '是');
39405
- });
39406
- });
39407
- }
39408
39451
  const entryDescription = `是相对于项目根目录的路径,支持 glob 模式(注意要用引号包裹),例如:
39409
39452
  - src/app.enums.Status.ts 支持具体文件
39410
39453
  - "src/app.enums.*.ts" 表示所有枚举
@@ -39526,17 +39569,6 @@ program
39526
39569
  .option('-q, --quiet', '不询问问题')
39527
39570
  .action(async (entry, options) => {
39528
39571
  try {
39529
- // 如果不是 quiet 模式,询问用户确认
39530
- if (!options?.quiet) {
39531
- defaultLogger.newLine();
39532
- defaultLogger.info('即将在 IDE 中创建新的应用,此操作将调用远程接口。');
39533
- const confirmed = await askForConfirmation('请确认是否继续?(Y/n): ');
39534
- if (!confirmed) {
39535
- defaultLogger.info('已取消操作');
39536
- process.exit(0);
39537
- }
39538
- defaultLogger.newLine();
39539
- }
39540
39572
  await createAppInIde(entry, options);
39541
39573
  }
39542
39574
  catch (error) {
@@ -39544,6 +39576,20 @@ program
39544
39576
  process.exit(1);
39545
39577
  }
39546
39578
  });
39579
+ program
39580
+ .command('update-app-in-ide <appId> [entry]')
39581
+ .description('在 IDE 中更新已有应用')
39582
+ .option('-v, --verbose', '显示详细信息,如依赖分析树')
39583
+ .option('-q, --quiet', '不询问问题')
39584
+ .action(async (appId, entry, options) => {
39585
+ try {
39586
+ await updateAppInIde(appId, entry, options);
39587
+ }
39588
+ catch (error) {
39589
+ defaultLogger.error(`更新应用过程发生错误:${error.message}`);
39590
+ process.exit(1);
39591
+ }
39592
+ });
39547
39593
  program
39548
39594
  .command('transform <transformType> [entry]')
39549
39595
  .description('转换文件格式\n transformType: files2full (将 src 文件组合成 fullNaturalTS), json2files (将 JSON 转换为文件), files2json (将 src 文件转换为 JSON), doc2full (将 plan markdown 文档组合成 fullNaturalTS)')