@lark-apaas/fullstack-cli 1.1.6-alpha.0 → 1.1.6-alpha.2

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 +156 -72
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -279,7 +279,7 @@ async function run2(options) {
279
279
  const userProjectRoot = process.env.INIT_CWD || process.cwd();
280
280
  const __filename = fileURLToPath2(import.meta.url);
281
281
  const __dirname2 = path2.dirname(__filename);
282
- const pluginRoot = path2.resolve(__dirname2, "../../..");
282
+ const pluginRoot = path2.resolve(__dirname2, "..");
283
283
  if (userProjectRoot === pluginRoot) {
284
284
  console.log("[fullstack-cli] Skip syncing (installing plugin itself)");
285
285
  process.exit(0);
@@ -438,7 +438,7 @@ var syncCommand = {
438
438
  // src/commands/action-plugin/utils.ts
439
439
  import fs3 from "fs";
440
440
  import path3 from "path";
441
- import { spawnSync as spawnSync2 } from "child_process";
441
+ import { spawnSync as spawnSync2, execSync } from "child_process";
442
442
  var CONFIG_FILE_NAME = ".capabilityrc.json";
443
443
  function parsePluginName(input) {
444
444
  const match = input.match(/^(@[^/]+\/[^@]+)(?:@(.+))?$/);
@@ -499,19 +499,6 @@ function npmInstall(tgzPath) {
499
499
  throw new Error(`npm install failed with exit code ${result.status}`);
500
500
  }
501
501
  }
502
- function npmUninstall(pluginName) {
503
- console.log(`[action-plugin] Running npm uninstall ${pluginName}...`);
504
- const result = spawnSync2("npm", ["uninstall", pluginName], {
505
- cwd: getProjectRoot(),
506
- stdio: "inherit"
507
- });
508
- if (result.error) {
509
- throw new Error(`npm uninstall failed: ${result.error.message}`);
510
- }
511
- if (result.status !== 0) {
512
- throw new Error(`npm uninstall failed with exit code ${result.status}`);
513
- }
514
- }
515
502
  function getPackageVersion(pluginName) {
516
503
  const pkgJsonPath = path3.join(getPluginPath(pluginName), "package.json");
517
504
  if (!fs3.existsSync(pkgJsonPath)) {
@@ -525,6 +512,90 @@ function getPackageVersion(pluginName) {
525
512
  return null;
526
513
  }
527
514
  }
515
+ function readPluginPackageJson(pluginPath) {
516
+ const pkgJsonPath = path3.join(pluginPath, "package.json");
517
+ if (!fs3.existsSync(pkgJsonPath)) {
518
+ return null;
519
+ }
520
+ try {
521
+ const content = fs3.readFileSync(pkgJsonPath, "utf-8");
522
+ return JSON.parse(content);
523
+ } catch {
524
+ return null;
525
+ }
526
+ }
527
+ function extractTgzToNodeModules(tgzPath, pluginName) {
528
+ const nodeModulesPath = path3.join(getProjectRoot(), "node_modules");
529
+ const targetDir = path3.join(nodeModulesPath, pluginName);
530
+ const scopeDir = path3.dirname(targetDir);
531
+ if (!fs3.existsSync(scopeDir)) {
532
+ fs3.mkdirSync(scopeDir, { recursive: true });
533
+ }
534
+ if (fs3.existsSync(targetDir)) {
535
+ fs3.rmSync(targetDir, { recursive: true });
536
+ }
537
+ const tempDir = path3.join(nodeModulesPath, ".cache", "fullstack-cli", "extract-temp");
538
+ if (fs3.existsSync(tempDir)) {
539
+ fs3.rmSync(tempDir, { recursive: true });
540
+ }
541
+ fs3.mkdirSync(tempDir, { recursive: true });
542
+ try {
543
+ execSync(`tar -xzf "${tgzPath}" -C "${tempDir}"`, { stdio: "pipe" });
544
+ const extractedDir = path3.join(tempDir, "package");
545
+ if (fs3.existsSync(extractedDir)) {
546
+ fs3.renameSync(extractedDir, targetDir);
547
+ } else {
548
+ const files = fs3.readdirSync(tempDir);
549
+ if (files.length === 1) {
550
+ fs3.renameSync(path3.join(tempDir, files[0]), targetDir);
551
+ } else {
552
+ throw new Error("Unexpected tgz structure");
553
+ }
554
+ }
555
+ return targetDir;
556
+ } finally {
557
+ if (fs3.existsSync(tempDir)) {
558
+ fs3.rmSync(tempDir, { recursive: true });
559
+ }
560
+ }
561
+ }
562
+ function checkMissingPeerDeps(peerDeps) {
563
+ if (!peerDeps || Object.keys(peerDeps).length === 0) {
564
+ return [];
565
+ }
566
+ const missing = [];
567
+ const nodeModulesPath = path3.join(getProjectRoot(), "node_modules");
568
+ for (const [depName, _version] of Object.entries(peerDeps)) {
569
+ const depPath = path3.join(nodeModulesPath, depName);
570
+ if (!fs3.existsSync(depPath)) {
571
+ missing.push(depName);
572
+ }
573
+ }
574
+ return missing;
575
+ }
576
+ function installMissingDeps(deps) {
577
+ if (deps.length === 0) {
578
+ return;
579
+ }
580
+ console.log(`[action-plugin] Installing missing dependencies: ${deps.join(", ")}`);
581
+ const result = spawnSync2("npm", ["install", ...deps, "--no-save", "--no-package-lock"], {
582
+ cwd: getProjectRoot(),
583
+ stdio: "inherit"
584
+ });
585
+ if (result.error) {
586
+ throw new Error(`npm install failed: ${result.error.message}`);
587
+ }
588
+ if (result.status !== 0) {
589
+ throw new Error(`npm install failed with exit code ${result.status}`);
590
+ }
591
+ }
592
+ function removePluginDirectory(pluginName) {
593
+ const pluginPath = getPluginPath(pluginName);
594
+ if (fs3.existsSync(pluginPath)) {
595
+ fs3.rmSync(pluginPath, { recursive: true });
596
+ console.log(`[action-plugin] Removed ${pluginName}`);
597
+ }
598
+ }
528
599
 
529
600
  // src/commands/action-plugin/api-client.ts
530
601
  import { HttpClient as HttpClient2 } from "@lark-apaas/http-client";
@@ -665,22 +736,35 @@ async function installOne(nameWithVersion) {
665
736
  const { name, version: requestedVersion } = parsePluginName(nameWithVersion);
666
737
  try {
667
738
  console.log(`[action-plugin] Installing ${name}@${requestedVersion}...`);
668
- if (isPluginInstalled(name)) {
739
+ if (isPluginInstalled(name) && requestedVersion !== "latest") {
740
+ const info = getInstalledPluginInfo(name);
741
+ if (info && info.version === requestedVersion) {
742
+ console.log(`[action-plugin] Plugin ${name}@${requestedVersion} is already installed`);
743
+ return { name, version: info.version, success: true, skipped: true };
744
+ }
745
+ }
746
+ if (isPluginInstalled(name) && requestedVersion === "latest") {
669
747
  const info = getInstalledPluginInfo(name);
670
748
  if (info) {
671
749
  const latestInfo = await getPluginVersion(name, "latest");
672
- const latestVersion = latestInfo.version;
673
- if (info.version === latestVersion) {
750
+ if (info.version === latestInfo.version) {
674
751
  console.log(`[action-plugin] Plugin ${name} is already up to date (version: ${info.version})`);
675
752
  return { name, version: info.version, success: true, skipped: true };
676
753
  }
677
- console.log(`[action-plugin] Found newer version: ${latestVersion} (installed: ${info.version})`);
678
- console.log(`[action-plugin] Updating to ${latestVersion}...`);
754
+ console.log(`[action-plugin] Found newer version: ${latestInfo.version} (installed: ${info.version})`);
679
755
  }
680
756
  }
681
757
  const downloadResult = await downloadPlugin(name, requestedVersion);
682
758
  tgzPath = downloadResult.tgzPath;
683
- npmInstall(tgzPath);
759
+ console.log(`[action-plugin] Extracting to node_modules...`);
760
+ const pluginDir = extractTgzToNodeModules(tgzPath, name);
761
+ const pluginPkg = readPluginPackageJson(pluginDir);
762
+ if (pluginPkg?.peerDependencies) {
763
+ const missingDeps = checkMissingPeerDeps(pluginPkg.peerDependencies);
764
+ if (missingDeps.length > 0) {
765
+ installMissingDeps(missingDeps);
766
+ }
767
+ }
684
768
  const installedVersion = getPackageVersion(name) || downloadResult.version;
685
769
  const config = readConfig();
686
770
  config.plugins[name] = {
@@ -812,7 +896,7 @@ async function remove(nameWithVersion) {
812
896
  console.error(`[action-plugin] Plugin ${name} is not installed`);
813
897
  process.exit(1);
814
898
  }
815
- npmUninstall(name);
899
+ removePluginDirectory(name);
816
900
  const config = readConfig();
817
901
  delete config.plugins[name];
818
902
  writeConfig(config);
@@ -917,8 +1001,8 @@ function getCapabilitiesDir() {
917
1001
  function getCapabilityPath(id) {
918
1002
  return path5.join(getCapabilitiesDir(), `${id}.json`);
919
1003
  }
920
- function getPluginManifestPath(pluginID) {
921
- return path5.join(getProjectRoot2(), "node_modules", pluginID, "manifest.json");
1004
+ function getPluginManifestPath(pluginKey) {
1005
+ return path5.join(getProjectRoot2(), "node_modules", pluginKey, "manifest.json");
922
1006
  }
923
1007
  function capabilitiesDirExists() {
924
1008
  return fs5.existsSync(getCapabilitiesDir());
@@ -950,17 +1034,17 @@ function readAllCapabilities() {
950
1034
  const ids = listCapabilityIds();
951
1035
  return ids.map((id) => readCapability(id));
952
1036
  }
953
- function readPluginManifest(pluginID) {
954
- const manifestPath = getPluginManifestPath(pluginID);
1037
+ function readPluginManifest(pluginKey) {
1038
+ const manifestPath = getPluginManifestPath(pluginKey);
955
1039
  if (!fs5.existsSync(manifestPath)) {
956
- throw new Error(`Plugin not installed: ${pluginID} (manifest.json not found)`);
1040
+ throw new Error(`Plugin not installed: ${pluginKey} (manifest.json not found)`);
957
1041
  }
958
1042
  try {
959
1043
  const content = fs5.readFileSync(manifestPath, "utf-8");
960
1044
  return JSON.parse(content);
961
1045
  } catch (error) {
962
1046
  if (error instanceof SyntaxError) {
963
- throw new Error(`Invalid JSON in plugin manifest: ${pluginID}/manifest.json`);
1047
+ throw new Error(`Invalid JSON in plugin manifest: ${pluginKey}/manifest.json`);
964
1048
  }
965
1049
  throw error;
966
1050
  }
@@ -971,19 +1055,19 @@ function isDynamicSchema(schema) {
971
1055
  function hasValidParamsSchema(paramsSchema) {
972
1056
  return paramsSchema !== void 0 && Object.keys(paramsSchema).length > 0;
973
1057
  }
974
- async function loadPlugin(pluginID) {
1058
+ async function loadPlugin(pluginKey) {
975
1059
  try {
976
- const pluginPackage = (await import(pluginID)).default;
1060
+ const pluginPackage = (await import(pluginKey)).default;
977
1061
  if (!pluginPackage || typeof pluginPackage.create !== "function") {
978
- throw new Error(`Plugin ${pluginID} does not export a valid create function`);
1062
+ throw new Error(`Plugin ${pluginKey} does not export a valid create function`);
979
1063
  }
980
1064
  return pluginPackage;
981
1065
  } catch (error) {
982
1066
  if (error.code === "MODULE_NOT_FOUND") {
983
- throw new Error(`Plugin not installed: ${pluginID}`);
1067
+ throw new Error(`Plugin not installed: ${pluginKey}`);
984
1068
  }
985
1069
  throw new Error(
986
- `Failed to load plugin ${pluginID}: ${error instanceof Error ? error.message : String(error)}`
1070
+ `Failed to load plugin ${pluginKey}: ${error instanceof Error ? error.message : String(error)}`
987
1071
  );
988
1072
  }
989
1073
  }
@@ -997,16 +1081,16 @@ async function zodToJsonSchema(zodSchema) {
997
1081
  }
998
1082
  async function hydrateCapability(capability) {
999
1083
  try {
1000
- const manifest = readPluginManifest(capability.pluginID);
1084
+ const manifest = readPluginManifest(capability.pluginKey);
1001
1085
  if (!manifest.actions || manifest.actions.length === 0) {
1002
- throw new Error(`Plugin ${capability.pluginID} has no actions defined`);
1086
+ throw new Error(`Plugin ${capability.pluginKey} has no actions defined`);
1003
1087
  }
1004
1088
  const hasDynamicSchema = manifest.actions.some(
1005
1089
  (action) => isDynamicSchema(action.inputSchema) || isDynamicSchema(action.outputSchema)
1006
1090
  );
1007
1091
  let pluginInstance = null;
1008
1092
  if (hasDynamicSchema) {
1009
- const plugin = await loadPlugin(capability.pluginID);
1093
+ const plugin = await loadPlugin(capability.pluginKey);
1010
1094
  pluginInstance = plugin.create(capability.formValue || {});
1011
1095
  }
1012
1096
  const actions = [];
@@ -1049,7 +1133,7 @@ async function hydrateCapability(capability) {
1049
1133
  }
1050
1134
  return {
1051
1135
  id: capability.id,
1052
- pluginID: capability.pluginID,
1136
+ pluginKey: capability.pluginKey,
1053
1137
  pluginVersion: capability.pluginVersion,
1054
1138
  name: capability.name,
1055
1139
  description: capability.description,
@@ -1141,14 +1225,14 @@ function mergeMapping(customMapping) {
1141
1225
  }
1142
1226
  return { ...DEFAULT_MAPPING, ...customMapping };
1143
1227
  }
1144
- function getPluginID(sourceActionID, mapping) {
1145
- const pluginID = mapping[sourceActionID];
1146
- if (!pluginID) {
1228
+ function getPluginKey(sourceActionID, mapping) {
1229
+ const pluginKey = mapping[sourceActionID];
1230
+ if (!pluginKey) {
1147
1231
  throw new Error(
1148
1232
  `Unknown sourceActionID: "${sourceActionID}". Please provide mapping via --mapping option or add to default mapping.`
1149
1233
  );
1150
1234
  }
1151
- return pluginID;
1235
+ return pluginKey;
1152
1236
  }
1153
1237
 
1154
1238
  // src/commands/capability/migration/json-migrator/index.ts
@@ -1213,10 +1297,10 @@ function detectJsonMigration() {
1213
1297
 
1214
1298
  // src/commands/capability/migration/json-migrator/transformer.ts
1215
1299
  function transformCapability(old, mapping) {
1216
- const pluginID = getPluginID(old.sourceActionID, mapping);
1300
+ const pluginKey = getPluginKey(old.sourceActionID, mapping);
1217
1301
  return {
1218
1302
  id: old.id,
1219
- pluginID,
1303
+ pluginKey,
1220
1304
  pluginVersion: "latest",
1221
1305
  name: old.name,
1222
1306
  description: old.desc,
@@ -1267,7 +1351,7 @@ async function migrateJsonFiles(options) {
1267
1351
  if (options.dryRun) {
1268
1352
  console.log(` Would create ${newCapabilities.length} capability files:`);
1269
1353
  for (const cap of newCapabilities) {
1270
- console.log(` - ${cap.id}.json (pluginID: ${cap.pluginID})`);
1354
+ console.log(` - ${cap.id}.json (pluginKey: ${cap.pluginKey})`);
1271
1355
  }
1272
1356
  return {
1273
1357
  success: true,
@@ -1296,22 +1380,22 @@ async function migrateJsonFiles(options) {
1296
1380
 
1297
1381
  // src/commands/capability/migration/plugin-installer/detector.ts
1298
1382
  import fs8 from "fs";
1299
- function isPluginInstalled2(pluginID) {
1300
- const manifestPath = getPluginManifestPath(pluginID);
1383
+ function isPluginInstalled2(pluginKey) {
1384
+ const manifestPath = getPluginManifestPath(pluginKey);
1301
1385
  return fs8.existsSync(manifestPath);
1302
1386
  }
1303
1387
  function detectPluginsToInstall(capabilities) {
1304
- const pluginIDs = /* @__PURE__ */ new Set();
1388
+ const pluginKeys = /* @__PURE__ */ new Set();
1305
1389
  for (const cap of capabilities) {
1306
- pluginIDs.add(cap.pluginID);
1390
+ pluginKeys.add(cap.pluginKey);
1307
1391
  }
1308
1392
  const toInstall = [];
1309
1393
  const alreadyInstalled = [];
1310
- for (const pluginID of pluginIDs) {
1311
- if (isPluginInstalled2(pluginID)) {
1312
- alreadyInstalled.push(pluginID);
1394
+ for (const pluginKey of pluginKeys) {
1395
+ if (isPluginInstalled2(pluginKey)) {
1396
+ alreadyInstalled.push(pluginKey);
1313
1397
  } else {
1314
- toInstall.push(pluginID);
1398
+ toInstall.push(pluginKey);
1315
1399
  }
1316
1400
  }
1317
1401
  return { toInstall, alreadyInstalled };
@@ -1330,15 +1414,15 @@ async function installPlugins(capabilities, options) {
1330
1414
  }
1331
1415
  if (options.dryRun) {
1332
1416
  console.log(` Would install ${detection.toInstall.length} plugins:`);
1333
- for (const pluginID of detection.toInstall) {
1334
- console.log(` - ${pluginID}`);
1417
+ for (const pluginKey of detection.toInstall) {
1418
+ console.log(` - ${pluginKey}`);
1335
1419
  }
1336
1420
  result.installed = detection.toInstall;
1337
1421
  return result;
1338
1422
  }
1339
1423
  console.log(` \u2B07 Installing ${detection.toInstall.length} plugins...`);
1340
- for (const pluginID of detection.toInstall) {
1341
- console.log(` - ${pluginID}`);
1424
+ for (const pluginKey of detection.toInstall) {
1425
+ console.log(` - ${pluginKey}`);
1342
1426
  }
1343
1427
  try {
1344
1428
  const originalExit = process.exit;
@@ -1353,9 +1437,9 @@ async function installPlugins(capabilities, options) {
1353
1437
  await install(detection.toInstall);
1354
1438
  result.installed = detection.toInstall;
1355
1439
  } catch (error) {
1356
- for (const pluginID of detection.toInstall) {
1440
+ for (const pluginKey of detection.toInstall) {
1357
1441
  result.failed.push({
1358
- pluginID,
1442
+ pluginKey,
1359
1443
  error: error instanceof Error ? error.message : String(error)
1360
1444
  });
1361
1445
  }
@@ -1363,9 +1447,9 @@ async function installPlugins(capabilities, options) {
1363
1447
  process.exit = originalExit;
1364
1448
  }
1365
1449
  } catch (error) {
1366
- for (const pluginID of detection.toInstall) {
1450
+ for (const pluginKey of detection.toInstall) {
1367
1451
  result.failed.push({
1368
- pluginID,
1452
+ pluginKey,
1369
1453
  error: error instanceof Error ? error.message : String(error)
1370
1454
  });
1371
1455
  }
@@ -1911,10 +1995,10 @@ async function generateReport(result) {
1911
1995
  } else {
1912
1996
  lines.push("### 1.1 \u5DF2\u8FC1\u79FB\u7684 Capabilities");
1913
1997
  lines.push("");
1914
- lines.push("| ID | pluginID |");
1915
- lines.push("|----|----------|");
1998
+ lines.push("| ID | pluginKey |");
1999
+ lines.push("|----|-----------|");
1916
2000
  for (const cap of jsonMigration.capabilities) {
1917
- lines.push(`| ${cap.id} | ${cap.pluginID} |`);
2001
+ lines.push(`| ${cap.id} | ${cap.pluginKey} |`);
1918
2002
  }
1919
2003
  lines.push("");
1920
2004
  if (jsonMigration.backupPath) {
@@ -1929,16 +2013,16 @@ async function generateReport(result) {
1929
2013
  if (pluginInstallation.installed.length === 0 && pluginInstallation.alreadyInstalled.length === 0) {
1930
2014
  lines.push("\u65E0\u63D2\u4EF6\u9700\u8981\u5B89\u88C5\u3002");
1931
2015
  } else {
1932
- lines.push("| pluginID | \u72B6\u6001 |");
1933
- lines.push("|----------|------|");
1934
- for (const pluginID of pluginInstallation.alreadyInstalled) {
1935
- lines.push(`| ${pluginID} | \u5DF2\u5B89\u88C5 |`);
2016
+ lines.push("| pluginKey | \u72B6\u6001 |");
2017
+ lines.push("|-----------|------|");
2018
+ for (const pluginKey of pluginInstallation.alreadyInstalled) {
2019
+ lines.push(`| ${pluginKey} | \u5DF2\u5B89\u88C5 |`);
1936
2020
  }
1937
- for (const pluginID of pluginInstallation.installed) {
1938
- lines.push(`| ${pluginID} | \u65B0\u5B89\u88C5 |`);
2021
+ for (const pluginKey of pluginInstallation.installed) {
2022
+ lines.push(`| ${pluginKey} | \u65B0\u5B89\u88C5 |`);
1939
2023
  }
1940
2024
  for (const failed of pluginInstallation.failed) {
1941
- lines.push(`| ${failed.pluginID} | \u274C \u5931\u8D25: ${failed.error} |`);
2025
+ lines.push(`| ${failed.pluginKey} | \u274C \u5931\u8D25: ${failed.error} |`);
1942
2026
  }
1943
2027
  }
1944
2028
  lines.push("");
@@ -2033,7 +2117,7 @@ async function runMigration(options = {}) {
2033
2117
  console.log(` \u2713 Installed: ${pluginResult.installed.join(", ")}`);
2034
2118
  }
2035
2119
  if (pluginResult.failed.length > 0) {
2036
- console.log(` \u2717 Failed: ${pluginResult.failed.map((f) => f.pluginID).join(", ")}`);
2120
+ console.log(` \u2717 Failed: ${pluginResult.failed.map((f) => f.pluginKey).join(", ")}`);
2037
2121
  }
2038
2122
  console.log("");
2039
2123
  } else {
@@ -2126,7 +2210,7 @@ var migrationCommand = {
2126
2210
  name: "migration",
2127
2211
  description: "Execute capability migration",
2128
2212
  register(program) {
2129
- program.command(this.name).description(this.description).option("--dry-run", "Preview mode, do not modify files").option("--skip-install", "Skip plugin installation step").option("--skip-code", "Skip code migration step").option("--mapping <file>", "Custom sourceActionID to pluginID mapping file").action(async (options) => {
2213
+ program.command(this.name).description(this.description).option("--dry-run", "Preview mode, do not modify files").option("--skip-install", "Skip plugin installation step").option("--skip-code", "Skip code migration step").option("--mapping <file>", "Custom sourceActionID to pluginKey mapping file").action(async (options) => {
2130
2214
  await migration(options);
2131
2215
  });
2132
2216
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/fullstack-cli",
3
- "version": "1.1.6-alpha.0",
3
+ "version": "1.1.6-alpha.2",
4
4
  "description": "CLI tool for fullstack template management",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",