@lark-apaas/fullstack-cli 1.1.20 → 1.1.22

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 +417 -104
  2. package/package.json +6 -1
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/index.ts
2
- import fs21 from "fs";
3
- import path17 from "path";
2
+ import fs22 from "fs";
3
+ import path18 from "path";
4
4
  import { fileURLToPath as fileURLToPath4 } from "url";
5
5
  import { config as dotenvConfig } from "dotenv";
6
6
 
@@ -3452,59 +3452,344 @@ var capabilityCommandGroup = {
3452
3452
  commands: [listCommand2]
3453
3453
  };
3454
3454
 
3455
- // src/commands/migration/version-manager.ts
3455
+ // src/commands/component/registry-preparer.ts
3456
3456
  import fs10 from "fs";
3457
3457
  import path8 from "path";
3458
+ import os from "os";
3459
+
3460
+ // src/commands/component/service.ts
3461
+ import { mapValues } from "es-toolkit";
3462
+
3463
+ // src/commands/component/utils.ts
3464
+ import createDebug from "debug";
3465
+ var debug = createDebug("component");
3466
+
3467
+ // src/commands/component/service.ts
3468
+ async function getComponents(keys) {
3469
+ const client = getHttpClient();
3470
+ debug("\u8C03\u7528 /components/batch_get %o", keys);
3471
+ const response = await client.post(
3472
+ `/api/v1/studio/innerapi/components/batch_get?keys=${keys.join(",")}`
3473
+ );
3474
+ if (response.status !== 200) {
3475
+ throw new Error(
3476
+ `\u83B7\u53D6\u7EC4\u4EF6\u4FE1\u606F\u5931\u8D25\uFF1A${response.status} ${response.statusText}`
3477
+ );
3478
+ }
3479
+ const result = await response.json();
3480
+ if (result.status_code !== "0") {
3481
+ debug("\u63A5\u53E3\u8FD4\u56DE\u9519\u8BEF\uFF1A%o", result);
3482
+ throw new Error(`\u83B7\u53D6\u7EC4\u4EF6\u4FE1\u606F\u5931\u8D25\uFF1A${result.error_msg}`);
3483
+ }
3484
+ return mapValues(result.data.components, ([component]) => component);
3485
+ }
3486
+ async function getRegistryItem(url) {
3487
+ const client = getHttpClient();
3488
+ debug("\u4E0B\u8F7D registry-item.json\uFF1A%s", url);
3489
+ const response = await client.get(url);
3490
+ if (!response.ok) {
3491
+ throw new Error(
3492
+ `\u4E0B\u8F7D registry-item.json \u5931\u8D25\uFF1A${response.status} ${response.statusText}`
3493
+ );
3494
+ }
3495
+ const item = await response.json();
3496
+ return item;
3497
+ }
3498
+ async function sendInstallEvent(key) {
3499
+ const client = getHttpClient();
3500
+ await client.post("/api/v1/studio/innerapi/resource_events", {
3501
+ events: [
3502
+ {
3503
+ resourceType: "component",
3504
+ resourceKey: key,
3505
+ eventType: "install",
3506
+ details: {}
3507
+ }
3508
+ ]
3509
+ });
3510
+ }
3511
+
3512
+ // src/commands/component/registry-preparer.ts
3513
+ var REGISTRY_TEMP_DIR = path8.join(os.tmpdir(), "miaoda-registry");
3514
+ function parseComponentKey(key) {
3515
+ const match = key.match(/^@([^/]+)\/(.+)$/);
3516
+ if (!match) {
3517
+ throw new Error(
3518
+ `Invalid component key format: ${key}. Expected format: @scope/name`
3519
+ );
3520
+ }
3521
+ return { scope: match[1], name: match[2] };
3522
+ }
3523
+ function getLocalRegistryPath(key) {
3524
+ const { scope, name } = parseComponentKey(key);
3525
+ return path8.join(REGISTRY_TEMP_DIR, scope, `${name}.json`);
3526
+ }
3527
+ function ensureDir(dirPath) {
3528
+ if (!fs10.existsSync(dirPath)) {
3529
+ fs10.mkdirSync(dirPath, { recursive: true });
3530
+ }
3531
+ }
3532
+ async function prepareRecursive(key, visited) {
3533
+ if (visited.has(key)) {
3534
+ debug("\u8DF3\u8FC7\u5DF2\u5904\u7406\u7684\u7EC4\u4EF6: %s", key);
3535
+ return;
3536
+ }
3537
+ visited.add(key);
3538
+ debug("\u5904\u7406\u7EC4\u4EF6: %s", key);
3539
+ debug("\u83B7\u53D6\u7EC4\u4EF6\u4E0B\u8F7D\u4FE1\u606F...");
3540
+ const infoMap = await getComponents([key]);
3541
+ const info = infoMap[key];
3542
+ debug("\u7EC4\u4EF6\u4FE1\u606F: %o", info);
3543
+ if (!info) {
3544
+ throw new Error(`Component not found: ${key}`);
3545
+ }
3546
+ if (info.status !== "active") {
3547
+ throw new Error(`Component is not active: ${key}`);
3548
+ }
3549
+ debug("\u4E0B\u8F7D registry item: %s", info.downloadURL);
3550
+ const registryItem = await getRegistryItem(info.downloadURL);
3551
+ debug("registry item \u5185\u5BB9: %o", registryItem);
3552
+ const deps = registryItem.registryDependencies || [];
3553
+ debug("\u4F9D\u8D56\u5217\u8868: %o", deps);
3554
+ for (const dep of deps) {
3555
+ await prepareRecursive(dep, visited);
3556
+ }
3557
+ const rewrittenItem = {
3558
+ ...registryItem,
3559
+ registryDependencies: deps.map((dep) => getLocalRegistryPath(dep))
3560
+ };
3561
+ const localPath = getLocalRegistryPath(key);
3562
+ ensureDir(path8.dirname(localPath));
3563
+ fs10.writeFileSync(localPath, JSON.stringify(rewrittenItem, null, 2), "utf-8");
3564
+ debug("\u4FDD\u5B58\u5230: %s", localPath);
3565
+ }
3566
+ async function prepareComponentRegistryItems(id) {
3567
+ const visited = /* @__PURE__ */ new Set();
3568
+ await prepareRecursive(id, visited);
3569
+ return getLocalRegistryPath(id);
3570
+ }
3571
+ function cleanupTempDir() {
3572
+ try {
3573
+ if (fs10.existsSync(REGISTRY_TEMP_DIR)) {
3574
+ fs10.rmSync(REGISTRY_TEMP_DIR, { recursive: true, force: true });
3575
+ }
3576
+ } catch {
3577
+ }
3578
+ }
3579
+ function getDownloadedRegistryItem(itemId) {
3580
+ const localPath = getLocalRegistryPath(itemId);
3581
+ if (!fs10.existsSync(localPath)) {
3582
+ return null;
3583
+ }
3584
+ const content = fs10.readFileSync(localPath, "utf-8");
3585
+ return JSON.parse(content);
3586
+ }
3587
+
3588
+ // src/commands/component/shadcn-executor.ts
3589
+ import * as pty from "@lydell/node-pty";
3590
+ function parseOutput(output) {
3591
+ const state = {
3592
+ currentSection: null,
3593
+ files: /* @__PURE__ */ new Set()
3594
+ };
3595
+ const lines = output.split("\n");
3596
+ for (const line of lines) {
3597
+ const trimmedLine = line.trim();
3598
+ if (/Created \d+ files?:/.test(trimmedLine)) {
3599
+ state.currentSection = "created";
3600
+ continue;
3601
+ }
3602
+ if (/Updated \d+ files?:/.test(trimmedLine)) {
3603
+ state.currentSection = "updated";
3604
+ continue;
3605
+ }
3606
+ if (/Skipped \d+ files?:/.test(trimmedLine)) {
3607
+ state.currentSection = "skipped";
3608
+ continue;
3609
+ }
3610
+ if (state.currentSection && trimmedLine.startsWith("- ")) {
3611
+ const filePath = trimmedLine.slice(2).trim();
3612
+ if (filePath && filePath.includes("/")) {
3613
+ state.files.add(filePath);
3614
+ }
3615
+ }
3616
+ if (state.currentSection && trimmedLine.length > 1 && !trimmedLine.startsWith("- ")) {
3617
+ state.currentSection = null;
3618
+ }
3619
+ }
3620
+ return Array.from(state.files);
3621
+ }
3622
+ function toFileInfo(filePath) {
3623
+ const name = filePath.split("/").pop() || filePath;
3624
+ return { name, path: filePath };
3625
+ }
3626
+ var PROMPT_PATTERNS = [
3627
+ // 文件覆盖确认 - 回答 n(不覆盖)
3628
+ { pattern: /overwrite/i, answer: "n\n" },
3629
+ // 主题/样式选择 - 回答 n(不安装额外主题)
3630
+ { pattern: /theme/i, answer: "n\n" },
3631
+ { pattern: /style/i, answer: "n\n" },
3632
+ // 继续确认 - 回答 y
3633
+ { pattern: /continue\?/i, answer: "y\n" },
3634
+ { pattern: /proceed\?/i, answer: "y\n" }
3635
+ ];
3636
+ async function executeShadcnAdd(registryItemPath) {
3637
+ return new Promise((resolve) => {
3638
+ let output = "";
3639
+ const args = ["--yes", "shadcn@3.8.2", "add", registryItemPath];
3640
+ const ptyProcess = pty.spawn("npx", args, {
3641
+ name: "xterm-color",
3642
+ cols: 120,
3643
+ rows: 30,
3644
+ cwd: process.cwd(),
3645
+ env: {
3646
+ ...process.env,
3647
+ // 禁用颜色输出以便解析
3648
+ NO_COLOR: "1",
3649
+ FORCE_COLOR: "0"
3650
+ }
3651
+ });
3652
+ ptyProcess.onData((data) => {
3653
+ output += data;
3654
+ for (const { pattern, answer } of PROMPT_PATTERNS) {
3655
+ if (pattern.test(data)) {
3656
+ ptyProcess.write(answer);
3657
+ return;
3658
+ }
3659
+ }
3660
+ });
3661
+ const timeoutId = setTimeout(() => {
3662
+ ptyProcess.kill();
3663
+ resolve({
3664
+ success: false,
3665
+ files: [],
3666
+ error: "\u6267\u884C\u8D85\u65F6"
3667
+ });
3668
+ }, 3 * 60 * 1e3);
3669
+ ptyProcess.onExit(({ exitCode }) => {
3670
+ clearTimeout(timeoutId);
3671
+ const success = exitCode === 0;
3672
+ const filePaths = parseOutput(output);
3673
+ const files = filePaths.map(toFileInfo);
3674
+ resolve({
3675
+ success,
3676
+ files,
3677
+ error: success ? void 0 : output || `Process exited with code ${exitCode}`
3678
+ });
3679
+ });
3680
+ });
3681
+ }
3682
+
3683
+ // src/commands/component/add.handler.ts
3684
+ function printResult(result) {
3685
+ console.log(JSON.stringify(result, null, 2));
3686
+ }
3687
+ async function addComponent(key) {
3688
+ debug("\u5F00\u59CB\u5B89\u88C5\u7EC4\u4EF6: %s", key);
3689
+ debug("\u51C6\u5907 registry items...");
3690
+ const registryItemPath = await prepareComponentRegistryItems(key);
3691
+ debug("registry item \u8DEF\u5F84: %s", registryItemPath);
3692
+ const registryItem = getDownloadedRegistryItem(key);
3693
+ debug("\u83B7\u53D6\u5230 registry item: %o", registryItem);
3694
+ debug("\u6267\u884C shadcn add...");
3695
+ const executeResult = await executeShadcnAdd(registryItemPath);
3696
+ debug("shadcn \u6267\u884C\u7ED3\u679C: %o", executeResult);
3697
+ if (!executeResult.success) {
3698
+ throw new Error(executeResult.error || "\u5B89\u88C5\u5931\u8D25\uFF0C\u672A\u77E5\u539F\u56E0");
3699
+ }
3700
+ return {
3701
+ success: true,
3702
+ name: key,
3703
+ description: registryItem?.description || "",
3704
+ files: executeResult.files,
3705
+ docs: registryItem?.docs || ""
3706
+ };
3707
+ }
3708
+ async function add(key) {
3709
+ try {
3710
+ const result = await addComponent(key);
3711
+ printResult(result);
3712
+ void sendInstallEvent(key);
3713
+ } catch (error) {
3714
+ const errorMessage = error instanceof Error ? error.message : "\u5B89\u88C5\u5931\u8D25\uFF0C\u539F\u56E0\u672A\u77E5";
3715
+ printResult({
3716
+ success: false,
3717
+ errors: [{ message: errorMessage }]
3718
+ });
3719
+ } finally {
3720
+ cleanupTempDir();
3721
+ }
3722
+ }
3723
+
3724
+ // src/commands/component/index.ts
3725
+ var addCommand = {
3726
+ name: "add",
3727
+ description: "\u5B89\u88C5\u5999\u642D\u7EC4\u4EF6\u5E02\u573A\u4E2D\u7684\u7EC4\u4EF6",
3728
+ register(program) {
3729
+ program.command(this.name).description(this.description).argument("<component>", "\u7EC4\u4EF6 ID (\u4F8B\u5982 @miaoda/button)").action(async (component) => {
3730
+ await add(component);
3731
+ });
3732
+ }
3733
+ };
3734
+ var componentCommandGroup = {
3735
+ name: "component",
3736
+ description: "\u7EC4\u4EF6\u76F8\u5173\u547D\u4EE4",
3737
+ commands: [addCommand]
3738
+ };
3739
+
3740
+ // src/commands/migration/version-manager.ts
3741
+ import fs11 from "fs";
3742
+ import path9 from "path";
3458
3743
  var PACKAGE_JSON = "package.json";
