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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +418 -108
  2. package/package.json +3 -2
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  // src/index.ts
2
- import fs28 from "fs";
3
- import path24 from "path";
2
+ import fs29 from "fs";
3
+ import path25 from "path";
4
4
  import { fileURLToPath as fileURLToPath5 } from "url";
5
5
  import { config as dotenvConfig } from "dotenv";
6
6
 
@@ -2435,13 +2435,23 @@ var syncConfig = {
2435
2435
  to: ".gitignore",
2436
2436
  pattern: "package-lock.json"
2437
2437
  },
2438
- // 5. 注册 postinstall 脚本,自动恢复 action plugins
2438
+ // 5. 注册 postinstall 脚本,自动恢复 action plugins
2439
+ // 用 npx -y 形式而不是裸 `fullstack-cli`:用户项目的 deps 没有 fullstack-cli,
2440
+ // bare 形式在新机器(PATH 没全局 fullstack-cli)下 npm i 立即 ENOENT。
2439
2441
  {
2440
2442
  type: "add-script",
2441
2443
  name: "postinstall",
2442
- command: "fullstack-cli action-plugin init",
2444
+ command: "npx -y @lark-apaas/fullstack-cli action-plugin init",
2443
2445
  overwrite: false
2444
2446
  },
2447
+ // 5a. 迁移已有应用的老形式 postinstall(裸 fullstack-cli → npx -y)。
2448
+ // patch-script 只在脚本以指定前缀开头时改写,用户真正手改过的脚本保持原样。
2449
+ {
2450
+ type: "patch-script",
2451
+ name: "postinstall",
2452
+ to: "npx -y @lark-apaas/fullstack-cli action-plugin init",
2453
+ ifStartsWith: "fullstack-cli action-plugin init"
2454
+ },
2445
2455
  // 6. 替换 drizzle.config.ts(仅当文件存在时)
