@lark-apaas/fullstack-cli 1.1.6-alpha.7 → 1.1.6-alpha.9

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/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/index.ts
2
- import fs13 from "fs";
3
- import path11 from "path";
2
+ import fs15 from "fs";
3
+ import path14 from "path";
4
4
  import { fileURLToPath as fileURLToPath3 } from "url";
5
5
  import { config as dotenvConfig } from "dotenv";
6
6
 
@@ -1271,117 +1271,289 @@ async function listAll(summary) {
1271
1271
  }
1272
1272
  }
1273
1273
 
1274
- // src/commands/capability/migration.handler.ts
1275
- import fs12 from "fs";
1276
-
1277
- // src/commands/capability/migration/mapping.ts
1278
- var DEFAULT_MAPPING = {
1279
- // 飞书相关
1280
- "official_feishu/create_group": "@official_feishu/create_group",
1281
- "official_feishu/send_message": "@official_feishu/send_message",
1282
- "official_feishu/send_card": "@official_feishu/send_card",
1283
- // AI 相关
1284
- "ai/generate_text": "@official_ai/text_generation",
1285
- "ai/chat_completion": "@official_ai/chat_completion"
1286
- // 其他
1287
- // 根据实际需要添加更多映射
1288
- };
1289
- function mergeMapping(customMapping) {
1290
- if (!customMapping) {
1291
- return { ...DEFAULT_MAPPING };
1274
+ // src/commands/capability/index.ts
1275
+ var listCommand2 = {
1276
+ name: "list",
1277
+ description: "List capability configurations",
1278
+ aliases: ["ls"],
1279
+ register(program) {
1280
+ program.command(this.name).alias("ls").description(this.description).option("--summary", "Return raw capability config (without hydration)").option("--id <id>", "Specify capability ID").action(async (options) => {
1281
+ await list2(options);
1282
+ });
1292
1283
  }
1293
- return { ...DEFAULT_MAPPING, ...customMapping };
1284
+ };
1285
+ var capabilityCommandGroup = {
1286
+ name: "capability",
1287
+ description: "Manage capability configurations",
1288
+ commands: [listCommand2]
1289
+ };
1290
+
1291
+ // src/commands/migration/version-manager.ts
1292
+ import fs6 from "fs";
1293
+ import path6 from "path";
1294
+ var PACKAGE_JSON = "package.json";
1295
+ var VERSION_FIELD = "migrationVersion";
1296
+ function getPackageJsonPath2() {
1297
+ return path6.join(process.cwd(), PACKAGE_JSON);
1294
1298
  }
1295
- function getPluginKey(sourceActionID, mapping) {
1296
- const pluginKey = mapping[sourceActionID];
1297
- if (!pluginKey) {
1298
- throw new Error(
1299
- `Unknown sourceActionID: "${sourceActionID}". Please provide mapping via --mapping option or add to default mapping.`
1300
- );
1299
+ function getCurrentVersion() {
1300
+ const pkgPath = getPackageJsonPath2();
1301
+ if (!fs6.existsSync(pkgPath)) {
1302
+ throw new Error("package.json not found");
1301
1303
  }
1302
- return pluginKey;
1304
+ const pkg2 = JSON.parse(fs6.readFileSync(pkgPath, "utf-8"));
1305
+ return pkg2[VERSION_FIELD] ?? 0;
1306
+ }
1307
+ function setCurrentVersion(version) {
1308
+ const pkgPath = getPackageJsonPath2();
1309
+ const pkg2 = JSON.parse(fs6.readFileSync(pkgPath, "utf-8"));
1310
+ pkg2[VERSION_FIELD] = version;
1311
+ fs6.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
1303
1312
  }
1304
1313
 
1305
- // src/commands/capability/migration/json-migrator/index.ts
1314
+ // src/commands/migration/versions/v001_capability/json-migrator/detector.ts
1315
+ import fs8 from "fs";
1316
+ import path8 from "path";
1317
+
1318
+ // src/commands/migration/versions/v001_capability/utils.ts
1306
1319
  import fs7 from "fs";
1307
1320
  import path7 from "path";
1321
+ var CAPABILITIES_DIR2 = "server/capabilities";
1322
+ function getProjectRoot3() {
1323
+ return process.cwd();
1324
+ }
1325
+ function getCapabilitiesDir2() {
1326
+ return path7.join(getProjectRoot3(), CAPABILITIES_DIR2);
1327
+ }
1328
+ function getPluginManifestPath2(pluginKey) {
1329
+ return path7.join(getProjectRoot3(), "node_modules", pluginKey, "manifest.json");
1330
+ }
1308
1331
 
1309
- // src/commands/capability/migration/json-migrator/detector.ts
1310
- import fs6 from "fs";
1311
- import path6 from "path";
1332
+ // src/commands/migration/versions/v001_capability/json-migrator/detector.ts
1312
1333
  function detectJsonMigration() {
1313
- const capabilitiesDir = getCapabilitiesDir();
1314
- const oldFilePath = path6.join(capabilitiesDir, "capabilities.json");
1315
- if (!fs6.existsSync(capabilitiesDir)) {
1316
- return {
1317
- needsMigration: false,
1318
- reason: "capabilities directory does not exist"
1319
- };
1320
- }
1321
- if (!fs6.existsSync(oldFilePath)) {
1334
+ const capabilitiesDir = getCapabilitiesDir2();
1335
+ const oldFilePath = path8.join(capabilitiesDir, "capabilities.json");
1336
+ if (!fs8.existsSync(oldFilePath)) {
1322
1337
  return {
1323
1338
  needsMigration: false,
1324
- reason: "capabilities.json not found (may already be migrated)"
1339
+ reason: "capabilities.json not found"
1325
1340
  };
1326
1341
  }
1327
1342
  try {
1328
- const content = fs6.readFileSync(oldFilePath, "utf-8");
1343
+ const content = fs8.readFileSync(oldFilePath, "utf-8");
1329
1344
  const parsed = JSON.parse(content);
1330
- if (!Array.isArray(parsed)) {
1331
- return {
1332
- needsMigration: false,
1333
- reason: "capabilities.json is not array format"
1334
- };
1335
- }
1336
- if (parsed.length === 0) {
1337
- return {
1338
- needsMigration: false,
1339
- reason: "capabilities.json is empty array"
1340
- };
1341
- }
1342
- const firstItem = parsed[0];
1343
- if (!firstItem.sourceActionID) {
1344
- return {
1345
- needsMigration: false,
1346
- reason: "capabilities.json does not contain old format (missing sourceActionID)"
1347
- };
1348
- }
1345
+ const capabilities = Array.isArray(parsed) ? parsed : [];
1349
1346
  return {
1350
1347
  needsMigration: true,
1351
- oldCapabilities: parsed,
1348
+ oldCapabilities: capabilities,
1352
1349
  oldFilePath
1353
1350
  };
1354
1351
  } catch (error) {
1355
- if (error instanceof SyntaxError) {
1356
- return {
1357
- needsMigration: false,
1358
- reason: "capabilities.json contains invalid JSON"
1359
- };
1352
+ return {
1353
+ needsMigration: true,
1354
+ oldCapabilities: [],
1355
+ oldFilePath
1356
+ };
1357
+ }
1358
+ }
1359
+
1360
+ // src/commands/migration/versions/v001_capability/check.ts
1361
+ async function check(options) {
1362
+ const detection = detectJsonMigration();
1363
+ if (!detection.needsMigration) {
1364
+ return {
1365
+ needsMigration: false,
1366
+ message: detection.reason || "No migration needed"
1367
+ };
1368
+ }
1369
+ const capabilityCount = detection.oldCapabilities?.length || 0;
1370
+ return {
1371
+ needsMigration: true,
1372
+ message: `found ${capabilityCount} capabilities to migrate`,
1373
+ items: [
1374
+ `server/capabilities/capabilities.json \u2192 server/capabilities/*.json`,
1375
+ `${capabilityCount} capabilities will be converted to new format`
1376
+ ]
1377
+ };
1378
+ }
1379
+
1380
+ // src/commands/migration/versions/v001_capability/json-migrator/index.ts
1381
+ import fs9 from "fs";
1382
+ import path9 from "path";
1383
+
1384
+ // src/commands/migration/versions/v001_capability/mapping.ts
1385
+ var DEFAULT_PLUGIN_VERSION = "1.0.0";
1386
+ var PLUGIN_MAPPING = {
1387
+ // 飞书相关
1388
+ "official_feishu/send_message": {
1389
+ pluginKey: "@official-plugins/send-feishu-message",
1390
+ pluginVersion: "1.0.0"
1391
+ },
1392
+ "official_feishu/create_group": {
1393
+ pluginKey: "@official-plugins/feishu-group-create",
1394
+ pluginVersion: "1.0.0"
1395
+ },
1396
+ // AI 相关
1397
+ "official_ai/text_generate": {
1398
+ pluginKey: "@official-plugins/ai-text-generate",
1399
+ pluginVersion: "1.0.0"
1400
+ },
1401
+ "official_ai/image_understanding": {
1402
+ pluginKey: "@official-plugins/ai-image-understanding",
1403
+ pluginVersion: "1.0.0"
1404
+ },
1405
+ "official_ai/image_generate": {
1406
+ pluginKey: "@official-plugins/ai-text-to-image",
1407
+ pluginVersion: "1.0.0"
1408
+ }
1409
+ };
1410
+ function getPluginInfo(sourceActionID) {
1411
+ const item = PLUGIN_MAPPING[sourceActionID];
1412
+ if (!item) {
1413
+ throw new Error(
1414
+ `Unknown sourceActionID: "${sourceActionID}". This sourceActionID is not in the built-in mapping. Please contact the developer to add it.`
1415
+ );
1416
+ }
1417
+ return {
1418
+ pluginKey: item.pluginKey,
1419
+ pluginVersion: item.pluginVersion ?? DEFAULT_PLUGIN_VERSION
1420
+ };
1421
+ }
1422
+
1423
+ // src/commands/migration/versions/v001_capability/json-migrator/form-value-transformers/send-feishu-message.ts
1424
+ function transformSendFeishuMessage(input) {
1425
+ const actionInput = input;
1426
+ const cardContent = actionInput.card_content;
1427
+ const header = cardContent?.header;
1428
+ const bodyElements = cardContent?.body?.elements;
1429
+ const title = {
1430
+ title: header?.title?.content ?? "",
1431
+ titleColor: header?.template
1432
+ };
1433
+ const markdownElement = bodyElements?.find((el) => el.tag === "markdown");
1434
+ const content = markdownElement?.content ?? "";
1435
+ const columnSet = bodyElements?.find((el) => el.tag === "column_set");
1436
+ const buttons = columnSet?.columns?.flatMap(
1437
+ (column) => column.elements?.filter((el) => el.tag === "button").map((btn) => ({
1438
+ style: btn.type,
1439
+ text: btn.text?.content,
1440
+ url: btn.behaviors?.[0]?.default_url
1441
+ })) ?? []
1442
+ ) ?? [];
1443
+ return {
1444
+ sender: "bot",
1445
+ receiverUserList: actionInput.receiver_user_list ?? [],
1446
+ receiverGroupList: actionInput.receiver_group_list ?? [],
1447
+ title,
1448
+ content,
1449
+ buttons
1450
+ };
1451
+ }
1452
+
1453
+ // src/commands/migration/versions/v001_capability/json-migrator/form-value-transformers/feishu-group-create.ts
1454
+ function transformFeishuGroupCreate(input) {
1455
+ const actionInput = input;
1456
+ return {
1457
+ owner: actionInput.owner,
1458
+ members: actionInput.members ?? [],
1459
+ groupName: actionInput.group_name ?? "",
1460
+ groupDescription: actionInput.group_description ?? "",
1461
+ welcomeMessage: actionInput.welcome_message ?? ""
1462
+ };
1463
+ }
1464
+
1465
+ // src/commands/migration/versions/v001_capability/json-migrator/form-value-transformers/utils.ts
1466
+ function convertToNumber(value, defaultValue) {
1467
+ if (value === void 0 || value === "") {
1468
+ return defaultValue;
1469
+ }
1470
+ const num = Number(value);
1471
+ return isNaN(num) ? defaultValue : num;
1472
+ }
1473
+
1474
+ // src/commands/migration/versions/v001_capability/json-migrator/form-value-transformers/ai-text-generate.ts
1475
+ var DEFAULT_MODEL_ID = "87";
1476
+ var DEFAULT_MAX_TOKENS = 8192;
1477
+ var DEFAULT_TEMPERATURE = 0.7;
1478
+ function transformAITextGenerate(input) {
1479
+ const actionInput = input;
1480
+ return {
1481
+ modelID: actionInput.model_id ?? DEFAULT_MODEL_ID,
1482
+ prompt: actionInput.prompt ?? "",
1483
+ modelParams: {
1484
+ maxTokens: convertToNumber(actionInput.max_tokens, DEFAULT_MAX_TOKENS),
1485
+ temperature: convertToNumber(actionInput.temperature, DEFAULT_TEMPERATURE)
1360
1486
  }
1361
- throw error;
1487
+ };
1488
+ }
1489
+
1490
+ // src/commands/migration/versions/v001_capability/json-migrator/form-value-transformers/ai-image-understanding.ts
1491
+ var DEFAULT_MODEL_ID2 = "87";
1492
+ var DEFAULT_MAX_TOKENS2 = 8192;
1493
+ var DEFAULT_TEMPERATURE2 = 0.7;
1494
+ function transformAIImageUnderstanding(input) {
1495
+ const actionInput = input;
1496
+ return {
1497
+ modelID: actionInput.model_id ?? DEFAULT_MODEL_ID2,
1498
+ prompt: actionInput.prompt ?? "",
1499
+ modelParams: {
1500
+ maxTokens: convertToNumber(actionInput.max_tokens, DEFAULT_MAX_TOKENS2),
1501
+ temperature: convertToNumber(actionInput.temperature, DEFAULT_TEMPERATURE2)
1502
+ }
1503
+ };
1504
+ }
1505
+
1506
+ // src/commands/migration/versions/v001_capability/json-migrator/form-value-transformers/ai-text-to-image.ts
1507
+ var DEFAULT_RATIO = "1:1";
1508
+ var DEFAULT_WATERMARK = true;
1509
+ function transformAITextToImage(input) {
1510
+ const actionInput = input;
1511
+ return {
1512
+ prompt: actionInput.prompt ?? "",
1513
+ ratio: actionInput.image_ratio ?? DEFAULT_RATIO,
1514
+ watermark: actionInput.watermark ?? DEFAULT_WATERMARK
1515
+ };
1516
+ }
1517
+
1518
+ // src/commands/migration/versions/v001_capability/json-migrator/form-value-transformers/index.ts
1519
+ var TRANSFORMER_MAP = {
1520
+ "official_feishu/send_message": transformSendFeishuMessage,
1521
+ "official_feishu/create_group": transformFeishuGroupCreate,
1522
+ "official_ai/text_generate": transformAITextGenerate,
1523
+ "official_ai/image_understanding": transformAIImageUnderstanding,
1524
+ "official_ai/image_generate": transformAITextToImage
1525
+ };
1526
+ function transformFormValue(sourceActionID, actionInput) {
1527
+ const transformer = TRANSFORMER_MAP[sourceActionID];
1528
+ if (!transformer) {
1529
+ throw new Error(
1530
+ `No formValue transformer found for sourceActionID: "${sourceActionID}". Please implement the transformer and add it to TRANSFORMER_MAP.`
1531
+ );
1362
1532
  }
1533
+ return transformer(actionInput);
1363
1534
  }
1364
1535
 
1365
- // src/commands/capability/migration/json-migrator/transformer.ts
1366
- function transformCapability(old, mapping) {
1367
- const pluginKey = getPluginKey(old.sourceActionID, mapping);
1536
+ // src/commands/migration/versions/v001_capability/json-migrator/transformer.ts
1537
+ function transformCapability(old) {
1538
+ const { pluginKey, pluginVersion } = getPluginInfo(old.sourceActionID);
1539
+ const formValue = transformFormValue(old.sourceActionID, old.actionInput);
1368
1540
  return {
1369
1541
  id: old.id,
1370
1542
  pluginKey,
1371
- pluginVersion: "latest",
1543
+ pluginVersion,
1372
1544
  name: old.name,
1373
1545
  description: old.desc,
1374
1546
  paramsSchema: old.inputSchema,
1375
- formValue: old.actionInput,
1547
+ formValue,
1376
1548
  createdAt: old.createdAt,
1377
1549
  updatedAt: old.updatedAt
1378
1550
  };
1379
1551
  }
1380
- function transformCapabilities(oldCapabilities, mapping) {
1381
- return oldCapabilities.map((old) => transformCapability(old, mapping));
1552
+ function transformCapabilities(oldCapabilities) {
1553
+ return oldCapabilities.map((old) => transformCapability(old));
1382
1554
  }
1383
1555
 
1384
- // src/commands/capability/migration/json-migrator/index.ts
1556
+ // src/commands/migration/versions/v001_capability/json-migrator/index.ts
1385
1557
  async function migrateJsonFiles(options) {
1386
1558
  const detection = detectJsonMigration();
1387
1559
  if (!detection.needsMigration) {
@@ -1405,7 +1577,7 @@ async function migrateJsonFiles(options) {
1405
1577
  }
1406
1578
  let newCapabilities;
1407
1579
  try {
1408
- newCapabilities = transformCapabilities(oldCapabilities, options.mapping);
1580
+ newCapabilities = transformCapabilities(oldCapabilities);
1409
1581
  } catch (error) {
1410
1582
  return {
1411
1583
  success: false,
@@ -1427,29 +1599,26 @@ async function migrateJsonFiles(options) {
1427
1599
  capabilities: newCapabilities
1428
1600
  };
1429
1601
  }
1430
- const capabilitiesDir = getCapabilitiesDir();
1602
+ const capabilitiesDir = getCapabilitiesDir2();
1431
1603
  for (const cap of newCapabilities) {
1432
- const filePath = path7.join(capabilitiesDir, `${cap.id}.json`);
1604
+ const filePath = path9.join(capabilitiesDir, `${cap.id}.json`);
1433
1605
  const content = JSON.stringify(cap, null, 2);
1434
- fs7.writeFileSync(filePath, content, "utf-8");
1606
+ fs9.writeFileSync(filePath, content, "utf-8");
1435
1607
  console.log(` \u2713 Created: ${cap.id}.json`);
1436
1608
  }
1437
- const backupPath = oldFilePath + ".backup";
1438
- fs7.renameSync(oldFilePath, backupPath);
1439
1609
  return {
1440
1610
  success: true,
1441
1611
  skipped: false,
1442
1612
  count: newCapabilities.length,
1443
- capabilities: newCapabilities,
1444
- backupPath
1613
+ capabilities: newCapabilities
1445
1614
  };
1446
1615
  }
1447
1616
 
1448
- // src/commands/capability/migration/plugin-installer/detector.ts
1449
- import fs8 from "fs";
1617
+ // src/commands/migration/versions/v001_capability/plugin-installer/detector.ts
1618
+ import fs10 from "fs";
1450
1619
  function isPluginInstalled2(pluginKey) {
1451
- const manifestPath = getPluginManifestPath(pluginKey);
1452
- return fs8.existsSync(manifestPath);
1620
+ const manifestPath = getPluginManifestPath2(pluginKey);
1621
+ return fs10.existsSync(manifestPath);
1453
1622
  }
1454
1623
  function detectPluginsToInstall(capabilities) {
1455
1624
  const pluginKeys = /* @__PURE__ */ new Set();
@@ -1468,7 +1637,7 @@ function detectPluginsToInstall(capabilities) {
1468
1637
  return { toInstall, alreadyInstalled };
1469
1638
  }
1470
1639
 
1471
- // src/commands/capability/migration/plugin-installer/index.ts
1640
+ // src/commands/migration/versions/v001_capability/plugin-installer/index.ts
1472
1641
  async function installPlugins(capabilities, options) {
1473
1642
  const detection = detectPluginsToInstall(capabilities);
1474
1643
  const result = {
@@ -1524,14 +1693,14 @@ async function installPlugins(capabilities, options) {
1524
1693
  return result;
1525
1694
  }
1526
1695
 
1527
- // src/commands/capability/migration/code-migrator/index.ts
1528
- import fs10 from "fs";
1529
- import path9 from "path";
1696
+ // src/commands/migration/versions/v001_capability/code-migrator/index.ts
1697
+ import fs12 from "fs";
1698
+ import path11 from "path";
1530
1699
  import * as ts4 from "typescript";
1531
1700
 
1532
- // src/commands/capability/migration/code-migrator/scanner.ts
1533
- import fs9 from "fs";
1534
- import path8 from "path";
1701
+ // src/commands/migration/versions/v001_capability/code-migrator/scanner.ts
1702
+ import fs11 from "fs";
1703
+ import path10 from "path";
1535
1704
  var EXCLUDED_DIRS = [
1536
1705
  "node_modules",
1537
1706
  "dist",
@@ -1546,9 +1715,9 @@ var EXCLUDED_PATTERNS = [
1546
1715
  /\.d\.ts$/
1547
1716
  ];
1548
1717
  function scanDirectory(dir, files = []) {
1549
- const entries = fs9.readdirSync(dir, { withFileTypes: true });
1718
+ const entries = fs11.readdirSync(dir, { withFileTypes: true });
1550
1719
  for (const entry of entries) {
1551
- const fullPath = path8.join(dir, entry.name);
1720
+ const fullPath = path10.join(dir, entry.name);
1552
1721
  if (entry.isDirectory()) {
1553
1722
  if (EXCLUDED_DIRS.includes(entry.name)) {
1554
1723
  continue;
@@ -1564,14 +1733,14 @@ function scanDirectory(dir, files = []) {
1564
1733
  return files;
1565
1734
  }
1566
1735
  function scanServerFiles() {
1567
- const serverDir = path8.join(getProjectRoot2(), "server");
1568
- if (!fs9.existsSync(serverDir)) {
1736
+ const serverDir = path10.join(getProjectRoot3(), "server");
1737
+ if (!fs11.existsSync(serverDir)) {
1569
1738
  return [];
1570
1739
  }
1571
1740
  return scanDirectory(serverDir);
1572
1741
  }
1573
1742
  function hasCapabilityImport(filePath) {
1574
- const content = fs9.readFileSync(filePath, "utf-8");
1743
+ const content = fs11.readFileSync(filePath, "utf-8");
1575
1744
  return /import\s+.*from\s+['"][^'"]*capabilities[^'"]*['"]/.test(content);
1576
1745
  }
1577
1746
  function scanFilesToMigrate() {
@@ -1579,7 +1748,7 @@ function scanFilesToMigrate() {
1579
1748
  return allFiles.filter(hasCapabilityImport);
1580
1749
  }
1581
1750
 
1582
- // src/commands/capability/migration/code-migrator/analyzers/import-analyzer.ts
1751
+ // src/commands/migration/versions/v001_capability/code-migrator/analyzers/import-analyzer.ts
1583
1752
  import * as ts from "typescript";
1584
1753
  function extractCapabilityId(importPath) {
1585
1754
  const match = importPath.match(/capabilities\/([^/]+)$/);
@@ -1643,7 +1812,7 @@ function analyzeImports(sourceFile) {
1643
1812
  return imports;
1644
1813
  }
1645
1814
 
1646
- // src/commands/capability/migration/code-migrator/analyzers/call-site-analyzer.ts
1815
+ // src/commands/migration/versions/v001_capability/code-migrator/analyzers/call-site-analyzer.ts
1647
1816
  import * as ts2 from "typescript";
1648
1817
  function analyzeCallSites(sourceFile, imports) {
1649
1818
  const callSites = [];
@@ -1693,7 +1862,7 @@ function analyzeCallSites(sourceFile, imports) {
1693
1862
  return callSites;
1694
1863
  }
1695
1864
 
1696
- // src/commands/capability/migration/code-migrator/analyzers/class-analyzer.ts
1865
+ // src/commands/migration/versions/v001_capability/code-migrator/analyzers/class-analyzer.ts
1697
1866
  import * as ts3 from "typescript";
1698
1867
  function hasDecorator(node, decoratorName) {
1699
1868
  const decorators = ts3.getDecorators(node);
@@ -1769,10 +1938,14 @@ function canAutoMigrate(classInfo) {
1769
1938
  return { canMigrate: true };
1770
1939
  }
1771
1940
 
1772
- // src/commands/capability/migration/code-migrator/transformers/import-transformer.ts
1773
- var CAPABILITY_SERVICE_IMPORT = `import { CapabilityService } from '@lark-apaas/nestjs-core';`;
1941
+ // src/commands/migration/versions/v001_capability/code-migrator/transformers/import-transformer.ts
1942
+ var CAPABILITY_SERVICE_IMPORT = `import { CapabilityService, migrationAdaptor } from '@lark-apaas/fullstack-nestjs-core';`;
1943
+ var INJECT_IMPORT = `import { Inject } from '@nestjs/common';`;
1774
1944
  function hasCapabilityServiceImport(content) {
1775
- return /import\s+.*CapabilityService.*from\s+['"]@lark-apaas\/nestjs-core['"]/.test(content);
1945
+ return /import\s+.*CapabilityService.*from\s+['"]@lark-apaas\/fullstack-nestjs-core['"]/.test(content);
1946
+ }
1947
+ function hasInjectImport(content) {
1948
+ return /import\s+.*\bInject\b.*from\s+['"]@nestjs\/common['"]/.test(content);
1776
1949
  }
1777
1950
  function findImportInsertPosition(content) {
1778
1951
  const importRegex = /^import\s+.*?from\s+['"][^'"]+['"];?\s*$/gm;
@@ -1805,11 +1978,20 @@ function transformImports(content, imports) {
1805
1978
  }
1806
1979
  importAdded = true;
1807
1980
  }
1981
+ if (!hasInjectImport(result)) {
1982
+ const insertPos = findImportInsertPosition(result);
1983
+ if (insertPos > 0) {
1984
+ result = result.substring(0, insertPos) + "\n" + INJECT_IMPORT + result.substring(insertPos);
1985
+ } else {
1986
+ result = INJECT_IMPORT + "\n" + result;
1987
+ }
1988
+ importAdded = true;
1989
+ }
1808
1990
  return { content: result, importAdded };
1809
1991
  }
1810
1992
 
1811
- // src/commands/capability/migration/code-migrator/transformers/injection-transformer.ts
1812
- var INJECTION_PARAM = "private readonly capabilityService: CapabilityService";
1993
+ // src/commands/migration/versions/v001_capability/code-migrator/transformers/injection-transformer.ts
1994
+ var INJECTION_PARAM = "@Inject() private readonly capabilityService: CapabilityService";
1813
1995
  function hasCapabilityServiceInjection(content) {
1814
1996
  return /capabilityService\s*:\s*CapabilityService/.test(content);
1815
1997
  }
@@ -1838,7 +2020,7 @@ function addInjection(content, classInfo) {
1838
2020
  return { content: result, injectionAdded: result !== content };
1839
2021
  }
1840
2022
 
1841
- // src/commands/capability/migration/code-migrator/transformers/call-site-transformer.ts
2023
+ // src/commands/migration/versions/v001_capability/code-migrator/transformers/call-site-transformer.ts
1842
2024
  function generateNewCall(capabilityId, originalCall) {
1843
2025
  const parenIndex = originalCall.indexOf("(");
1844
2026
  if (parenIndex === -1) {
@@ -1846,14 +2028,14 @@ function generateNewCall(capabilityId, originalCall) {
1846
2028
  }
1847
2029
  const argsStart = parenIndex + 1;
1848
2030
  const argsEnd = originalCall.lastIndexOf(")");
1849
- if (argsEnd === -1 || argsEnd <= argsStart) {
1850
- return `this.capabilityService.load('${capabilityId}').call('run', {})`;
1851
- }
1852
- const args = originalCall.substring(argsStart, argsEnd).trim();
1853
- if (!args) {
1854
- return `this.capabilityService.load('${capabilityId}').call('run', {})`;
2031
+ let args = "{}";
2032
+ if (argsEnd !== -1 && argsEnd > argsStart) {
2033
+ const extractedArgs = originalCall.substring(argsStart, argsEnd).trim();
2034
+ if (extractedArgs) {
2035
+ args = extractedArgs;
2036
+ }
1855
2037
  }
1856
- return `this.capabilityService.load('${capabilityId}').call('run', ${args})`;
2038
+ return `migrationAdaptor(this.capabilityService.load('${capabilityId}').call('run', ${args}))`;
1857
2039
  }
1858
2040
  function transformCallSites(content, callSites) {
1859
2041
  const sortedCallSites = [...callSites].sort((a, b) => b.start - a.start);
@@ -1869,9 +2051,9 @@ function transformCallSites(content, callSites) {
1869
2051
  return { content: result, replacedCount };
1870
2052
  }
1871
2053
 
1872
- // src/commands/capability/migration/code-migrator/index.ts
2054
+ // src/commands/migration/versions/v001_capability/code-migrator/index.ts
1873
2055
  function analyzeFile(filePath) {
1874
- const content = fs10.readFileSync(filePath, "utf-8");
2056
+ const content = fs12.readFileSync(filePath, "utf-8");
1875
2057
  const sourceFile = ts4.createSourceFile(
1876
2058
  filePath,
1877
2059
  content,
@@ -1882,7 +2064,7 @@ function analyzeFile(filePath) {
1882
2064
  const callSites = analyzeCallSites(sourceFile, imports);
1883
2065
  const classInfo = analyzeClass(sourceFile);
1884
2066
  const { canMigrate, reason } = canAutoMigrate(classInfo);
1885
- const relativePath = path9.relative(getProjectRoot2(), filePath);
2067
+ const relativePath = path11.relative(getProjectRoot3(), filePath);
1886
2068
  return {
1887
2069
  filePath: relativePath,
1888
2070
  imports,
@@ -1893,7 +2075,7 @@ function analyzeFile(filePath) {
1893
2075
  };
1894
2076
  }
1895
2077
  function migrateFile(analysis, dryRun) {
1896
- const absolutePath = path9.join(getProjectRoot2(), analysis.filePath);
2078
+ const absolutePath = path11.join(getProjectRoot3(), analysis.filePath);
1897
2079
  if (!analysis.canAutoMigrate) {
1898
2080
  return {
1899
2081
  filePath: analysis.filePath,
@@ -1905,7 +2087,7 @@ function migrateFile(analysis, dryRun) {
1905
2087
  };
1906
2088
  }
1907
2089
  try {
1908
- let content = fs10.readFileSync(absolutePath, "utf-8");
2090
+ let content = fs12.readFileSync(absolutePath, "utf-8");
1909
2091
  const callResult = transformCallSites(content, analysis.callSites);
1910
2092
  content = callResult.content;
1911
2093
  const sourceFile = ts4.createSourceFile(
@@ -1933,7 +2115,7 @@ function migrateFile(analysis, dryRun) {
1933
2115
  }
1934
2116
  }
1935
2117
  if (!dryRun) {
1936
- fs10.writeFileSync(absolutePath, content, "utf-8");
2118
+ fs12.writeFileSync(absolutePath, content, "utf-8");
1937
2119
  }
1938
2120
  return {
1939
2121
  filePath: analysis.filePath,
@@ -1999,12 +2181,50 @@ function getSuggestion(analysis) {
1999
2181
  return "Manual review required";
2000
2182
  }
2001
2183
 
2002
- // src/commands/capability/migration/report-generator.ts
2003
- import fs11 from "fs";
2004
- import path10 from "path";
2184
+ // src/commands/migration/versions/v001_capability/cleanup.ts
2185
+ import fs13 from "fs";
2186
+ import path12 from "path";
2187
+ function cleanupOldFiles(capabilities, dryRun) {
2188
+ const deletedFiles = [];
2189
+ const errors = [];
2190
+ const capabilitiesDir = getCapabilitiesDir2();
2191
+ const oldJsonPath = path12.join(capabilitiesDir, "capabilities.json");
2192
+ if (fs13.existsSync(oldJsonPath)) {
2193
+ try {
2194
+ if (!dryRun) {
2195
+ fs13.unlinkSync(oldJsonPath);
2196
+ }
2197
+ deletedFiles.push("capabilities.json");
2198
+ } catch (error) {
2199
+ errors.push(`Failed to delete capabilities.json: ${error instanceof Error ? error.message : String(error)}`);
2200
+ }
2201
+ }
2202
+ for (const cap of capabilities) {
2203
+ const tsFilePath = path12.join(capabilitiesDir, `${cap.id}.ts`);
2204
+ if (fs13.existsSync(tsFilePath)) {
2205
+ try {
2206
+ if (!dryRun) {
2207
+ fs13.unlinkSync(tsFilePath);
2208
+ }
2209
+ deletedFiles.push(`${cap.id}.ts`);
2210
+ } catch (error) {
2211
+ errors.push(`Failed to delete ${cap.id}.ts: ${error instanceof Error ? error.message : String(error)}`);
2212
+ }
2213
+ }
2214
+ }
2215
+ return {
2216
+ success: errors.length === 0,
2217
+ deletedFiles,
2218
+ errors
2219
+ };
2220
+ }
2221
+
2222
+ // src/commands/migration/versions/v001_capability/report-generator.ts
2223
+ import fs14 from "fs";
2224
+ import path13 from "path";
2005
2225
  var REPORT_FILE = "capability-migration-report.md";
2006
2226
  function printSummary(result) {
2007
- const { jsonMigration, pluginInstallation, codeMigration } = result;
2227
+ const { jsonMigration, pluginInstallation, codeMigration, cleanup } = result;
2008
2228
  console.log("\u{1F4CA} Migration Summary");
2009
2229
  console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
2010
2230
  if (!jsonMigration.skipped) {
@@ -2029,6 +2249,9 @@ function printSummary(result) {
2029
2249
  console.log(` Files need manual work: ${codeMigration.manualRequired.length}`);
2030
2250
  }
2031
2251
  console.log(` Total call sites fixed: ${totalCallSites}`);
2252
+ if (cleanup.deletedFiles.length > 0) {
2253
+ console.log(` Old files cleaned up: ${cleanup.deletedFiles.length}`);
2254
+ }
2032
2255
  console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n");
2033
2256
  const hasErrors = pluginInstallation.failed.length > 0 || failedMigrations.length > 0;
2034
2257
  const hasManual = codeMigration.manualRequired.length > 0;
@@ -2049,7 +2272,7 @@ function printSummary(result) {
2049
2272
  console.log("");
2050
2273
  }
2051
2274
  async function generateReport(result) {
2052
- const { jsonMigration, pluginInstallation, codeMigration } = result;
2275
+ const { jsonMigration, pluginInstallation, codeMigration, cleanup } = result;
2053
2276
  const lines = [];
2054
2277
  lines.push("# Capability \u8FC1\u79FB\u62A5\u544A");
2055
2278
  lines.push("");
@@ -2068,12 +2291,6 @@ async function generateReport(result) {
2068
2291
  lines.push(`| ${cap.id} | ${cap.pluginKey} |`);
2069
2292
  }
2070
2293
  lines.push("");
2071
- if (jsonMigration.backupPath) {
2072
- lines.push("### 1.2 \u5907\u4EFD\u6587\u4EF6");
2073
- lines.push("");
2074
- lines.push(`- \`${jsonMigration.backupPath}\``);
2075
- lines.push("");
2076
- }
2077
2294
  }
2078
2295
  lines.push("## 2. \u63D2\u4EF6\u5B89\u88C5");
2079
2296
  lines.push("");
@@ -2134,7 +2351,30 @@ async function generateReport(result) {
2134
2351
  lines.push("");
2135
2352
  }
2136
2353
  }
2137
- lines.push("## 4. \u9A8C\u8BC1\u6E05\u5355");
2354
+ lines.push("## 4. \u6E05\u7406\u8001\u6587\u4EF6");
2355
+ lines.push("");
2356
+ if (cleanup.deletedFiles.length === 0 && cleanup.errors.length === 0) {
2357
+ lines.push("\u65E0\u6587\u4EF6\u9700\u8981\u6E05\u7406\u3002");
2358
+ } else {
2359
+ if (cleanup.deletedFiles.length > 0) {
2360
+ lines.push("### 4.1 \u5DF2\u5220\u9664\u7684\u6587\u4EF6");
2361
+ lines.push("");
2362
+ for (const file of cleanup.deletedFiles) {
2363
+ lines.push(`- \`${file}\``);
2364
+ }
2365
+ lines.push("");
2366
+ }
2367
+ if (cleanup.errors.length > 0) {
2368
+ lines.push("### 4.2 \u6E05\u7406\u5931\u8D25");
2369
+ lines.push("");
2370
+ for (const err of cleanup.errors) {
2371
+ lines.push(`- \u274C ${err}`);
2372
+ }
2373
+ lines.push("");
2374
+ }
2375
+ }
2376
+ lines.push("");
2377
+ lines.push("## 5. \u9A8C\u8BC1\u6E05\u5355");
2138
2378
  lines.push("");
2139
2379
  lines.push("- [ ] \u8FD0\u884C `git diff` \u68C0\u67E5\u4EE3\u7801\u53D8\u66F4");
2140
2380
  lines.push("- [ ] \u8FD0\u884C `npm run typecheck` \u68C0\u67E5\u7C7B\u578B");
@@ -2142,40 +2382,74 @@ async function generateReport(result) {
2142
2382
  if (codeMigration.manualRequired.length > 0) {
2143
2383
  lines.push("- [ ] \u5904\u7406\u624B\u52A8\u8FC1\u79FB\u9879");
2144
2384
  }
2145
- lines.push("- [ ] \u5220\u9664\u5907\u4EFD\u6587\u4EF6\uFF08\u786E\u8BA4\u65E0\u8BEF\u540E\uFF09");
2146
2385
  lines.push("");
2147
- const reportPath = path10.join(getProjectRoot2(), REPORT_FILE);
2148
- fs11.writeFileSync(reportPath, lines.join("\n"), "utf-8");
2386
+ const reportPath = path13.join(getProjectRoot3(), REPORT_FILE);
2387
+ fs14.writeFileSync(reportPath, lines.join("\n"), "utf-8");
2149
2388
  console.log(`\u{1F4C4} Report generated: ${REPORT_FILE}`);
2150
2389
  }
2151
2390
 
2152
- // src/commands/capability/migration/index.ts
2153
- async function runMigration(options = {}) {
2391
+ // src/commands/migration/versions/v001_capability/migration-runner.ts
2392
+ async function runCapabilityMigration(options = {}) {
2154
2393
  const fullOptions = {
2155
- dryRun: options.dryRun ?? false,
2156
- skipInstall: options.skipInstall ?? false,
2157
- skipCode: options.skipCode ?? false,
2158
- mapping: mergeMapping(options.mapping)
2394
+ dryRun: options.dryRun ?? false
2159
2395
  };
2160
2396
  console.log("\u{1F50D} Analyzing project...\n");
2161
2397
  if (fullOptions.dryRun) {
2162
2398
  console.log("\u{1F4CB} Running in dry-run mode (no files will be modified)\n");
2163
2399
  }
2400
+ let jsonResult = {
2401
+ success: false,
2402
+ skipped: true,
2403
+ reason: "Not executed",
2404
+ count: 0,
2405
+ capabilities: []
2406
+ };
2407
+ let pluginResult = {
2408
+ installed: [],
2409
+ alreadyInstalled: [],
2410
+ failed: []
2411
+ };
2412
+ let codeResult = {
2413
+ autoMigrated: [],
2414
+ manualRequired: []
2415
+ };
2416
+ let cleanupResult = {
2417
+ success: true,
2418
+ deletedFiles: [],
2419
+ errors: []
2420
+ };
2164
2421
  console.log("\u{1F4C1} Step 1: JSON File Migration");
2165
- const jsonResult = await migrateJsonFiles(fullOptions);
2166
- if (jsonResult.skipped) {
2167
- console.log(` \u25CB Skipped: ${jsonResult.reason}
2422
+ try {
2423
+ jsonResult = await migrateJsonFiles(fullOptions);
2424
+ if (jsonResult.skipped) {
2425
+ console.log(` \u25CB Skipped: ${jsonResult.reason}
2426
+ `);
2427
+ } else if (jsonResult.success) {
2428
+ console.log(` \u2713 Created ${jsonResult.count} capability files
2429
+ `);
2430
+ } else {
2431
+ console.log(` \u2717 Failed: ${jsonResult.reason}
2168
2432
  `);
2169
- } else if (jsonResult.success) {
2170
- console.log(` \u2713 Migrated ${jsonResult.count} capabilities`);
2171
- if (jsonResult.backupPath) {
2172
- console.log(` \u2713 Backed up: capabilities.json \u2192 capabilities.json.backup`);
2433
+ return buildResult(jsonResult, pluginResult, codeResult, cleanupResult);
2173
2434
  }
2174
- console.log("");
2435
+ } catch (error) {
2436
+ const errorMsg = error instanceof Error ? error.message : String(error);
2437
+ console.log(` \u2717 Error: ${errorMsg}
2438
+ `);
2439
+ jsonResult = {
2440
+ success: false,
2441
+ skipped: false,
2442
+ reason: errorMsg,
2443
+ count: 0,
2444
+ capabilities: []
2445
+ };
2446
+ return buildResult(jsonResult, pluginResult, codeResult, cleanupResult);
2175
2447
  }
2176
- let pluginResult = { installed: [], alreadyInstalled: [], failed: [] };
2177
- if (!fullOptions.skipInstall) {
2178
- console.log("\u{1F4E6} Step 2: Plugin Installation");
2448
+ if (jsonResult.skipped) {
2449
+ return buildResult(jsonResult, pluginResult, codeResult, cleanupResult);
2450
+ }
2451
+ console.log("\u{1F4E6} Step 2: Plugin Installation");
2452
+ try {
2179
2453
  pluginResult = await installPlugins(jsonResult.capabilities, fullOptions);
2180
2454
  if (pluginResult.alreadyInstalled.length > 0) {
2181
2455
  console.log(` \u2713 Already installed: ${pluginResult.alreadyInstalled.join(", ")}`);
@@ -2184,18 +2458,27 @@ async function runMigration(options = {}) {
2184
2458
  console.log(` \u2713 Installed: ${pluginResult.installed.join(", ")}`);
2185
2459
  }
2186
2460
  if (pluginResult.failed.length > 0) {
2187
- console.log(` \u2717 Failed: ${pluginResult.failed.map((f) => f.pluginKey).join(", ")}`);
2461
+ console.log(` \u26A0 Failed (will continue): ${pluginResult.failed.map((f) => f.pluginKey).join(", ")}`);
2462
+ for (const f of pluginResult.failed) {
2463
+ console.log(` - ${f.pluginKey}: ${f.error}`);
2464
+ }
2188
2465
  }
2189
2466
  console.log("");
2190
- } else {
2191
- console.log("\u{1F4E6} Step 2: Plugin Installation");
2192
- console.log(" \u25CB Skipped (--skip-install)\n");
2467
+ } catch (error) {
2468
+ const errorMsg = error instanceof Error ? error.message : String(error);
2469
+ console.log(` \u26A0 Error (will continue): ${errorMsg}
2470
+ `);
2471
+ pluginResult = {
2472
+ installed: [],
2473
+ alreadyInstalled: [],
2474
+ failed: [{ pluginKey: "unknown", error: errorMsg }]
2475
+ };
2193
2476
  }
2194
- let codeResult = { autoMigrated: [], manualRequired: [] };
2195
- if (!fullOptions.skipCode) {
2196
- console.log("\u{1F527} Step 3: Code Migration");
2197
- console.log(" Scanning server/ directory...\n");
2477
+ console.log("\u{1F527} Step 3: Code Migration");
2478
+ console.log(" Scanning server/ directory...\n");
2479
+ try {
2198
2480
  codeResult = await migrateCode(fullOptions);
2481
+ let hasCodeError = false;
2199
2482
  for (const file of codeResult.autoMigrated) {
2200
2483
  if (file.success) {
2201
2484
  console.log(` \u2713 ${file.filePath}`);
@@ -2206,6 +2489,7 @@ async function runMigration(options = {}) {
2206
2489
  console.log(` - Replaced ${file.callSitesReplaced} call sites`);
2207
2490
  } else {
2208
2491
  console.log(` \u2717 ${file.filePath}: ${file.error}`);
2492
+ hasCodeError = true;
2209
2493
  }
2210
2494
  }
2211
2495
  if (codeResult.manualRequired.length > 0) {
@@ -2216,93 +2500,414 @@ async function runMigration(options = {}) {
2216
2500
  }
2217
2501
  }
2218
2502
  console.log("");
2219
- } else {
2220
- console.log("\u{1F527} Step 3: Code Migration");
2221
- console.log(" \u25CB Skipped (--skip-code)\n");
2503
+ if (hasCodeError) {
2504
+ console.log(" \u2717 Code migration failed, aborting...\n");
2505
+ return buildResult(jsonResult, pluginResult, codeResult, cleanupResult);
2506
+ }
2507
+ } catch (error) {
2508
+ const errorMsg = error instanceof Error ? error.message : String(error);
2509
+ console.log(` \u2717 Error: ${errorMsg}
2510
+ `);
2511
+ codeResult = {
2512
+ autoMigrated: [],
2513
+ manualRequired: []
2514
+ };
2515
+ return buildResult(jsonResult, pluginResult, codeResult, cleanupResult);
2222
2516
  }
2223
- const result = {
2224
- jsonMigration: jsonResult,
2225
- pluginInstallation: pluginResult,
2226
- codeMigration: codeResult
2227
- };
2517
+ console.log("\u{1F9F9} Step 4: Cleanup Old Files");
2518
+ try {
2519
+ cleanupResult = cleanupOldFiles(jsonResult.capabilities, fullOptions.dryRun);
2520
+ if (cleanupResult.deletedFiles.length > 0) {
2521
+ for (const file of cleanupResult.deletedFiles) {
2522
+ console.log(` \u2713 Deleted: ${file}`);
2523
+ }
2524
+ } else {
2525
+ console.log(" \u25CB No files to clean up");
2526
+ }
2527
+ if (cleanupResult.errors.length > 0) {
2528
+ for (const err of cleanupResult.errors) {
2529
+ console.log(` \u26A0 ${err}`);
2530
+ }
2531
+ }
2532
+ console.log("");
2533
+ } catch (error) {
2534
+ const errorMsg = error instanceof Error ? error.message : String(error);
2535
+ console.log(` \u26A0 Error: ${errorMsg}
2536
+ `);
2537
+ cleanupResult = {
2538
+ success: false,
2539
+ deletedFiles: [],
2540
+ errors: [errorMsg]
2541
+ };
2542
+ }
2543
+ const result = buildResult(jsonResult, pluginResult, codeResult, cleanupResult);
2228
2544
  printSummary(result);
2229
2545
  if (!fullOptions.dryRun) {
2230
2546
  await generateReport(result);
2231
2547
  }
2232
2548
  return result;
2233
2549
  }
2550
+ function buildResult(jsonMigration, pluginInstallation, codeMigration, cleanup) {
2551
+ return {
2552
+ jsonMigration,
2553
+ pluginInstallation,
2554
+ codeMigration,
2555
+ cleanup
2556
+ };
2557
+ }
2234
2558
 
2235
- // src/commands/capability/migration.handler.ts
2236
- async function migration(options = {}) {
2559
+ // src/commands/migration/versions/v001_capability/run.ts
2560
+ async function run3(options) {
2237
2561
  try {
2238
- let customMapping;
2239
- if (options.mapping) {
2240
- if (!fs12.existsSync(options.mapping)) {
2241
- console.error(`[capability] Mapping file not found: ${options.mapping}`);
2242
- process.exit(1);
2243
- }
2244
- try {
2245
- const content = fs12.readFileSync(options.mapping, "utf-8");
2246
- customMapping = JSON.parse(content);
2247
- } catch (error) {
2248
- console.error(`[capability] Failed to parse mapping file: ${error}`);
2249
- process.exit(1);
2562
+ const migrationOptions = {
2563
+ dryRun: options.dryRun ?? false
2564
+ };
2565
+ const result = await runCapabilityMigration(migrationOptions);
2566
+ const { jsonMigration, pluginInstallation, codeMigration, cleanup } = result;
2567
+ const jsonFailed = !jsonMigration.success && !jsonMigration.skipped;
2568
+ const codeFailed = codeMigration.autoMigrated.some((f) => !f.success);
2569
+ if (jsonFailed) {
2570
+ return {
2571
+ success: false,
2572
+ message: jsonMigration.reason || "JSON migration failed",
2573
+ error: new Error(jsonMigration.reason || "Unknown error")
2574
+ };
2575
+ }
2576
+ if (codeFailed) {
2577
+ return {
2578
+ success: false,
2579
+ message: "Code migration failed",
2580
+ error: new Error("Some files failed to migrate")
2581
+ };
2582
+ }
2583
+ const messages = [];
2584
+ if (jsonMigration.success) {
2585
+ messages.push(`${jsonMigration.count} capabilities migrated`);
2586
+ }
2587
+ if (pluginInstallation.installed.length > 0) {
2588
+ messages.push(`${pluginInstallation.installed.length} plugins installed`);
2589
+ }
2590
+ if (codeMigration.autoMigrated.length > 0) {
2591
+ const successCount = codeMigration.autoMigrated.filter((f) => f.success).length;
2592
+ if (successCount > 0) {
2593
+ messages.push(`${successCount} files auto-migrated`);
2250
2594
  }
2251
2595
  }
2252
- const migrationOptions = {
2253
- dryRun: options.dryRun,
2254
- skipInstall: options.skipInstall,
2255
- skipCode: options.skipCode,
2256
- mapping: customMapping
2596
+ if (cleanup.deletedFiles.length > 0) {
2597
+ messages.push(`${cleanup.deletedFiles.length} old files cleaned up`);
2598
+ }
2599
+ if (codeMigration.manualRequired.length > 0) {
2600
+ messages.push(`${codeMigration.manualRequired.length} files need manual migration`);
2601
+ }
2602
+ if (pluginInstallation.failed.length > 0) {
2603
+ messages.push(`${pluginInstallation.failed.length} plugins failed to install`);
2604
+ }
2605
+ return {
2606
+ success: true,
2607
+ message: messages.join(", ") || "No migration needed"
2257
2608
  };
2258
- await runMigration(migrationOptions);
2259
2609
  } catch (error) {
2260
- console.error(`[capability] Migration failed: ${error}`);
2261
- process.exit(1);
2610
+ const err = error instanceof Error ? error : new Error(String(error));
2611
+ return {
2612
+ success: false,
2613
+ message: err.message,
2614
+ error: err
2615
+ };
2262
2616
  }
2263
2617
  }
2264
2618
 
2265
- // src/commands/capability/index.ts
2266
- var listCommand2 = {
2267
- name: "list",
2268
- description: "List capability configurations",
2269
- aliases: ["ls"],
2270
- register(program) {
2271
- program.command(this.name).alias("ls").description(this.description).option("--summary", "Return raw capability config (without hydration)").option("--id <id>", "Specify capability ID").action(async (options) => {
2272
- await list2(options);
2273
- });
2274
- }
2619
+ // src/commands/migration/versions/v001_capability/index.ts
2620
+ var v001CapabilityMigration = {
2621
+ version: 1,
2622
+ name: "capability",
2623
+ description: "Migrate capability configurations from old format (capabilities.json array) to new format (individual JSON files)",
2624
+ check,
2625
+ run: run3
2275
2626
  };
2627
+
2628
+ // src/commands/migration/versions/index.ts
2629
+ var versionedMigrations = [
2630
+ v001CapabilityMigration
2631
+ // 未来新增的迁移脚本在此添加,如:
2632
+ // v002ConfigMigration,
2633
+ // v003RoutesMigration,
2634
+ ];
2635
+ function getPendingMigrations(currentVersion) {
2636
+ return versionedMigrations.filter((m) => m.version > currentVersion).sort((a, b) => a.version - b.version);
2637
+ }
2638
+ function getLatestVersion() {
2639
+ if (versionedMigrations.length === 0) return 0;
2640
+ return Math.max(...versionedMigrations.map((m) => m.version));
2641
+ }
2642
+
2643
+ // src/commands/migration/runner.ts
2644
+ function log(message) {
2645
+ console.log(`[migration] ${message}`);
2646
+ }
2647
+ async function executeSingle(migration, options) {
2648
+ const { version, name } = migration;
2649
+ const versionTag = `v${version}`;
2650
+ try {
2651
+ log(`Checking [${versionTag}] ${name}...`);
2652
+ const checkResult = await migration.check(options);
2653
+ if (!checkResult.needsMigration) {
2654
+ log(`[${versionTag}] ${name}: no migration needed`);
2655
+ return {
2656
+ name,
2657
+ status: "skipped",
2658
+ message: checkResult.message || "No migration needed"
2659
+ };
2660
+ }
2661
+ log(`[${versionTag}] ${name}: needs migration (${checkResult.message})`);
2662
+ if (checkResult.items && checkResult.items.length > 0) {
2663
+ for (const item of checkResult.items) {
2664
+ console.log(` - ${item}`);
2665
+ }
2666
+ }
2667
+ if (options.dryRun) {
2668
+ return {
2669
+ name,
2670
+ status: "skipped",
2671
+ message: `Dry-run: ${checkResult.message}`
2672
+ };
2673
+ }
2674
+ log(`Running [${versionTag}] ${name} migration...`);
2675
+ const runResult = await migration.run(options);
2676
+ if (runResult.success) {
2677
+ log(`\u2713 [${versionTag}] ${name}: completed (${runResult.message})`);
2678
+ return {
2679
+ name,
2680
+ status: "completed",
2681
+ message: runResult.message
2682
+ };
2683
+ } else {
2684
+ log(`\u2717 [${versionTag}] ${name}: failed`);
2685
+ if (runResult.error) {
2686
+ console.log(` Error: ${runResult.error.message}`);
2687
+ }
2688
+ return {
2689
+ name,
2690
+ status: "failed",
2691
+ message: runResult.message,
2692
+ error: runResult.error
2693
+ };
2694
+ }
2695
+ } catch (error) {
2696
+ const err = error instanceof Error ? error : new Error(String(error));
2697
+ log(`\u2717 [${versionTag}] ${name}: failed`);
2698
+ console.log(` Error: ${err.message}`);
2699
+ return {
2700
+ name,
2701
+ status: "failed",
2702
+ message: err.message,
2703
+ error: err
2704
+ };
2705
+ }
2706
+ }
2707
+ function printSummary2(summary, dryRun) {
2708
+ console.log("");
2709
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
2710
+ console.log(dryRun ? "Dry-run Summary:" : "Migration Summary:");
2711
+ if (dryRun) {
2712
+ const needsMigration = summary.skipped.filter((s) => s.message.startsWith("Dry-run:")).length;
2713
+ const noAction = summary.skipped.filter((s) => !s.message.startsWith("Dry-run:")).length;
2714
+ console.log(` Needs migration: ${needsMigration}`);
2715
+ console.log(` No action needed: ${noAction}`);
2716
+ } else {
2717
+ console.log(` \u2713 Completed: ${summary.completed.length}`);
2718
+ console.log(` \u25CB Skipped: ${summary.skipped.length} (no migration needed)`);
2719
+ console.log(` \u2717 Failed: ${summary.failed.length}`);
2720
+ }
2721
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
2722
+ }
2723
+ async function runMigrations(options) {
2724
+ const currentVersion = getCurrentVersion();
2725
+ const latestVersion = getLatestVersion();
2726
+ console.log("");
2727
+ log(`Current version: ${currentVersion || "0 (not set)"}`);
2728
+ if (currentVersion >= latestVersion) {
2729
+ log("All migrations are up to date.");
2730
+ return {
2731
+ needsMigration: false,
2732
+ completed: [],
2733
+ skipped: [],
2734
+ failed: []
2735
+ };
2736
+ }
2737
+ const pendingMigrations = getPendingMigrations(currentVersion);
2738
+ if (options.dryRun) {
2739
+ log("Dry-run mode enabled, no changes will be made.");
2740
+ } else {
2741
+ log("Applying migrations...");
2742
+ }
2743
+ console.log("");
2744
+ const summary = {
2745
+ needsMigration: false,
2746
+ completed: [],
2747
+ skipped: [],
2748
+ failed: []
2749
+ };
2750
+ let hasAnyMigration = false;
2751
+ for (const migration of pendingMigrations) {
2752
+ const result = await executeSingle(migration, options);
2753
+ switch (result.status) {
2754
+ case "completed":
2755
+ summary.completed.push(result);
2756
+ hasAnyMigration = true;
2757
+ if (!options.dryRun) {
2758
+ setCurrentVersion(migration.version);
2759
+ }
2760
+ break;
2761
+ case "skipped":
2762
+ summary.skipped.push(result);
2763
+ if (result.message.startsWith("Dry-run:")) {
2764
+ hasAnyMigration = true;
2765
+ }
2766
+ break;
2767
+ case "failed":
2768
+ summary.failed.push(result);
2769
+ hasAnyMigration = true;
2770
+ log("Migration aborted due to failure.");
2771
+ printSummary2(summary, !!options.dryRun);
2772
+ return summary;
2773
+ }
2774
+ console.log("");
2775
+ }
2776
+ summary.needsMigration = hasAnyMigration;
2777
+ if (currentVersion === 0 && !hasAnyMigration && !options.dryRun) {
2778
+ log(`All migrations skipped. Project is up to date.`);
2779
+ log(`Updated migrationVersion to ${latestVersion}.`);
2780
+ setCurrentVersion(latestVersion);
2781
+ } else if (!options.dryRun && summary.completed.length > 0) {
2782
+ log(`Migration complete. Updated to version ${getCurrentVersion()}.`);
2783
+ }
2784
+ printSummary2(summary, !!options.dryRun);
2785
+ return summary;
2786
+ }
2787
+ async function checkMigrations(options) {
2788
+ const currentVersion = getCurrentVersion();
2789
+ const latestVersion = getLatestVersion();
2790
+ console.log("");
2791
+ log(`Current version: ${currentVersion || "0 (not set)"}`);
2792
+ if (currentVersion >= latestVersion) {
2793
+ log("All migrations are up to date.");
2794
+ return {
2795
+ needsMigration: false,
2796
+ completed: [],
2797
+ skipped: [],
2798
+ failed: []
2799
+ };
2800
+ }
2801
+ log("Checking pending migrations...");
2802
+ console.log("");
2803
+ const pendingMigrations = getPendingMigrations(currentVersion);
2804
+ const summary = {
2805
+ needsMigration: false,
2806
+ completed: [],
2807
+ skipped: [],
2808
+ failed: []
2809
+ };
2810
+ let needsCount = 0;
2811
+ let noActionCount = 0;
2812
+ for (const migration of pendingMigrations) {
2813
+ const { version, name } = migration;
2814
+ const versionTag = `v${version}`;
2815
+ try {
2816
+ const checkResult = await migration.check(options);
2817
+ if (checkResult.needsMigration) {
2818
+ needsCount++;
2819
+ console.log(` ${versionTag} (${name}): needs migration`);
2820
+ if (checkResult.items && checkResult.items.length > 0) {
2821
+ for (const item of checkResult.items) {
2822
+ console.log(` - ${item}`);
2823
+ }
2824
+ }
2825
+ summary.skipped.push({
2826
+ name,
2827
+ status: "skipped",
2828
+ message: `Needs migration: ${checkResult.message}`
2829
+ });
2830
+ } else {
2831
+ noActionCount++;
2832
+ console.log(` ${versionTag} (${name}): no migration needed`);
2833
+ summary.skipped.push({
2834
+ name,
2835
+ status: "skipped",
2836
+ message: checkResult.message || "No migration needed"
2837
+ });
2838
+ }
2839
+ } catch (error) {
2840
+ const err = error instanceof Error ? error : new Error(String(error));
2841
+ console.log(` ${versionTag} (${name}): check failed`);
2842
+ console.log(` Error: ${err.message}`);
2843
+ summary.failed.push({
2844
+ name,
2845
+ status: "failed",
2846
+ message: err.message,
2847
+ error: err
2848
+ });
2849
+ }
2850
+ }
2851
+ console.log("");
2852
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
2853
+ console.log("Check Summary:");
2854
+ console.log(` Needs migration: ${needsCount}`);
2855
+ console.log(` No action needed: ${noActionCount}`);
2856
+ if (summary.failed.length > 0) {
2857
+ console.log(` Check failed: ${summary.failed.length}`);
2858
+ }
2859
+ console.log("\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
2860
+ if (needsCount > 0) {
2861
+ console.log("");
2862
+ log("Run 'fullstack-cli migration' to apply.");
2863
+ }
2864
+ summary.needsMigration = needsCount > 0;
2865
+ if (needsCount === 0 && summary.failed.length === 0) {
2866
+ setCurrentVersion(latestVersion);
2867
+ console.log("");
2868
+ log(`Updated migrationVersion to ${latestVersion}.`);
2869
+ }
2870
+ return summary;
2871
+ }
2872
+
2873
+ // src/commands/migration/index.ts
2276
2874
  var migrationCommand = {
2277
2875
  name: "migration",
2278
- description: "Execute capability migration",
2876
+ description: "Run versioned migration scripts",
2279
2877
  register(program) {
2280
- 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) => {
2281
- await migration(options);
2878
+ const migrationCmd = program.command(this.name).description("Run all pending migrations based on current migrationVersion").option("--dry-run", "Preview mode, only run check() without executing run()").action(async (options) => {
2879
+ const summary = await runMigrations(options);
2880
+ if (summary.failed.length > 0) {
2881
+ process.exit(1);
2882
+ }
2883
+ });
2884
+ migrationCmd.command("check").description("Check pending migrations without applying them").action(async () => {
2885
+ const summary = await checkMigrations({});
2886
+ if (summary.failed.length > 0) {
2887
+ process.exit(2);
2888
+ } else if (summary.needsMigration) {
2889
+ process.exit(1);
2890
+ }
2282
2891
  });
2283
2892
  }
2284
2893
  };
2285
- var capabilityCommandGroup = {
2286
- name: "capability",
2287
- description: "Manage capability configurations",
2288
- commands: [listCommand2, migrationCommand]
2289
- };
2290
2894
 
2291
2895
  // src/commands/index.ts
2292
2896
  var commands = [
2293
2897
  genDbSchemaCommand,
2294
2898
  syncCommand,
2295
2899
  actionPluginCommandGroup,
2296
- capabilityCommandGroup
2900
+ capabilityCommandGroup,
2901
+ migrationCommand
2297
2902
  ];
2298
2903
 
2299
2904
  // src/index.ts
2300
- var envPath = path11.join(process.cwd(), ".env");
2301
- if (fs13.existsSync(envPath)) {
2905
+ var envPath = path14.join(process.cwd(), ".env");
2906
+ if (fs15.existsSync(envPath)) {
2302
2907
  dotenvConfig({ path: envPath });
2303
2908
  }
2304
- var __dirname = path11.dirname(fileURLToPath3(import.meta.url));
2305
- var pkg = JSON.parse(fs13.readFileSync(path11.join(__dirname, "../package.json"), "utf-8"));
2909
+ var __dirname = path14.dirname(fileURLToPath3(import.meta.url));
2910
+ var pkg = JSON.parse(fs15.readFileSync(path14.join(__dirname, "../package.json"), "utf-8"));
2306
2911
  var cli = new FullstackCLI(pkg.version);
2307
2912
  cli.useAll(commands);
2308
2913
  cli.run();