3459
3744
  var VERSION_FIELD = "migrationVersion";
3460
3745
  function getPackageJsonPath2() {
3461
- return path8.join(process.cwd(), PACKAGE_JSON);
3746
+ return path9.join(process.cwd(), PACKAGE_JSON);
3462
3747
  }
3463
3748
  function getCurrentVersion() {
3464
3749
  const pkgPath = getPackageJsonPath2();
3465
- if (!fs10.existsSync(pkgPath)) {
3750
+ if (!fs11.existsSync(pkgPath)) {
3466
3751
  throw new Error("package.json not found");
3467
3752
  }
3468
- const pkg2 = JSON.parse(fs10.readFileSync(pkgPath, "utf-8"));
3753
+ const pkg2 = JSON.parse(fs11.readFileSync(pkgPath, "utf-8"));
3469
3754
  return pkg2[VERSION_FIELD] ?? 0;
3470
3755
  }
3471
3756
  function setCurrentVersion(version) {
3472
3757
  const pkgPath = getPackageJsonPath2();
3473
- const pkg2 = JSON.parse(fs10.readFileSync(pkgPath, "utf-8"));
3758
+ const pkg2 = JSON.parse(fs11.readFileSync(pkgPath, "utf-8"));
3474
3759
  pkg2[VERSION_FIELD] = version;
3475
- fs10.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
3760
+ fs11.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
3476
3761
  }
3477
3762
 
3478
3763
  // src/commands/migration/versions/v001_capability/json-migrator/detector.ts
3479
- import fs12 from "fs";
3480
- import path10 from "path";
3764
+ import fs13 from "fs";
3765
+ import path11 from "path";
3481
3766
 
3482
3767
  // src/commands/migration/versions/v001_capability/utils.ts
3483
- import fs11 from "fs";
3484
- import path9 from "path";
3768
+ import fs12 from "fs";
3769
+ import path10 from "path";
3485
3770
  var CAPABILITIES_DIR2 = "server/capabilities";
3486
3771
  function getProjectRoot3() {
3487
3772
  return process.cwd();
3488
3773
  }
3489
3774
  function getCapabilitiesDir2() {
3490
- return path9.join(getProjectRoot3(), CAPABILITIES_DIR2);
3775
+ return path10.join(getProjectRoot3(), CAPABILITIES_DIR2);
3491
3776
  }
3492
3777
  function getPluginManifestPath2(pluginKey) {
3493
- return path9.join(getProjectRoot3(), "node_modules", pluginKey, "manifest.json");
3778
+ return path10.join(getProjectRoot3(), "node_modules", pluginKey, "manifest.json");
3494
3779
  }
3495
3780
 
3496
3781
  // src/commands/migration/versions/v001_capability/json-migrator/detector.ts
3497
3782
  function detectJsonMigration() {
3498
3783
  const capabilitiesDir = getCapabilitiesDir2();
3499
- const oldFilePath = path10.join(capabilitiesDir, "capabilities.json");
3500
- if (!fs12.existsSync(oldFilePath)) {
3784
+ const oldFilePath = path11.join(capabilitiesDir, "capabilities.json");
3785
+ if (!fs13.existsSync(oldFilePath)) {
3501
3786
  return {
3502
3787
  needsMigration: false,
3503
3788
  reason: "capabilities.json not found"
3504
3789
  };
3505
3790
  }
3506
3791
  try {
3507
- const content = fs12.readFileSync(oldFilePath, "utf-8");
3792
+ const content = fs13.readFileSync(oldFilePath, "utf-8");
3508
3793
  const parsed = JSON.parse(content);
3509
3794
  if (!Array.isArray(parsed)) {
3510
3795
  return {
@@ -3555,8 +3840,8 @@ async function check(options) {
3555
3840
  }
3556
3841
 
3557
3842
  // src/commands/migration/versions/v001_capability/json-migrator/index.ts
3558
- import fs13 from "fs";
3559
- import path11 from "path";
3843
+ import fs14 from "fs";
3844
+ import path12 from "path";
3560
3845
 
3561
3846
  // src/commands/migration/versions/v001_capability/mapping.ts
3562
3847
  var DEFAULT_PLUGIN_VERSION = "1.0.0";
@@ -3786,18 +4071,18 @@ function transformCapabilities(oldCapabilities) {
3786
4071
  // src/commands/migration/versions/v001_capability/json-migrator/index.ts
3787
4072
  function loadExistingCapabilities() {
3788
4073
  const capabilitiesDir = getCapabilitiesDir2();
3789
- if (!fs13.existsSync(capabilitiesDir)) {
4074
+ if (!fs14.existsSync(capabilitiesDir)) {
3790
4075
  return [];
3791
4076
  }
3792
- const files = fs13.readdirSync(capabilitiesDir);
4077
+ const files = fs14.readdirSync(capabilitiesDir);
3793
4078
  const capabilities = [];
3794
4079
  for (const file of files) {
3795
4080
  if (file === "capabilities.json" || !file.endsWith(".json")) {
3796
4081
  continue;
3797
4082
  }
3798
4083
  try {
3799
- const filePath = path11.join(capabilitiesDir, file);
3800
- const content = fs13.readFileSync(filePath, "utf-8");
4084
+ const filePath = path12.join(capabilitiesDir, file);
4085
+ const content = fs14.readFileSync(filePath, "utf-8");
3801
4086
  const capability = JSON.parse(content);
3802
4087
  if (capability.id && capability.pluginKey) {
3803
4088
  capabilities.push(capability);
@@ -3855,9 +4140,9 @@ async function migrateJsonFiles(options) {
3855
4140
  }
3856
4141
  const capabilitiesDir = getCapabilitiesDir2();
3857
4142
  for (const cap of newCapabilities) {
3858
- const filePath = path11.join(capabilitiesDir, `${cap.id}.json`);
4143
+ const filePath = path12.join(capabilitiesDir, `${cap.id}.json`);
3859
4144
  const content = JSON.stringify(cap, null, 2);
3860
- fs13.writeFileSync(filePath, content, "utf-8");
4145
+ fs14.writeFileSync(filePath, content, "utf-8");
3861
4146
  console.log(` \u2713 Created: ${cap.id}.json`);
3862
4147
  }
3863
4148
  return {
@@ -3869,11 +4154,11 @@ async function migrateJsonFiles(options) {
3869
4154
  }
3870
4155
 
3871
4156
  // src/commands/migration/versions/v001_capability/plugin-installer/detector.ts
3872
- import fs14 from "fs";
4157
+ import fs15 from "fs";
3873
4158
  function isPluginInstalled2(pluginKey) {
3874
4159
  const actionPlugins = readActionPlugins();
3875
4160
  const manifestPath = getPluginManifestPath2(pluginKey);
3876
- return fs14.existsSync(manifestPath) && !!actionPlugins[pluginKey];
4161
+ return fs15.existsSync(manifestPath) && !!actionPlugins[pluginKey];
3877
4162
  }
3878
4163
  function detectPluginsToInstall(capabilities) {
3879
4164
  const pluginKeys = /* @__PURE__ */ new Set();
@@ -3949,12 +4234,12 @@ async function installPlugins(capabilities, options) {
3949
4234
  }
3950
4235
 
3951
4236
  // src/commands/migration/versions/v001_capability/code-migrator/index.ts
3952
- import path13 from "path";
4237
+ import path14 from "path";
3953
4238
  import { Project as Project3 } from "ts-morph";
3954
4239
 
3955
4240
  // src/commands/migration/versions/v001_capability/code-migrator/scanner.ts
3956
- import fs15 from "fs";
3957
- import path12 from "path";
4241
+ import fs16 from "fs";
4242
+ import path13 from "path";
3958
4243
  var EXCLUDED_DIRS = [
3959
4244
  "node_modules",
3960
4245
  "dist",
@@ -3969,9 +4254,9 @@ var EXCLUDED_PATTERNS = [
3969
4254
  /\.d\.ts$/
3970
4255
  ];
3971
4256
  function scanDirectory(dir, files = []) {
3972
- const entries = fs15.readdirSync(dir, { withFileTypes: true });
4257
+ const entries = fs16.readdirSync(dir, { withFileTypes: true });
3973
4258
  for (const entry of entries) {
3974
- const fullPath = path12.join(dir, entry.name);
4259
+ const fullPath = path13.join(dir, entry.name);
3975
4260
  if (entry.isDirectory()) {
3976
4261
  if (EXCLUDED_DIRS.includes(entry.name)) {
3977
4262
  continue;
@@ -3987,14 +4272,14 @@ function scanDirectory(dir, files = []) {
3987
4272
  return files;
3988
4273
  }
3989
4274
  function scanServerFiles() {
3990
- const serverDir = path12.join(getProjectRoot3(), "server");
3991
- if (!fs15.existsSync(serverDir)) {
4275
+ const serverDir = path13.join(getProjectRoot3(), "server");
4276
+ if (!fs16.existsSync(serverDir)) {
3992
4277
  return [];
3993
4278
  }
3994
4279
  return scanDirectory(serverDir);
3995
4280
  }
3996
4281
  function hasCapabilityImport(filePath) {
3997
- const content = fs15.readFileSync(filePath, "utf-8");
4282
+ const content = fs16.readFileSync(filePath, "utf-8");
3998
4283
  return /import\s+.*from\s+['"][^'"]*capabilities[^'"]*['"]/.test(content);
3999
4284
  }
4000
4285
  function scanFilesToMigrate() {
@@ -4371,7 +4656,7 @@ function analyzeFile(project, filePath, actionNameMap) {
4371
4656
  const callSites = analyzeCallSites(sourceFile, imports);
4372
4657
  const classInfo = analyzeClass(sourceFile);
4373
4658
  const { canMigrate, reason } = canAutoMigrate(classInfo);
4374
- const relativePath = path13.relative(getProjectRoot3(), filePath);
4659
+ const relativePath = path14.relative(getProjectRoot3(), filePath);
4375
4660
  return {
4376
4661
  filePath: relativePath,
4377
4662
  imports,
@@ -4382,7 +4667,7 @@ function analyzeFile(project, filePath, actionNameMap) {
4382
4667
  };
4383
4668
  }
4384
4669
  function migrateFile(project, analysis, dryRun) {
4385
- const absolutePath = path13.join(getProjectRoot3(), analysis.filePath);
4670
+ const absolutePath = path14.join(getProjectRoot3(), analysis.filePath);
4386
4671
  if (!analysis.canAutoMigrate) {
4387
4672
  return {
4388
4673
  filePath: analysis.filePath,
@@ -4485,17 +4770,17 @@ function getSuggestion(analysis) {
4485
4770
  }
4486
4771
 
4487
4772
  // src/commands/migration/versions/v001_capability/cleanup.ts
4488
- import fs16 from "fs";
4489
- import path14 from "path";
4773
+ import fs17 from "fs";
4774
+ import path15 from "path";
4490
4775
  function cleanupOldFiles(capabilities, dryRun) {
4491
4776
  const deletedFiles = [];
4492
4777
  const errors = [];
4493
4778
  const capabilitiesDir = getCapabilitiesDir2();
4494
- const oldJsonPath = path14.join(capabilitiesDir, "capabilities.json");
4495
- if (fs16.existsSync(oldJsonPath)) {
4779
+ const oldJsonPath = path15.join(capabilitiesDir, "capabilities.json");
4780
+ if (fs17.existsSync(oldJsonPath)) {
4496
4781
  try {
4497
4782
  if (!dryRun) {
4498
- fs16.unlinkSync(oldJsonPath);
4783
+ fs17.unlinkSync(oldJsonPath);
4499
4784
  }
4500
4785
  deletedFiles.push("capabilities.json");
4501
4786
  } catch (error) {
@@ -4503,11 +4788,11 @@ function cleanupOldFiles(capabilities, dryRun) {
4503
4788
  }
4504
4789
  }
4505
4790
  for (const cap of capabilities) {
4506
- const tsFilePath = path14.join(capabilitiesDir, `${cap.id}.ts`);
4507
- if (fs16.existsSync(tsFilePath)) {
4791
+ const tsFilePath = path15.join(capabilitiesDir, `${cap.id}.ts`);
4792
+ if (fs17.existsSync(tsFilePath)) {
4508
4793
  try {
4509
4794
  if (!dryRun) {
4510
- fs16.unlinkSync(tsFilePath);
4795
+ fs17.unlinkSync(tsFilePath);
4511
4796
  }
4512
4797
  deletedFiles.push(`${cap.id}.ts`);
4513
4798
  } catch (error) {
@@ -4523,8 +4808,8 @@ function cleanupOldFiles(capabilities, dryRun) {
4523
4808
  }
4524
4809
 
4525
4810
  // src/commands/migration/versions/v001_capability/report-generator.ts
4526
- import fs17 from "fs";
4527
- import path15 from "path";
4811
+ import fs18 from "fs";
4812
+ import path16 from "path";
4528
4813
  var REPORT_FILE = "capability-migration-report.md";
4529
4814
  function printSummary(result) {
4530
4815
  const { jsonMigration, pluginInstallation, codeMigration, cleanup } = result;
@@ -4687,15 +4972,15 @@ async function generateReport(result) {
4687
4972
  }
4688
4973
  lines.push("");
4689
4974
  const logDir = process.env.LOG_DIR || "logs";
4690
- if (!fs17.existsSync(logDir)) {
4975
+ if (!fs18.existsSync(logDir)) {
4691
4976
  return;
4692
4977
  }
4693
- const reportDir = path15.join(logDir, "migration");
4694
- if (!fs17.existsSync(reportDir)) {
4695
- fs17.mkdirSync(reportDir, { recursive: true });
4978
+ const reportDir = path16.join(logDir, "migration");
4979
+ if (!fs18.existsSync(reportDir)) {
4980
+ fs18.mkdirSync(reportDir, { recursive: true });
4696
4981
  }
4697
- const reportPath = path15.join(reportDir, REPORT_FILE);
4698
- fs17.writeFileSync(reportPath, lines.join("\n"), "utf-8");
4982
+ const reportPath = path16.join(reportDir, REPORT_FILE);
4983
+ fs18.writeFileSync(reportPath, lines.join("\n"), "utf-8");
4699
4984
  console.log(`\u{1F4C4} Report generated: ${reportPath}`);
4700
4985
  }
4701
4986
 
@@ -5227,10 +5512,10 @@ var migrationCommand = {
5227
5512
  };
5228
5513
 
5229
5514
  // src/commands/read-logs/index.ts
5230
- import path16 from "path";
5515
+ import path17 from "path";
5231
5516
 
5232
5517
  // src/commands/read-logs/std-utils.ts
5233
- import fs18 from "fs";
5518
+ import fs19 from "fs";
5234
5519
  function formatStdPrefixTime(localTime) {
5235
5520
  const match = localTime.match(/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/);
5236
5521
  if (!match) return localTime;
@@ -5260,11 +5545,11 @@ function stripPrefixFromStdLine(line) {
5260
5545
  return `[${time}] ${content}`;
5261
5546
  }
5262
5547
  function readStdLinesTailFromLastMarkerPaged(filePath, maxLines, offset, isMarker) {
5263
- const stat = fs18.statSync(filePath);
5548
+ const stat = fs19.statSync(filePath);
5264
5549
  if (stat.size === 0) {
5265
5550
  return { lines: [], markerFound: false, totalLinesCount: 0 };
5266
5551
  }
5267
- const fd = fs18.openSync(filePath, "r");
5552
+ const fd = fs19.openSync(filePath, "r");
5268
5553
  const chunkSize = 64 * 1024;
5269
5554
  let position = stat.size;
5270
5555
  let remainder = "";
@@ -5278,7 +5563,7 @@ function readStdLinesTailFromLastMarkerPaged(filePath, maxLines, offset, isMarke
5278
5563
  const length = Math.min(chunkSize, position);
5279
5564
  position -= length;
5280
5565
  const buffer = Buffer.alloc(length);
5281
- fs18.readSync(fd, buffer, 0, length, position);
5566
+ fs19.readSync(fd, buffer, 0, length, position);
5282
5567
  let chunk = buffer.toString("utf8");
5283
5568
  if (remainder) {
5284
5569
  chunk += remainder;
@@ -5320,7 +5605,7 @@ function readStdLinesTailFromLastMarkerPaged(filePath, maxLines, offset, isMarke
5320
5605
  }
5321
5606
  }
5322
5607
  } finally {
5323
- fs18.closeSync(fd);
5608
+ fs19.closeSync(fd);
5324
5609
  }
5325
5610
  return { lines: collected.reverse(), markerFound, totalLinesCount };
5326
5611
  }
@@ -5341,21 +5626,21 @@ function readServerStdSegment(filePath, maxLines, offset) {
5341
5626
  }
5342
5627
 
5343
5628
  // src/commands/read-logs/tail.ts
5344
- import fs19 from "fs";
5629
+ import fs20 from "fs";
5345
5630
  function fileExists(filePath) {
5346
5631
  try {
5347
- fs19.accessSync(filePath, fs19.constants.F_OK | fs19.constants.R_OK);
5632
+ fs20.accessSync(filePath, fs20.constants.F_OK | fs20.constants.R_OK);
5348
5633
  return true;
5349
5634
  } catch {
5350
5635
  return false;
5351
5636
  }
5352
5637
  }
5353
5638
  function readFileTailLines(filePath, maxLines) {
5354
- const stat = fs19.statSync(filePath);
5639
+ const stat = fs20.statSync(filePath);
5355
5640
  if (stat.size === 0) {
5356
5641
  return [];
5357
5642
  }
5358
- const fd = fs19.openSync(filePath, "r");
5643
+ const fd = fs20.openSync(filePath, "r");
5359
5644
  const chunkSize = 64 * 1024;
5360
5645
  const chunks = [];
5361
5646
  let position = stat.size;
@@ -5365,13 +5650,13 @@ function readFileTailLines(filePath, maxLines) {
5365
5650
  const length = Math.min(chunkSize, position);
5366
5651
  position -= length;
5367
5652
  const buffer = Buffer.alloc(length);
5368
- fs19.readSync(fd, buffer, 0, length, position);
5653
+ fs20.readSync(fd, buffer, 0, length, position);
5369
5654
  chunks.unshift(buffer.toString("utf8"));
5370
5655
  const chunkLines = buffer.toString("utf8").split("\n").length - 1;
5371
5656
  collectedLines += chunkLines;
5372
5657
  }
5373
5658
  } finally {
5374
- fs19.closeSync(fd);
5659
+ fs20.closeSync(fd);
5375
5660
  }
5376
5661
  const content = chunks.join("");
5377
5662
  const allLines = content.split("\n");
@@ -5387,11 +5672,11 @@ function readFileTailLines(filePath, maxLines) {
5387
5672
  return allLines.slice(allLines.length - maxLines);
5388
5673
  }
5389
5674
  function readFileTailNonEmptyLinesWithOffset(filePath, maxLines, offset) {
5390
- const stat = fs19.statSync(filePath);
5675
+ const stat = fs20.statSync(filePath);
5391
5676
  if (stat.size === 0) {
5392
5677
  return { lines: [], totalLinesCount: 0 };
5393
5678
  }
5394
- const fd = fs19.openSync(filePath, "r");
5679
+ const fd = fs20.openSync(filePath, "r");
5395
5680
  const chunkSize = 64 * 1024;
5396
5681
  let position = stat.size;
5397
5682
  let remainder = "";
@@ -5403,7 +5688,7 @@ function readFileTailNonEmptyLinesWithOffset(filePath, maxLines, offset) {
5403
5688
  const length = Math.min(chunkSize, position);
5404
5689
  position -= length;
5405
5690
  const buffer = Buffer.alloc(length);
5406
- fs19.readSync(fd, buffer, 0, length, position);
5691
+ fs20.readSync(fd, buffer, 0, length, position);
5407
5692
  let chunk = buffer.toString("utf8");
5408
5693
  if (remainder) {
5409
5694
  chunk += remainder;
@@ -5434,7 +5719,7 @@ function readFileTailNonEmptyLinesWithOffset(filePath, maxLines, offset) {
5434
5719
  }
5435
5720
  }
5436
5721
  } finally {
5437
- fs19.closeSync(fd);
5722
+ fs20.closeSync(fd);
5438
5723
  }
5439
5724
  return { lines: collected.reverse(), totalLinesCount };
5440
5725
  }
@@ -5447,13 +5732,19 @@ function readClientStdSegment(filePath, maxLines, offset) {
5447
5732
  function extractClientStdSegment(lines, maxLines, offset) {
5448
5733
  const bodyLines = lines.map(stripPrefixFromStdLine);
5449
5734
  const hotStartMarkers = [
5735
+ // Webpack markers
5450
5736
  /file change detected\..*incremental compilation/i,
5451
5737
  /starting incremental compilation/i,
5452
5738
  /starting compilation/i,
5453
5739
  /\bcompiling\b/i,
5454
- /\brecompil/i
5740
+ /\brecompil/i,
5741
+ // Vite markers - format: "3:11:46 PM [vite] (client) hmr update ..."
5742
+ /VITE v[\d.]+.*ready/i,
5743
+ /\[vite\].*page reload/i,
5744
+ /\[vite\].*hmr update/i
5455
5745
  ];
5456
5746
  const hotEndMarkers = [
5747
+ // Webpack markers
5457
5748
  /file change detected\..*incremental compilation/i,
5458
5749
  /\bwebpack compiled\b/i,
5459
5750
  /compiled successfully/i,
@@ -5464,14 +5755,25 @@ function extractClientStdSegment(lines, maxLines, offset) {
5464
5755
  /\bhmr\b/i,
5465
5756
  /hot update/i,
5466
5757
  /\bhot reload\b/i,
5467
- /\bhmr update\b/i
5758
+ /\bhmr update\b/i,
5759
+ // Vite markers
5760
+ /VITE v[\d.]+.*ready/i,
5761
+ /\[vite\].*page reload/i,
5762
+ /\[vite\].*hmr update/i,
5763
+ /\[vite\].*hmr invalidate/i,
5764
+ /\[vite\].*internal server error/i,
5765
+ /\[vite\].*pre-transform error/i
5468
5766
  ];
5469
5767
  const compiledMarkers = [
5768
+ // Webpack markers
5470
5769
  /\bwebpack compiled\b/i,
5471
5770
  /compiled successfully/i,
5472
5771
  /compiled with warnings/i,
5473
5772
  /compiled with errors/i,
5474
- /failed to compile/i
5773
+ /failed to compile/i,
5774
+ // Vite markers
5775
+ /VITE v[\d.]+.*ready/i,
5776
+ /\[vite\].*hmr update/i
5475
5777
  ];
5476
5778
  let startIndex = -1;
5477
5779
  for (let i = bodyLines.length - 1; i >= 0; i -= 1) {
@@ -5524,14 +5826,15 @@ function extractClientStdSegment(lines, maxLines, offset) {
5524
5826
  }
5525
5827
  const segment = startIndex === -1 ? bodyLines : bodyLines.slice(startIndex);
5526
5828
  if (segment.length === 0) {
5527
- return { lines: [], totalLinesCount: 0 };
5829
+ return { lines: [], totalLinesCount: 0, allLines: [] };
5528
5830
  }
5529
5831
  const totalLinesCount = segment.length;
5530
5832
  const endExclusive = Math.max(0, segment.length - offset);
5531
5833
  const start = Math.max(0, endExclusive - maxLines);
5532
5834
  return {
5533
5835
  lines: segment.slice(start, endExclusive),
5534
- totalLinesCount
5836
+ totalLinesCount,
5837
+ allLines: segment
5535
5838
  };
5536
5839
  }
5537
5840
 
@@ -5558,7 +5861,7 @@ function readDevStdSegment(filePath, maxLines, offset) {
5558
5861
  }
5559
5862
 
5560
5863
  // src/commands/read-logs/json-lines.ts
5561
- import fs20 from "fs";
5864
+ import fs21 from "fs";
5562
5865
  function normalizePid(value) {
5563
5866
  if (typeof value === "number") {
5564
5867
  return String(value);
@@ -5609,11 +5912,11 @@ function buildWantedLevelSet(levels) {
5609
5912
  return set.size > 0 ? set : null;
5610
5913
  }
5611
5914
  function readJsonLinesLastPid(filePath, maxLines, offset, levels) {
5612
- const stat = fs20.statSync(filePath);
5915
+ const stat = fs21.statSync(filePath);
5613
5916
  if (stat.size === 0) {
5614
5917
  return { lines: [], totalLinesCount: 0 };
5615
5918
  }
5616
- const fd = fs20.openSync(filePath, "r");
5919
+ const fd = fs21.openSync(filePath, "r");
5617
5920
  const chunkSize = 64 * 1024;
5618
5921
  let position = stat.size;
5619
5922
  let remainder = "";
@@ -5628,7 +5931,7 @@ function readJsonLinesLastPid(filePath, maxLines, offset, levels) {
5628
5931
  const length = Math.min(chunkSize, position);
5629
5932
  position -= length;
5630
5933
  const buffer = Buffer.alloc(length);
5631
- fs20.readSync(fd, buffer, 0, length, position);
5934
+ fs21.readSync(fd, buffer, 0, length, position);
5632
5935
  let chunk = buffer.toString("utf8");
5633
5936
  if (remainder) {
5634
5937
  chunk += remainder;
@@ -5690,7 +5993,7 @@ function readJsonLinesLastPid(filePath, maxLines, offset, levels) {
5690
5993
  }
5691
5994
  }
5692
5995
  } finally {
5693
- fs20.closeSync(fd);
5996
+ fs21.closeSync(fd);
5694
5997
  }
5695
5998
  return { lines: collected.reverse(), totalLinesCount };
5696
5999
  }
@@ -5733,11 +6036,11 @@ function extractTraceId(obj) {
5733
6036
  function readJsonLinesByTraceId(filePath, traceId, maxLines, offset, levels) {
5734
6037
  const wanted = traceId.trim();
5735
6038
  if (!wanted) return { lines: [], totalLinesCount: 0 };
5736
- const stat = fs20.statSync(filePath);
6039
+ const stat = fs21.statSync(filePath);
5737
6040
  if (stat.size === 0) {
5738
6041
  return { lines: [], totalLinesCount: 0 };
5739
6042
  }
5740
- const fd = fs20.openSync(filePath, "r");
6043
+ const fd = fs21.openSync(filePath, "r");
5741
6044
  const chunkSize = 64 * 1024;
5742
6045
  let position = stat.size;
5743
6046
  let remainder = "";
@@ -5750,7 +6053,7 @@ function readJsonLinesByTraceId(filePath, traceId, maxLines, offset, levels) {
5750
6053
  const length = Math.min(chunkSize, position);
5751
6054
  position -= length;
5752
6055
  const buffer = Buffer.alloc(length);
5753
- fs20.readSync(fd, buffer, 0, length, position);
6056
+ fs21.readSync(fd, buffer, 0, length, position);
5754
6057
  let chunk = buffer.toString("utf8");
5755
6058
  if (remainder) {
5756
6059
  chunk += remainder;
@@ -5803,7 +6106,7 @@ function readJsonLinesByTraceId(filePath, traceId, maxLines, offset, levels) {
5803
6106
  }
5804
6107
  }
5805
6108
  } finally {
5806
- fs20.closeSync(fd);
6109
+ fs21.closeSync(fd);
5807
6110
  }
5808
6111
  return { lines: collected.reverse(), totalLinesCount };
5809
6112
  }
@@ -5812,11 +6115,11 @@ function readJsonLinesTailByLevel(filePath, maxLines, offset, levels) {
5812
6115
  if (!wantedLevelSet) {
5813
6116
  return { lines: [], totalLinesCount: 0 };
5814
6117
  }
5815
- const stat = fs20.statSync(filePath);
6118
+ const stat = fs21.statSync(filePath);
5816
6119
  if (stat.size === 0) {
5817
6120
  return { lines: [], totalLinesCount: 0 };
5818
6121
  }
5819
- const fd = fs20.openSync(filePath, "r");
6122
+ const fd = fs21.openSync(filePath, "r");
5820
6123
  const chunkSize = 64 * 1024;
5821
6124
  let position = stat.size;
5822
6125
  let remainder = "";
@@ -5828,7 +6131,7 @@ function readJsonLinesTailByLevel(filePath, maxLines, offset, levels) {
5828
6131
  const length = Math.min(chunkSize, position);
5829
6132
  position -= length;
5830
6133
  const buffer = Buffer.alloc(length);
5831
- fs20.readSync(fd, buffer, 0, length, position);
6134
+ fs21.readSync(fd, buffer, 0, length, position);
5832
6135
  let chunk = buffer.toString("utf8");
5833
6136
  if (remainder) {
5834
6137
  chunk += remainder;
@@ -5875,7 +6178,7 @@ function readJsonLinesTailByLevel(filePath, maxLines, offset, levels) {
5875
6178
  }
5876
6179
  }
5877
6180
  } finally {
5878
- fs20.closeSync(fd);
6181
+ fs21.closeSync(fd);
5879
6182
  }
5880
6183
  return { lines: collected.reverse(), totalLinesCount };
5881
6184
  }
@@ -6068,12 +6371,21 @@ async function readLatestLogLinesMeta(options) {
6068
6371
  return { lines: [], totalLinesCount: 0 };
6069
6372
  }
6070
6373
  async function readLogsJsonResult(options) {
6071
- const { lines, totalLinesCount } = await readLatestLogLinesMeta(options);
6374
+ const { lines, totalLinesCount, allLines } = await readLatestLogLinesMeta(options);
6072
6375
  if (options.type === "server-std" || options.type === "client-std" || options.type === "dev" || options.type === "dev-std" || options.type === "install-dep-std") {
6376
+ const linesForErrorCheck = allLines ?? lines;
6377
+ const stackTracePattern = /\bat\s+\S+\s+\([^)]+:\d+:\d+\)/;
6378
+ const linesToFilter = allLines ?? lines;
6379
+ const filteredLines = linesToFilter.filter((line) => !stackTracePattern.test(line));
6380
+ const maxLines = options.maxLines ?? 30;
6381
+ const offset = options.offset ?? 0;
6382
+ const endExclusive = Math.max(0, filteredLines.length - offset);
6383
+ const start = Math.max(0, endExclusive - maxLines);
6384
+ const paginatedLogs = filteredLines.slice(start, endExclusive);
6073
6385
  return {
6074
- hasError: hasErrorInStdLines(lines),
6075
- totalLinesCount,
6076
- logs: lines
6386
+ hasError: hasErrorInStdLines(linesForErrorCheck),
6387
+ totalLinesCount: filteredLines.length,
6388
+ logs: paginatedLogs
6077
6389
  };
6078
6390
  }
6079
6391
  const logs = [];
@@ -6100,30 +6412,30 @@ async function readLogsJsonResult(options) {
6100
6412
  };
6101
6413
  }
6102
6414
  function resolveLogFilePath(logDir, type) {
6103
- const base = path16.isAbsolute(logDir) ? logDir : path16.join(process.cwd(), logDir);
6415
+ const base = path17.isAbsolute(logDir) ? logDir : path17.join(process.cwd(), logDir);
6104
6416
  if (type === "server") {
6105
- return path16.join(base, "server.log");
6417
+ return path17.join(base, "server.log");
6106
6418
  }
6107
6419
  if (type === "trace") {
6108
- return path16.join(base, "trace.log");
6420
+ return path17.join(base, "trace.log");
6109
6421
  }
6110
6422
  if (type === "server-std") {
6111
- return path16.join(base, "server.std.log");
6423
+ return path17.join(base, "server.std.log");
6112
6424
  }
6113
6425
  if (type === "client-std") {
6114
- return path16.join(base, "client.std.log");
6426
+ return path17.join(base, "client.std.log");
6115
6427
  }
6116
6428
  if (type === "dev") {
6117
- return path16.join(base, "dev.log");
6429
+ return path17.join(base, "dev.log");
6118
6430
  }
6119
6431
  if (type === "dev-std") {
6120
- return path16.join(base, "dev.std.log");
6432
+ return path17.join(base, "dev.std.log");
6121
6433
  }
6122
6434
  if (type === "install-dep-std") {
6123
- return path16.join(base, "install-dep.std.log");
6435
+ return path17.join(base, "install-dep.std.log");
6124
6436
  }
6125
6437
  if (type === "browser") {
6126
- return path16.join(base, "browser.log");
6438
+ return path17.join(base, "browser.log");
6127
6439
  }
6128
6440
  throw new Error(`Unsupported log type: ${type}`);
6129
6441
  }
@@ -6185,17 +6497,18 @@ var commands = [
6185
6497
  syncCommand,
6186
6498
  actionPluginCommandGroup,
6187
6499
  capabilityCommandGroup,
6500
+ componentCommandGroup,
6188
6501
  migrationCommand,
6189
6502
  readLogsCommand
6190
6503
  ];
6191
6504
 
6192
6505
  // src/index.ts
6193
- var envPath = path17.join(process.cwd(), ".env");
6194
- if (fs21.existsSync(envPath)) {
6506
+ var envPath = path18.join(process.cwd(), ".env");
6507
+ if (fs22.existsSync(envPath)) {
6195
6508
  dotenvConfig({ path: envPath });
6196
6509
  }
6197
- var __dirname = path17.dirname(fileURLToPath4(import.meta.url));
6198
- var pkg = JSON.parse(fs21.readFileSync(path17.join(__dirname, "../package.json"), "utf-8"));
6510
+ var __dirname = path18.dirname(fileURLToPath4(import.meta.url));
6511
+ var pkg = JSON.parse(fs22.readFileSync(path18.join(__dirname, "../package.json"), "utf-8"));
6199
6512
  var cli = new FullstackCLI(pkg.version);
6200
6513
  cli.useAll(commands);
6201
6514
  cli.run();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/fullstack-cli",
3
- "version": "1.1.20",
3
+ "version": "1.1.22",
4
4
  "description": "CLI tool for fullstack template management",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -32,18 +32,23 @@
32
32
  },
33
33
  "dependencies": {
34
34
  "@lark-apaas/http-client": "^0.1.2",
35
+ "@lydell/node-pty": "1.1.0",
35
36
  "@vercel/nft": "^0.30.3",
36
37
  "commander": "^13.0.0",
38
+ "debug": "^4.4.3",
37
39
  "dotenv": "^16.0.0",
38
40
  "drizzle-kit": "0.31.5",
39
41
  "drizzle-orm": "0.44.6",
42
+ "es-toolkit": "^1.44.0",
40
43
  "inflection": "^3.0.2",
41
44
  "pinyin-pro": "^3.27.0",
42
45
  "postgres": "^3.4.3",
46
+ "shadcn": "3.8.2",
43
47
  "ts-morph": "^27.0.0",
44
48
  "zod-to-json-schema": "^3.24.1"
45
49
  },
46
50
  "devDependencies": {
51
+ "@types/debug": "^4",
47
52
  "@types/node": "^22.0.0",
48
53
  "tsup": "^8.3.5",
49
54
  "typescript": "^5.9.2",