2446
2456
  {
2447
2457
  from: "templates/drizzle.config.ts",
@@ -4690,59 +4700,358 @@ var capabilityCommandGroup = {
4690
4700
  commands: [listCommand2]
4691
4701
  };
4692
4702
 
4693
- // src/commands/migration/version-manager.ts
4703
+ // src/commands/component/add.handler.ts
4704
+ import { execFile } from "child_process";
4705
+
4706
+ // src/commands/component/registry-preparer.ts
4694
4707
  import fs16 from "fs";
4695
4708
  import path14 from "path";
4709
+ import os from "os";
4710
+
4711
+ // src/commands/component/service.ts
4712
+ import { mapValues } from "es-toolkit";
4713
+
4714
+ // src/commands/component/utils.ts
4715
+ import createDebug from "debug";
4716
+ var debug = createDebug("component");
4717
+
4718
+ // src/commands/component/service.ts
4719
+ async function getComponents(keys) {
4720
+ const client = getHttpClient();
4721
+ debug("\u8C03\u7528 /components/batch_get %o", keys);
4722
+ const response = await client.post(
4723
+ `/api/v1/studio/innerapi/components/batch_get?keys=${keys.join(",")}`
4724
+ );
4725
+ if (response.status !== 200) {
4726
+ throw new Error(
4727
+ `\u83B7\u53D6\u7EC4\u4EF6\u4FE1\u606F\u5931\u8D25\uFF1A${response.status} ${response.statusText}`
4728
+ );
4729
+ }
4730
+ const result = await response.json();
4731
+ if (result.status_code !== "0") {
4732
+ debug("\u63A5\u53E3\u8FD4\u56DE\u9519\u8BEF\uFF1A%o", result);
4733
+ throw new Error(`\u83B7\u53D6\u7EC4\u4EF6\u4FE1\u606F\u5931\u8D25\uFF1A${result.error_msg}`);
4734
+ }
4735
+ return mapValues(result.data.components, ([component]) => component);
4736
+ }
4737
+ async function getRegistryItem(url) {
4738
+ const client = getHttpClient();
4739
+ debug("\u4E0B\u8F7D registry-item.json\uFF1A%s", url);
4740
+ const response = await client.get(url);
4741
+ if (!response.ok) {
4742
+ throw new Error(
4743
+ `\u4E0B\u8F7D registry-item.json \u5931\u8D25\uFF1A${response.status} ${response.statusText}`
4744
+ );
4745
+ }
4746
+ const item = await response.json();
4747
+ return item;
4748
+ }
4749
+ async function sendInstallEvent(key) {
4750
+ const client = getHttpClient();
4751
+ await client.post("/api/v1/studio/innerapi/resource_events", {
4752
+ events: [
4753
+ {
4754
+ resourceType: "component",
4755
+ resourceKey: key,
4756
+ eventType: "install",
4757
+ details: {}
4758
+ }
4759
+ ]
4760
+ });
4761
+ }
4762
+
4763
+ // src/commands/component/registry-preparer.ts
4764
+ var REGISTRY_TEMP_DIR = path14.join(os.tmpdir(), "miaoda-registry");
4765
+ function parseComponentKey(key) {
4766
+ const match = key.match(/^@([^/]+)\/(.+)$/);
4767
+ if (!match) {
4768
+ throw new Error(
4769
+ `Invalid component key format: ${key}. Expected format: @scope/name`
4770
+ );
4771
+ }
4772
+ return { scope: match[1], name: match[2] };
4773
+ }
4774
+ function getLocalRegistryPath(key) {
4775
+ const { scope, name } = parseComponentKey(key);
4776
+ return path14.join(REGISTRY_TEMP_DIR, scope, `${name}.json`);
4777
+ }
4778
+ function ensureDir(dirPath) {
4779
+ if (!fs16.existsSync(dirPath)) {
4780
+ fs16.mkdirSync(dirPath, { recursive: true });
4781
+ }
4782
+ }
4783
+ async function prepareRecursive(key, visited) {
4784
+ if (visited.has(key)) {
4785
+ debug("\u8DF3\u8FC7\u5DF2\u5904\u7406\u7684\u7EC4\u4EF6: %s", key);
4786
+ return;
4787
+ }
4788
+ visited.add(key);
4789
+ debug("\u5904\u7406\u7EC4\u4EF6: %s", key);
4790
+ debug("\u83B7\u53D6\u7EC4\u4EF6\u4E0B\u8F7D\u4FE1\u606F...");
4791
+ const infoMap = await getComponents([key]);
4792
+ const info = infoMap[key];
4793
+ debug("\u7EC4\u4EF6\u4FE1\u606F: %o", info);
4794
+ if (!info) {
4795
+ throw new Error(`Component not found: ${key}`);
4796
+ }
4797
+ if (info.status !== "active") {
4798
+ throw new Error(`Component is not active: ${key}`);
4799
+ }
4800
+ debug("\u4E0B\u8F7D registry item: %s", info.downloadURL);
4801
+ const registryItem = await getRegistryItem(info.downloadURL);
4802
+ debug("registry item \u5185\u5BB9: %o", registryItem);
4803
+ const deps = registryItem.registryDependencies || [];
4804
+ debug("\u4F9D\u8D56\u5217\u8868: %o", deps);
4805
+ for (const dep of deps) {
4806
+ await prepareRecursive(dep, visited);
4807
+ }
4808
+ const rewrittenItem = {
4809
+ ...registryItem,
4810
+ registryDependencies: deps.map((dep) => getLocalRegistryPath(dep))
4811
+ };
4812
+ const localPath = getLocalRegistryPath(key);
4813
+ ensureDir(path14.dirname(localPath));
4814
+ fs16.writeFileSync(localPath, JSON.stringify(rewrittenItem, null, 2), "utf-8");
4815
+ debug("\u4FDD\u5B58\u5230: %s", localPath);
4816
+ }
4817
+ async function prepareComponentRegistryItems(id) {
4818
+ const visited = /* @__PURE__ */ new Set();
4819
+ await prepareRecursive(id, visited);
4820
+ return getLocalRegistryPath(id);
4821
+ }
4822
+ function cleanupTempDir() {
4823
+ try {
4824
+ if (fs16.existsSync(REGISTRY_TEMP_DIR)) {
4825
+ fs16.rmSync(REGISTRY_TEMP_DIR, { recursive: true, force: true });
4826
+ }
4827
+ } catch {
4828
+ }
4829
+ }
4830
+ function getDownloadedRegistryItem(itemId) {
4831
+ const localPath = getLocalRegistryPath(itemId);
4832
+ if (!fs16.existsSync(localPath)) {
4833
+ return null;
4834
+ }
4835
+ const content = fs16.readFileSync(localPath, "utf-8");
4836
+ return JSON.parse(content);
4837
+ }
4838
+
4839
+ // src/commands/component/shadcn-executor.ts
4840
+ import * as pty from "@lydell/node-pty";
4841
+ function parseOutput(output) {
4842
+ const state = {
4843
+ currentSection: null,
4844
+ files: /* @__PURE__ */ new Set()
4845
+ };
4846
+ const lines = output.split("\n");
4847
+ for (const line of lines) {
4848
+ const trimmedLine = line.trim();
4849
+ if (/Created \d+ files?:/.test(trimmedLine)) {
4850
+ state.currentSection = "created";
4851
+ continue;
4852
+ }
4853
+ if (/Updated \d+ files?:/.test(trimmedLine)) {
4854
+ state.currentSection = "updated";
4855
+ continue;
4856
+ }
4857
+ if (/Skipped \d+ files?:/.test(trimmedLine)) {
4858
+ state.currentSection = "skipped";
4859
+ continue;
4860
+ }
4861
+ if (state.currentSection && trimmedLine.startsWith("- ")) {
4862
+ const filePath = trimmedLine.slice(2).trim();
4863
+ if (filePath && filePath.includes("/")) {
4864
+ state.files.add(filePath);
4865
+ }
4866
+ }
4867
+ if (state.currentSection && trimmedLine.length > 1 && !trimmedLine.startsWith("- ")) {
4868
+ state.currentSection = null;
4869
+ }
4870
+ }
4871
+ return Array.from(state.files);
4872
+ }
4873
+ function toFileInfo(filePath) {
4874
+ const name = filePath.split("/").pop() || filePath;
4875
+ return { name, path: filePath };
4876
+ }
4877
+ var PROMPT_PATTERNS = [
4878
+ // 文件覆盖确认 - 回答 n(不覆盖)
4879
+ { pattern: /overwrite/i, answer: "n\n" },
4880
+ // 主题/样式选择 - 回答 n(不安装额外主题)
4881
+ { pattern: /theme/i, answer: "n\n" },
4882
+ { pattern: /style/i, answer: "n\n" },
4883
+ // 继续确认 - 回答 y
4884
+ { pattern: /continue\?/i, answer: "y\n" },
4885
+ { pattern: /proceed\?/i, answer: "y\n" }
4886
+ ];
4887
+ async function executeShadcnAdd(registryItemPath) {
4888
+ return new Promise((resolve2) => {
4889
+ let output = "";
4890
+ const args = ["--yes", "shadcn@3.8.2", "add", registryItemPath];
4891
+ const ptyProcess = pty.spawn("npx", args, {
4892
+ name: "xterm-color",
4893
+ cols: 120,
4894
+ rows: 30,
4895
+ cwd: process.cwd(),
4896
+ env: {
4897
+ ...process.env,
4898
+ // 禁用颜色输出以便解析
4899
+ NO_COLOR: "1",
4900
+ FORCE_COLOR: "0"
4901
+ }
4902
+ });
4903
+ ptyProcess.onData((data) => {
4904
+ output += data;
4905
+ for (const { pattern, answer } of PROMPT_PATTERNS) {
4906
+ if (pattern.test(data)) {
4907
+ ptyProcess.write(answer);
4908
+ return;
4909
+ }
4910
+ }
4911
+ });
4912
+ const timeoutId = setTimeout(() => {
4913
+ ptyProcess.kill();
4914
+ resolve2({
4915
+ success: false,
4916
+ files: [],
4917
+ error: "\u6267\u884C\u8D85\u65F6"
4918
+ });
4919
+ }, 3 * 60 * 1e3);
4920
+ ptyProcess.onExit(({ exitCode }) => {
4921
+ clearTimeout(timeoutId);
4922
+ const success = exitCode === 0;
4923
+ const filePaths = parseOutput(output);
4924
+ const files = filePaths.map(toFileInfo);
4925
+ resolve2({
4926
+ success,
4927
+ files,
4928
+ error: success ? void 0 : output || `Process exited with code ${exitCode}`
4929
+ });
4930
+ });
4931
+ });
4932
+ }
4933
+
4934
+ // src/commands/component/add.handler.ts
4935
+ function runActionPluginInit() {
4936
+ return new Promise((resolve2) => {
4937
+ execFile("fullstack-cli", ["action-plugin", "init"], { cwd: process.cwd(), stdio: "ignore" }, (error) => {
4938
+ if (error) {
4939
+ debug("action-plugin init \u5931\u8D25: %s", error.message);
4940
+ }
4941
+ resolve2();
4942
+ });
4943
+ });
4944
+ }
4945
+ function printResult(result) {
4946
+ console.log(JSON.stringify(result, null, 2));
4947
+ }
4948
+ async function addComponent(key) {
4949
+ debug("\u5F00\u59CB\u5B89\u88C5\u7EC4\u4EF6: %s", key);
4950
+ debug("\u51C6\u5907 registry items...");
4951
+ const registryItemPath = await prepareComponentRegistryItems(key);
4952
+ debug("registry item \u8DEF\u5F84: %s", registryItemPath);
4953
+ const registryItem = getDownloadedRegistryItem(key);
4954
+ debug("\u83B7\u53D6\u5230 registry item: %o", registryItem);
4955
+ debug("\u6267\u884C shadcn add...");
4956
+ const executeResult = await executeShadcnAdd(registryItemPath);
4957
+ debug("shadcn \u6267\u884C\u7ED3\u679C: %o", executeResult);
4958
+ if (!executeResult.success) {
4959
+ throw new Error(executeResult.error || "\u5B89\u88C5\u5931\u8D25\uFF0C\u672A\u77E5\u539F\u56E0");
4960
+ }
4961
+ return {
4962
+ success: true,
4963
+ name: key,
4964
+ description: registryItem?.description || "",
4965
+ files: executeResult.files,
4966
+ docs: registryItem?.docs || ""
4967
+ };
4968
+ }
4969
+ async function add(key) {
4970
+ try {
4971
+ const result = await addComponent(key);
4972
+ printResult(result);
4973
+ void sendInstallEvent(key);
4974
+ } catch (error) {
4975
+ const errorMessage = error instanceof Error ? error.message : "\u5B89\u88C5\u5931\u8D25\uFF0C\u539F\u56E0\u672A\u77E5";
4976
+ printResult({
4977
+ success: false,
4978
+ errors: [{ message: errorMessage }]
4979
+ });
4980
+ } finally {
4981
+ await runActionPluginInit();
4982
+ cleanupTempDir();
4983
+ }
4984
+ }
4985
+
4986
+ // src/commands/component/index.ts
4987
+ var addCommand = {
4988
+ name: "add",
4989
+ description: "\u5B89\u88C5\u5999\u642D\u7EC4\u4EF6\u5E02\u573A\u4E2D\u7684\u7EC4\u4EF6",
4990
+ register(program) {
4991
+ program.command(this.name).description(this.description).argument("<component>", "\u7EC4\u4EF6 ID (\u4F8B\u5982 @miaoda/button)").action(async (component) => {
4992
+ await add(component);
4993
+ });
4994
+ }
4995
+ };
4996
+ var componentCommandGroup = {
4997
+ name: "component",
4998
+ description: "\u7EC4\u4EF6\u76F8\u5173\u547D\u4EE4",
4999
+ commands: [addCommand]
5000
+ };
5001
+
5002
+ // src/commands/migration/version-manager.ts
5003
+ import fs17 from "fs";
5004
+ import path15 from "path";
4696
5005
  var PACKAGE_JSON = "package.json";
4697
5006
  var VERSION_FIELD = "migrationVersion";
4698
5007
  function getPackageJsonPath2() {
4699
- return path14.join(process.cwd(), PACKAGE_JSON);
5008
+ return path15.join(process.cwd(), PACKAGE_JSON);
4700
5009
  }
4701
5010
  function getCurrentVersion() {
4702
5011
  const pkgPath = getPackageJsonPath2();
4703
- if (!fs16.existsSync(pkgPath)) {
5012
+ if (!fs17.existsSync(pkgPath)) {
4704
5013
  throw new Error("package.json not found");
4705
5014
  }
4706
- const pkg2 = JSON.parse(fs16.readFileSync(pkgPath, "utf-8"));
5015
+ const pkg2 = JSON.parse(fs17.readFileSync(pkgPath, "utf-8"));
4707
5016
  return pkg2[VERSION_FIELD] ?? 0;
4708
5017
  }
4709
5018
  function setCurrentVersion(version) {
4710
5019
  const pkgPath = getPackageJsonPath2();
4711
- const pkg2 = JSON.parse(fs16.readFileSync(pkgPath, "utf-8"));
5020
+ const pkg2 = JSON.parse(fs17.readFileSync(pkgPath, "utf-8"));
4712
5021
  pkg2[VERSION_FIELD] = version;
4713
- fs16.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
5022
+ fs17.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
4714
5023
  }
4715
5024
 
4716
5025
  // src/commands/migration/versions/v001_capability/json-migrator/detector.ts
4717
- import fs18 from "fs";
4718
- import path16 from "path";
5026
+ import fs19 from "fs";
5027
+ import path17 from "path";
4719
5028
 
4720
5029
  // src/commands/migration/versions/v001_capability/utils.ts
4721
- import fs17 from "fs";
4722
- import path15 from "path";
5030
+ import fs18 from "fs";
5031
+ import path16 from "path";
4723
5032
  var CAPABILITIES_DIR2 = "server/capabilities";
4724
5033
  function getProjectRoot3() {
4725
5034
  return process.cwd();
4726
5035
  }
4727
5036
  function getCapabilitiesDir2() {
4728
- return path15.join(getProjectRoot3(), CAPABILITIES_DIR2);
5037
+ return path16.join(getProjectRoot3(), CAPABILITIES_DIR2);
4729
5038
  }
4730
5039
  function getPluginManifestPath2(pluginKey) {
4731
- return path15.join(getProjectRoot3(), "node_modules", pluginKey, "manifest.json");
5040
+ return path16.join(getProjectRoot3(), "node_modules", pluginKey, "manifest.json");
4732
5041
  }
4733
5042
 
4734
5043
  // src/commands/migration/versions/v001_capability/json-migrator/detector.ts
4735
5044
  function detectJsonMigration() {
4736
5045
  const capabilitiesDir = getCapabilitiesDir2();
4737
- const oldFilePath = path16.join(capabilitiesDir, "capabilities.json");
4738
- if (!fs18.existsSync(oldFilePath)) {
5046
+ const oldFilePath = path17.join(capabilitiesDir, "capabilities.json");
5047
+ if (!fs19.existsSync(oldFilePath)) {
4739
5048
  return {
4740
5049
  needsMigration: false,
4741
5050
  reason: "capabilities.json not found"
4742
5051
  };
4743
5052
  }
4744
5053
  try {
4745
- const content = fs18.readFileSync(oldFilePath, "utf-8");
5054
+ const content = fs19.readFileSync(oldFilePath, "utf-8");
4746
5055
  const parsed = JSON.parse(content);
4747
5056
  if (!Array.isArray(parsed)) {
4748
5057
  return {
@@ -4793,8 +5102,8 @@ async function check(options) {
4793
5102
  }
4794
5103
 
4795
5104
  // src/commands/migration/versions/v001_capability/json-migrator/index.ts
4796
- import fs19 from "fs";
4797
- import path17 from "path";
5105
+ import fs20 from "fs";
5106
+ import path18 from "path";
4798
5107
 
4799
5108
  // src/commands/migration/versions/v001_capability/mapping.ts
4800
5109
  var DEFAULT_PLUGIN_VERSION = "1.0.0";
@@ -5024,18 +5333,18 @@ function transformCapabilities(oldCapabilities) {
5024
5333
  // src/commands/migration/versions/v001_capability/json-migrator/index.ts
5025
5334
  function loadExistingCapabilities() {
5026
5335
  const capabilitiesDir = getCapabilitiesDir2();
5027
- if (!fs19.existsSync(capabilitiesDir)) {
5336
+ if (!fs20.existsSync(capabilitiesDir)) {
5028
5337
  return [];
5029
5338
  }
5030
- const files = fs19.readdirSync(capabilitiesDir);
5339
+ const files = fs20.readdirSync(capabilitiesDir);
5031
5340
  const capabilities = [];
5032
5341
  for (const file of files) {
5033
5342
  if (file === "capabilities.json" || !file.endsWith(".json")) {
5034
5343
  continue;
5035
5344
  }
5036
5345
  try {
5037
- const filePath = path17.join(capabilitiesDir, file);
5038
- const content = fs19.readFileSync(filePath, "utf-8");
5346
+ const filePath = path18.join(capabilitiesDir, file);
5347
+ const content = fs20.readFileSync(filePath, "utf-8");
5039
5348
  const capability = JSON.parse(content);
5040
5349
  if (capability.id && capability.pluginKey) {
5041
5350
  capabilities.push(capability);
@@ -5093,9 +5402,9 @@ async function migrateJsonFiles(options) {
5093
5402
  }
5094
5403
  const capabilitiesDir = getCapabilitiesDir2();
5095
5404
  for (const cap of newCapabilities) {
5096
- const filePath = path17.join(capabilitiesDir, `${cap.id}.json`);
5405
+ const filePath = path18.join(capabilitiesDir, `${cap.id}.json`);
5097
5406
  const content = JSON.stringify(cap, null, 2);
5098
- fs19.writeFileSync(filePath, content, "utf-8");
5407
+ fs20.writeFileSync(filePath, content, "utf-8");
5099
5408
  console.log(` \u2713 Created: ${cap.id}.json`);
5100
5409
  }
5101
5410
  return {
@@ -5107,11 +5416,11 @@ async function migrateJsonFiles(options) {
5107
5416
  }
5108
5417
 
5109
5418
  // src/commands/migration/versions/v001_capability/plugin-installer/detector.ts
5110
- import fs20 from "fs";
5419
+ import fs21 from "fs";
5111
5420
  function isPluginInstalled2(pluginKey) {
5112
5421
  const actionPlugins = readActionPlugins();
5113
5422
  const manifestPath = getPluginManifestPath2(pluginKey);
5114
- return fs20.existsSync(manifestPath) && !!actionPlugins[pluginKey];
5423
+ return fs21.existsSync(manifestPath) && !!actionPlugins[pluginKey];
5115
5424
  }
5116
5425
  function detectPluginsToInstall(capabilities) {
5117
5426
  const pluginKeys = /* @__PURE__ */ new Set();
@@ -5187,12 +5496,12 @@ async function installPlugins(capabilities, options) {
5187
5496
  }
5188
5497
 
5189
5498
  // src/commands/migration/versions/v001_capability/code-migrator/index.ts
5190
- import path19 from "path";
5499
+ import path20 from "path";
5191
5500
  import { Project as Project3 } from "ts-morph";
5192
5501
 
5193
5502
  // src/commands/migration/versions/v001_capability/code-migrator/scanner.ts
5194
- import fs21 from "fs";
5195
- import path18 from "path";
5503
+ import fs22 from "fs";
5504
+ import path19 from "path";
5196
5505
  var EXCLUDED_DIRS = [
5197
5506
  "node_modules",
5198
5507
  "dist",
@@ -5207,9 +5516,9 @@ var EXCLUDED_PATTERNS = [
5207
5516
  /\.d\.ts$/
5208
5517
  ];
5209
5518
  function scanDirectory(dir, files = []) {
5210
- const entries = fs21.readdirSync(dir, { withFileTypes: true });
5519
+ const entries = fs22.readdirSync(dir, { withFileTypes: true });
5211
5520
  for (const entry of entries) {
5212
- const fullPath = path18.join(dir, entry.name);
5521
+ const fullPath = path19.join(dir, entry.name);
5213
5522
  if (entry.isDirectory()) {
5214
5523
  if (EXCLUDED_DIRS.includes(entry.name)) {
5215
5524
  continue;
@@ -5225,14 +5534,14 @@ function scanDirectory(dir, files = []) {
5225
5534
  return files;
5226
5535
  }
5227
5536
  function scanServerFiles() {
5228
- const serverDir = path18.join(getProjectRoot3(), "server");
5229
- if (!fs21.existsSync(serverDir)) {
5537
+ const serverDir = path19.join(getProjectRoot3(), "server");
5538
+ if (!fs22.existsSync(serverDir)) {
5230
5539
  return [];
5231
5540
  }
5232
5541
  return scanDirectory(serverDir);
5233
5542
  }
5234
5543
  function hasCapabilityImport(filePath) {
5235
- const content = fs21.readFileSync(filePath, "utf-8");
5544
+ const content = fs22.readFileSync(filePath, "utf-8");
5236
5545
  return /import\s+.*from\s+['"][^'"]*capabilities[^'"]*['"]/.test(content);
5237
5546
  }
5238
5547
  function scanFilesToMigrate() {
@@ -5609,7 +5918,7 @@ function analyzeFile(project, filePath, actionNameMap) {
5609
5918
  const callSites = analyzeCallSites(sourceFile, imports);
5610
5919
  const classInfo = analyzeClass(sourceFile);
5611
5920
  const { canMigrate, reason } = canAutoMigrate(classInfo);
5612
- const relativePath = path19.relative(getProjectRoot3(), filePath);
5921
+ const relativePath = path20.relative(getProjectRoot3(), filePath);
5613
5922
  return {
5614
5923
  filePath: relativePath,
5615
5924
  imports,
@@ -5620,7 +5929,7 @@ function analyzeFile(project, filePath, actionNameMap) {
5620
5929
  };
5621
5930
  }
5622
5931
  function migrateFile(project, analysis, dryRun) {
5623
- const absolutePath = path19.join(getProjectRoot3(), analysis.filePath);
5932
+ const absolutePath = path20.join(getProjectRoot3(), analysis.filePath);
5624
5933
  if (!analysis.canAutoMigrate) {
5625
5934
  return {
5626
5935
  filePath: analysis.filePath,
@@ -5723,17 +6032,17 @@ function getSuggestion(analysis) {
5723
6032
  }
5724
6033
 
5725
6034
  // src/commands/migration/versions/v001_capability/cleanup.ts
5726
- import fs22 from "fs";
5727
- import path20 from "path";
6035
+ import fs23 from "fs";
6036
+ import path21 from "path";
5728
6037
  function cleanupOldFiles(capabilities, dryRun) {
5729
6038
  const deletedFiles = [];
5730
6039
  const errors = [];
5731
6040
  const capabilitiesDir = getCapabilitiesDir2();
5732
- const oldJsonPath = path20.join(capabilitiesDir, "capabilities.json");
5733
- if (fs22.existsSync(oldJsonPath)) {
6041
+ const oldJsonPath = path21.join(capabilitiesDir, "capabilities.json");
6042
+ if (fs23.existsSync(oldJsonPath)) {
5734
6043
  try {
5735
6044
  if (!dryRun) {
5736
- fs22.unlinkSync(oldJsonPath);
6045
+ fs23.unlinkSync(oldJsonPath);
5737
6046
  }
5738
6047
  deletedFiles.push("capabilities.json");
5739
6048
  } catch (error) {
@@ -5741,11 +6050,11 @@ function cleanupOldFiles(capabilities, dryRun) {
5741
6050
  }
5742
6051
  }
5743
6052
  for (const cap of capabilities) {
5744
- const tsFilePath = path20.join(capabilitiesDir, `${cap.id}.ts`);
5745
- if (fs22.existsSync(tsFilePath)) {
6053
+ const tsFilePath = path21.join(capabilitiesDir, `${cap.id}.ts`);
6054
+ if (fs23.existsSync(tsFilePath)) {
5746
6055
  try {
5747
6056
  if (!dryRun) {
5748
- fs22.unlinkSync(tsFilePath);
6057
+ fs23.unlinkSync(tsFilePath);
5749
6058
  }
5750
6059
  deletedFiles.push(`${cap.id}.ts`);
5751
6060
  } catch (error) {
@@ -5761,8 +6070,8 @@ function cleanupOldFiles(capabilities, dryRun) {
5761
6070
  }
5762
6071
 
5763
6072
  // src/commands/migration/versions/v001_capability/report-generator.ts
5764
- import fs23 from "fs";
5765
- import path21 from "path";
6073
+ import fs24 from "fs";
6074
+ import path22 from "path";
5766
6075
  var REPORT_FILE = "capability-migration-report.md";
5767
6076
  function printSummary(result) {
5768
6077
  const { jsonMigration, pluginInstallation, codeMigration, cleanup } = result;
@@ -5925,15 +6234,15 @@ async function generateReport(result) {
5925
6234
  }
5926
6235
  lines.push("");
5927
6236
  const logDir = process.env.LOG_DIR || "logs";
5928
- if (!fs23.existsSync(logDir)) {
6237
+ if (!fs24.existsSync(logDir)) {
5929
6238
  return;
5930
6239
  }
5931
- const reportDir = path21.join(logDir, "migration");
5932
- if (!fs23.existsSync(reportDir)) {
5933
- fs23.mkdirSync(reportDir, { recursive: true });
6240
+ const reportDir = path22.join(logDir, "migration");
6241
+ if (!fs24.existsSync(reportDir)) {
6242
+ fs24.mkdirSync(reportDir, { recursive: true });
5934
6243
  }
5935
- const reportPath = path21.join(reportDir, REPORT_FILE);
5936
- fs23.writeFileSync(reportPath, lines.join("\n"), "utf-8");
6244
+ const reportPath = path22.join(reportDir, REPORT_FILE);
6245
+ fs24.writeFileSync(reportPath, lines.join("\n"), "utf-8");
5937
6246
  console.log(`\u{1F4C4} Report generated: ${reportPath}`);
5938
6247
  }
5939
6248
 
@@ -6465,10 +6774,10 @@ var migrationCommand = {
6465
6774
  };
6466
6775
 
6467
6776
  // src/commands/read-logs/index.ts
6468
- import path22 from "path";
6777
+ import path23 from "path";
6469
6778
 
6470
6779
  // src/commands/read-logs/std-utils.ts
6471
- import fs24 from "fs";
6780
+ import fs25 from "fs";
6472
6781
  function formatStdPrefixTime(localTime) {
6473
6782
  const match = localTime.match(/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/);
6474
6783
  if (!match) return localTime;
@@ -6498,11 +6807,11 @@ function stripPrefixFromStdLine(line) {
6498
6807
  return `[${time}] ${content}`;
6499
6808
  }
6500
6809
  function readStdLinesTailFromLastMarkerPaged(filePath, maxLines, offset, isMarker) {
6501
- const stat = fs24.statSync(filePath);
6810
+ const stat = fs25.statSync(filePath);
6502
6811
  if (stat.size === 0) {
6503
6812
  return { lines: [], markerFound: false, totalLinesCount: 0 };
6504
6813
  }
6505
- const fd = fs24.openSync(filePath, "r");
6814
+ const fd = fs25.openSync(filePath, "r");
6506
6815
  const chunkSize = 64 * 1024;
6507
6816
  let position = stat.size;
6508
6817
  let remainder = "";
@@ -6516,7 +6825,7 @@ function readStdLinesTailFromLastMarkerPaged(filePath, maxLines, offset, isMarke
6516
6825
  const length = Math.min(chunkSize, position);
6517
6826
  position -= length;
6518
6827
  const buffer = Buffer.alloc(length);
6519
- fs24.readSync(fd, buffer, 0, length, position);
6828
+ fs25.readSync(fd, buffer, 0, length, position);
6520
6829
  let chunk = buffer.toString("utf8");
6521
6830
  if (remainder) {
6522
6831
  chunk += remainder;
@@ -6558,7 +6867,7 @@ function readStdLinesTailFromLastMarkerPaged(filePath, maxLines, offset, isMarke
6558
6867
  }
6559
6868
  }
6560
6869
  } finally {
6561
- fs24.closeSync(fd);
6870
+ fs25.closeSync(fd);
6562
6871
  }
6563
6872
  return { lines: collected.reverse(), markerFound, totalLinesCount };
6564
6873
  }
@@ -6579,21 +6888,21 @@ function readServerStdSegment(filePath, maxLines, offset) {
6579
6888
  }
6580
6889
 
6581
6890
  // src/commands/read-logs/tail.ts
6582
- import fs25 from "fs";
6891
+ import fs26 from "fs";
6583
6892
  function fileExists(filePath) {
6584
6893
  try {
6585
- fs25.accessSync(filePath, fs25.constants.F_OK | fs25.constants.R_OK);
6894
+ fs26.accessSync(filePath, fs26.constants.F_OK | fs26.constants.R_OK);
6586
6895
  return true;
6587
6896
  } catch {
6588
6897
  return false;
6589
6898
  }
6590
6899
  }
6591
6900
  function readFileTailLines(filePath, maxLines) {
6592
- const stat = fs25.statSync(filePath);
6901
+ const stat = fs26.statSync(filePath);
6593
6902
  if (stat.size === 0) {
6594
6903
  return [];
6595
6904
  }
6596
- const fd = fs25.openSync(filePath, "r");
6905
+ const fd = fs26.openSync(filePath, "r");
6597
6906
  const chunkSize = 64 * 1024;
6598
6907
  const chunks = [];
6599
6908
  let position = stat.size;
@@ -6603,13 +6912,13 @@ function readFileTailLines(filePath, maxLines) {
6603
6912
  const length = Math.min(chunkSize, position);
6604
6913
  position -= length;
6605
6914
  const buffer = Buffer.alloc(length);
6606
- fs25.readSync(fd, buffer, 0, length, position);
6915
+ fs26.readSync(fd, buffer, 0, length, position);
6607
6916
  chunks.unshift(buffer.toString("utf8"));
6608
6917
  const chunkLines = buffer.toString("utf8").split("\n").length - 1;
6609
6918
  collectedLines += chunkLines;
6610
6919
  }
6611
6920
  } finally {
6612
- fs25.closeSync(fd);
6921
+ fs26.closeSync(fd);
6613
6922
  }
6614
6923
  const content = chunks.join("");
6615
6924
  const allLines = content.split("\n");
@@ -6625,11 +6934,11 @@ function readFileTailLines(filePath, maxLines) {
6625
6934
  return allLines.slice(allLines.length - maxLines);
6626
6935
  }
6627
6936
  function readFileTailNonEmptyLinesWithOffset(filePath, maxLines, offset) {
6628
- const stat = fs25.statSync(filePath);
6937
+ const stat = fs26.statSync(filePath);
6629
6938
  if (stat.size === 0) {
6630
6939
  return { lines: [], totalLinesCount: 0 };
6631
6940
  }
6632
- const fd = fs25.openSync(filePath, "r");
6941
+ const fd = fs26.openSync(filePath, "r");
6633
6942
  const chunkSize = 64 * 1024;
6634
6943
  let position = stat.size;
6635
6944
  let remainder = "";
@@ -6641,7 +6950,7 @@ function readFileTailNonEmptyLinesWithOffset(filePath, maxLines, offset) {
6641
6950
  const length = Math.min(chunkSize, position);
6642
6951
  position -= length;
6643
6952
  const buffer = Buffer.alloc(length);
6644
- fs25.readSync(fd, buffer, 0, length, position);
6953
+ fs26.readSync(fd, buffer, 0, length, position);
6645
6954
  let chunk = buffer.toString("utf8");
6646
6955
  if (remainder) {
6647
6956
  chunk += remainder;
@@ -6672,7 +6981,7 @@ function readFileTailNonEmptyLinesWithOffset(filePath, maxLines, offset) {
6672
6981
  }
6673
6982
  }
6674
6983
  } finally {
6675
- fs25.closeSync(fd);
6984
+ fs26.closeSync(fd);
6676
6985
  }
6677
6986
  return { lines: collected.reverse(), totalLinesCount };
6678
6987
  }
@@ -6814,7 +7123,7 @@ function readDevStdSegment(filePath, maxLines, offset) {
6814
7123
  }
6815
7124
 
6816
7125
  // src/commands/read-logs/json-lines.ts
6817
- import fs26 from "fs";
7126
+ import fs27 from "fs";
6818
7127
  function normalizePid(value) {
6819
7128
  if (typeof value === "number") {
6820
7129
  return String(value);
@@ -6865,11 +7174,11 @@ function buildWantedLevelSet(levels) {
6865
7174
  return set.size > 0 ? set : null;
6866
7175
  }
6867
7176
  function readJsonLinesLastPid(filePath, maxLines, offset, levels) {
6868
- const stat = fs26.statSync(filePath);
7177
+ const stat = fs27.statSync(filePath);
6869
7178
  if (stat.size === 0) {
6870
7179
  return { lines: [], totalLinesCount: 0 };
6871
7180
  }
6872
- const fd = fs26.openSync(filePath, "r");
7181
+ const fd = fs27.openSync(filePath, "r");
6873
7182
  const chunkSize = 64 * 1024;
6874
7183
  let position = stat.size;
6875
7184
  let remainder = "";
@@ -6884,7 +7193,7 @@ function readJsonLinesLastPid(filePath, maxLines, offset, levels) {
6884
7193
  const length = Math.min(chunkSize, position);
6885
7194
  position -= length;
6886
7195
  const buffer = Buffer.alloc(length);
6887
- fs26.readSync(fd, buffer, 0, length, position);
7196
+ fs27.readSync(fd, buffer, 0, length, position);
6888
7197
  let chunk = buffer.toString("utf8");
6889
7198
  if (remainder) {
6890
7199
  chunk += remainder;
@@ -6946,7 +7255,7 @@ function readJsonLinesLastPid(filePath, maxLines, offset, levels) {
6946
7255
  }
6947
7256
  }
6948
7257
  } finally {
6949
- fs26.closeSync(fd);
7258
+ fs27.closeSync(fd);
6950
7259
  }
6951
7260
  return { lines: collected.reverse(), totalLinesCount };
6952
7261
  }
@@ -6989,11 +7298,11 @@ function extractTraceId(obj) {
6989
7298
  function readJsonLinesByTraceId(filePath, traceId, maxLines, offset, levels) {
6990
7299
  const wanted = traceId.trim();
6991
7300
  if (!wanted) return { lines: [], totalLinesCount: 0 };
6992
- const stat = fs26.statSync(filePath);
7301
+ const stat = fs27.statSync(filePath);
6993
7302
  if (stat.size === 0) {
6994
7303
  return { lines: [], totalLinesCount: 0 };
6995
7304
  }
6996
- const fd = fs26.openSync(filePath, "r");
7305
+ const fd = fs27.openSync(filePath, "r");
6997
7306
  const chunkSize = 64 * 1024;
6998
7307
  let position = stat.size;
6999
7308
  let remainder = "";
@@ -7006,7 +7315,7 @@ function readJsonLinesByTraceId(filePath, traceId, maxLines, offset, levels) {
7006
7315
  const length = Math.min(chunkSize, position);
7007
7316
  position -= length;
7008
7317
  const buffer = Buffer.alloc(length);
7009
- fs26.readSync(fd, buffer, 0, length, position);
7318
+ fs27.readSync(fd, buffer, 0, length, position);
7010
7319
  let chunk = buffer.toString("utf8");
7011
7320
  if (remainder) {
7012
7321
  chunk += remainder;
@@ -7059,7 +7368,7 @@ function readJsonLinesByTraceId(filePath, traceId, maxLines, offset, levels) {
7059
7368
  }
7060
7369
  }
7061
7370
  } finally {
7062
- fs26.closeSync(fd);
7371
+ fs27.closeSync(fd);
7063
7372
  }
7064
7373
  return { lines: collected.reverse(), totalLinesCount };
7065
7374
  }
@@ -7068,11 +7377,11 @@ function readJsonLinesTailByLevel(filePath, maxLines, offset, levels) {
7068
7377
  if (!wantedLevelSet) {
7069
7378
  return { lines: [], totalLinesCount: 0 };
7070
7379
  }
7071
- const stat = fs26.statSync(filePath);
7380
+ const stat = fs27.statSync(filePath);
7072
7381
  if (stat.size === 0) {
7073
7382
  return { lines: [], totalLinesCount: 0 };
7074
7383
  }
7075
- const fd = fs26.openSync(filePath, "r");
7384
+ const fd = fs27.openSync(filePath, "r");
7076
7385
  const chunkSize = 64 * 1024;
7077
7386
  let position = stat.size;
7078
7387
  let remainder = "";
@@ -7084,7 +7393,7 @@ function readJsonLinesTailByLevel(filePath, maxLines, offset, levels) {
7084
7393
  const length = Math.min(chunkSize, position);
7085
7394
  position -= length;
7086
7395
  const buffer = Buffer.alloc(length);
7087
- fs26.readSync(fd, buffer, 0, length, position);
7396
+ fs27.readSync(fd, buffer, 0, length, position);
7088
7397
  let chunk = buffer.toString("utf8");
7089
7398
  if (remainder) {
7090
7399
  chunk += remainder;
@@ -7131,7 +7440,7 @@ function readJsonLinesTailByLevel(filePath, maxLines, offset, levels) {
7131
7440
  }
7132
7441
  }
7133
7442
  } finally {
7134
- fs26.closeSync(fd);
7443
+ fs27.closeSync(fd);
7135
7444
  }
7136
7445
  return { lines: collected.reverse(), totalLinesCount };
7137
7446
  }
@@ -7365,30 +7674,30 @@ async function readLogsJsonResult(options) {
7365
7674
  };
7366
7675
  }
7367
7676
  function resolveLogFilePath(logDir, type) {
7368
- const base = path22.isAbsolute(logDir) ? logDir : path22.join(process.cwd(), logDir);
7677
+ const base = path23.isAbsolute(logDir) ? logDir : path23.join(process.cwd(), logDir);
7369
7678
  if (type === "server") {
7370
- return path22.join(base, "server.log");
7679
+ return path23.join(base, "server.log");
7371
7680
  }
7372
7681
  if (type === "trace") {
7373
- return path22.join(base, "trace.log");
7682
+ return path23.join(base, "trace.log");
7374
7683
  }
7375
7684
  if (type === "server-std") {
7376
- return path22.join(base, "server.std.log");
7685
+ return path23.join(base, "server.std.log");
7377
7686
  }
7378
7687
  if (type === "client-std") {
7379
- return path22.join(base, "client.std.log");
7688
+ return path23.join(base, "client.std.log");
7380
7689
  }
7381
7690
  if (type === "dev") {
7382
- return path22.join(base, "dev.log");
7691
+ return path23.join(base, "dev.log");
7383
7692
  }
7384
7693
  if (type === "dev-std") {
7385
- return path22.join(base, "dev.std.log");
7694
+ return path23.join(base, "dev.std.log");
7386
7695
  }
7387
7696
  if (type === "install-dep-std") {
7388
- return path22.join(base, "install-dep.std.log");
7697
+ return path23.join(base, "install-dep.std.log");
7389
7698
  }
7390
7699
  if (type === "browser") {
7391
- return path22.join(base, "browser.log");
7700
+ return path23.join(base, "browser.log");
7392
7701
  }
7393
7702
  throw new Error(`Unsupported log type: ${type}`);
7394
7703
  }
@@ -7565,9 +7874,9 @@ function camelToKebab(str) {
7565
7874
  }
7566
7875
 
7567
7876
  // src/commands/build/upload-static.handler.ts
7568
- import * as fs27 from "fs";
7569
- import * as os from "os";
7570
- import * as path23 from "path";
7877
+ import * as fs28 from "fs";
7878
+ import * as os2 from "os";
7879
+ import * as path24 from "path";
7571
7880
  import { execFileSync } from "child_process";
7572
7881
  function readCredentialsFromEnv() {
7573
7882
  const uploadPrefix = process.env.STATIC_UPLOAD_PREFIX;
@@ -7591,8 +7900,8 @@ async function uploadStatic(options) {
7591
7900
  endpoint = UPLOAD_STATIC_DEFAULTS.endpoint,
7592
7901
  region = UPLOAD_STATIC_DEFAULTS.region
7593
7902
  } = options;
7594
- const resolvedStaticDir = path23.resolve(staticDir);
7595
- if (!fs27.existsSync(resolvedStaticDir)) {
7903
+ const resolvedStaticDir = path24.resolve(staticDir);
7904
+ if (!fs28.existsSync(resolvedStaticDir)) {
7596
7905
  console.error(`${LOG_PREFIX} \u76EE\u5F55\u4E0D\u5B58\u5728: ${resolvedStaticDir}\uFF0C\u8DF3\u8FC7\u4E0A\u4F20`);
7597
7906
  return;
7598
7907
  }
@@ -7625,8 +7934,8 @@ async function uploadStatic(options) {
7625
7934
  ({ AccessKeyID: accessKeyID, SecretAccessKey: secretAccessKey, SessionToken: sessionToken } = uploadCredential);
7626
7935
  }
7627
7936
  console.error(`${LOG_PREFIX} \u4E0A\u4F20\u76EE\u6807: ${uploadPrefix}`);
7628
- const confPath = path23.join(os.tmpdir(), `.tosutilconfig-static-${process.pid}`);
7629
- fs27.writeFileSync(confPath, "");
7937
+ const confPath = path24.join(os2.tmpdir(), `.tosutilconfig-static-${process.pid}`);
7938
+ fs28.writeFileSync(confPath, "");
7630
7939
  try {
7631
7940
  console.error(`${LOG_PREFIX} \u914D\u7F6E tosutil...`);
7632
7941
  configureTosutil(resolvedTosutil, confPath, {
@@ -7640,7 +7949,7 @@ async function uploadStatic(options) {
7640
7949
  uploadToTos(resolvedTosutil, confPath, resolvedStaticDir, uploadPrefix);
7641
7950
  } finally {
7642
7951
  try {
7643
- fs27.unlinkSync(confPath);
7952
+ fs28.unlinkSync(confPath);
7644
7953
  } catch {
7645
7954
  }
7646
7955
  }
@@ -7660,8 +7969,8 @@ async function uploadStatic(options) {
7660
7969
  }
7661
7970
  }
7662
7971
  function resolveTosutilPath(tosutilPath) {
7663
- if (path23.isAbsolute(tosutilPath)) {
7664
- return fs27.existsSync(tosutilPath) ? tosutilPath : null;
7972
+ if (path24.isAbsolute(tosutilPath)) {
7973
+ return fs28.existsSync(tosutilPath) ? tosutilPath : null;
7665
7974
  }
7666
7975
  try {
7667
7976
  const resolved = execFileSync("which", [tosutilPath], { encoding: "utf-8" }).trim();
@@ -7706,7 +8015,7 @@ async function resolveBucketId(appId) {
7706
8015
  return bucketId;
7707
8016
  }
7708
8017
  function isDirEmpty(dirPath) {
7709
- const entries = fs27.readdirSync(dirPath);
8018
+ const entries = fs28.readdirSync(dirPath);
7710
8019
  return entries.length === 0;
7711
8020
  }
7712
8021
 
@@ -7794,18 +8103,19 @@ var commands = [
7794
8103
  upgradeCommand,
7795
8104
  actionPluginCommandGroup,
7796
8105
  capabilityCommandGroup,
8106
+ componentCommandGroup,
7797
8107
  migrationCommand,
7798
8108
  readLogsCommand,
7799
8109
  buildCommandGroup
7800
8110
  ];
7801
8111
 
7802
8112
  // src/index.ts
7803
- var envPath = path24.join(process.cwd(), ".env");
7804
- if (fs28.existsSync(envPath)) {
8113
+ var envPath = path25.join(process.cwd(), ".env");
8114
+ if (fs29.existsSync(envPath)) {
7805
8115
  dotenvConfig({ path: envPath });
7806
8116
  }
7807
- var __dirname = path24.dirname(fileURLToPath5(import.meta.url));
7808
- var pkg = JSON.parse(fs28.readFileSync(path24.join(__dirname, "../package.json"), "utf-8"));
8117
+ var __dirname = path25.dirname(fileURLToPath5(import.meta.url));
8118
+ var pkg = JSON.parse(fs29.readFileSync(path25.join(__dirname, "../package.json"), "utf-8"));
7809
8119
  var cli = new FullstackCLI(pkg.version);
7810
8120
  cli.useAll(commands);
7811
8121
  cli.run();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/fullstack-cli",
3
- "version": "1.1.48-alpha.0",
3
+ "version": "1.1.48-alpha.2",
4
4
  "description": "CLI tool for fullstack template management",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -31,7 +31,7 @@
31
31
  "access": "public"
32
32
  },
33
33
  "dependencies": {
34
- "@lark-apaas/http-client": "^0.1.6",
34
+ "@lark-apaas/http-client": "0.1.7-alpha.1",
35
35
  "@lydell/node-pty": "1.1.0",
36
36
  "@vercel/nft": "^0.30.3",
37
37
  "commander": "^13.0.0",
@@ -43,6 +43,7 @@
43
43
  "inflection": "^3.0.2",
44
44
  "pinyin-pro": "^3.27.0",
45
45
  "postgres": "^3.4.3",
46
+ "shadcn": "3.8.2",
46
47
  "ts-morph": "^27.0.0",
47
48
  "zod-to-json-schema": "^3.24.1"
48
49
  },