@4399ywkf/core 5.0.12 → 5.0.13

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
@@ -2763,33 +2763,38 @@ import { join as join8 } from "path";
2763
2763
  var i18nPlugin = createPlugin((options = {}) => ({
2764
2764
  name: "@4399ywkf/plugin-i18n",
2765
2765
  version: "1.0.0",
2766
- description: "\u56FD\u9645\u5316 (i18next) \u63D2\u4EF6",
2766
+ description: "\u56FD\u9645\u5316 (i18next) \u63D2\u4EF6 \u2014 TS-first \u5DE5\u4F5C\u6D41",
2767
2767
  setup(context) {
2768
2768
  const {
2769
2769
  defaultLocale = "zh-CN",
2770
2770
  locales = ["zh-CN", "en-US"],
2771
2771
  localesDir = "locales",
2772
+ sourceDir = "src/locales/default",
2772
2773
  defaultNS = ["common"],
2773
2774
  autoScaffold = true
2774
2775
  } = options;
2775
- const { cwd, logger } = context;
2776
+ const { cwd, logger, isDev } = context;
2776
2777
  if (autoScaffold) {
2777
- scaffoldLocaleFiles(cwd, localesDir, locales, defaultNS, logger);
2778
+ scaffoldSourceFiles(cwd, sourceDir, defaultNS, logger);
2779
+ scaffoldResourcesFile(cwd, sourceDir, defaultNS, locales, defaultLocale, logger);
2780
+ scaffoldConvertScript(cwd, sourceDir, localesDir, defaultLocale, logger);
2781
+ scaffoldI18nRc(cwd, localesDir, defaultLocale, locales, logger);
2782
+ scaffoldLocaleJsonDirs(cwd, localesDir, locales, defaultLocale, defaultNS, logger);
2778
2783
  }
2779
2784
  const hooks = {
2780
2785
  modifyRspackConfig(rspackConfig) {
2781
2786
  const aliases = rspackConfig.resolve?.alias || {};
2782
2787
  if (!aliases["@locales"]) {
2783
2788
  aliases["@locales"] = join8(cwd, localesDir);
2784
- rspackConfig.resolve = { ...rspackConfig.resolve, alias: aliases };
2785
2789
  }
2790
+ rspackConfig.resolve = { ...rspackConfig.resolve, alias: aliases };
2786
2791
  return rspackConfig;
2787
2792
  },
2788
2793
  generateFiles(ctx) {
2789
2794
  return [
2790
2795
  {
2791
2796
  path: "i18n.ts",
2792
- content: generateI18nCode(defaultLocale, locales, localesDir, defaultNS)
2797
+ content: generateI18nCode({ defaultLocale, locales, localesDir, sourceDir, defaultNS, isDev })
2793
2798
  }
2794
2799
  ];
2795
2800
  },
@@ -2799,7 +2804,6 @@ var i18nPlugin = createPlugin((options = {}) => ({
2799
2804
  `import { initI18n } from "./i18n";`
2800
2805
  ],
2801
2806
  topLevel: [
2802
- `// \u521D\u59CB\u5316 i18n\uFF08\u5728\u5E94\u7528\u542F\u52A8\u524D\uFF09`,
2803
2807
  `await initI18n();`
2804
2808
  ]
2805
2809
  };
@@ -2808,38 +2812,43 @@ var i18nPlugin = createPlugin((options = {}) => ({
2808
2812
  return hooks;
2809
2813
  }
2810
2814
  }));
2811
- function generateI18nCode(defaultLocale, locales, localesDir, defaultNS) {
2815
+ function generateI18nCode(opts) {
2816
+ const { defaultLocale, locales, defaultNS, sourceDir } = opts;
2817
+ const defaultDirAlias = sourceDir.replace(/^src\//, "");
2818
+ const parentDirAlias = defaultDirAlias.replace(/\/[^/]+$/, "");
2812
2819
  return `// \u6B64\u6587\u4EF6\u7531 @4399ywkf/plugin-i18n \u81EA\u52A8\u751F\u6210
2813
2820
  import i18n from "i18next";
2814
2821
  import LanguageDetector from "i18next-browser-languagedetector";
2815
2822
  import resourcesToBackend from "i18next-resources-to-backend";
2816
2823
  import { initReactI18next } from "react-i18next";
2824
+ import { normalizeLocale, SUPPORTED_LOCALES, DEFAULT_LOCALE } from "@/${parentDirAlias}/resources";
2817
2825
 
2818
- export const DEFAULT_LOCALE = "${defaultLocale}";
2819
-
2820
- export const SUPPORTED_LOCALES = ${JSON.stringify(locales)} as const;
2826
+ export { DEFAULT_LOCALE, SUPPORTED_LOCALES, normalizeLocale };
2827
+ export type { SupportedLocale, NS } from "@/${parentDirAlias}/resources";
2821
2828
 
2822
- export type SupportedLocale = typeof SUPPORTED_LOCALES[number];
2829
+ const isDev = process.env.NODE_ENV === "development";
2823
2830
 
2824
2831
  const instance = i18n
2825
2832
  .use(initReactI18next)
2826
2833
  .use(LanguageDetector)
2827
2834
  .use(
2828
2835
  resourcesToBackend(async (lng: string, ns: string) => {
2829
- return import(\`@locales/\${normalizeLocale(lng)}/\${ns}.json\`);
2836
+ const normalizedLng = normalizeLocale(lng);
2837
+
2838
+ // \u5F00\u53D1\u6A21\u5F0F\u4E0B\uFF0C\u9ED8\u8BA4\u8BED\u8A00\u76F4\u63A5 import TS\uFF08\u5373\u65F6\u751F\u6548\uFF0C\u65E0\u9700\u5148\u751F\u6210 JSON\uFF09
2839
+ if (isDev && normalizedLng === "${defaultLocale}") {
2840
+ return import("@/${defaultDirAlias}/" + ns);
2841
+ }
2842
+
2843
+ // \u5176\u4ED6\u8BED\u8A00 / \u751F\u4EA7\u6A21\u5F0F\uFF1A\u61D2\u52A0\u8F7D JSON
2844
+ return import(
2845
+ /* webpackInclude: /\\.json$/ */
2846
+ /* webpackChunkName: "locales-[request]" */
2847
+ \`@locales/\${normalizedLng}/\${ns}.json\`
2848
+ );
2830
2849
  })
2831
2850
  );
2832
2851
 
2833
- function normalizeLocale(locale?: string): string {
2834
- if (!locale) return DEFAULT_LOCALE;
2835
- for (const l of SUPPORTED_LOCALES) {
2836
- if (l.startsWith(locale) || locale.startsWith(l.split("-")[0])) {
2837
- return l;
2838
- }
2839
- }
2840
- return DEFAULT_LOCALE;
2841
- }
2842
-
2843
2852
  let initialized = false;
2844
2853
 
2845
2854
  export async function initI18n(lang?: string): Promise<typeof i18n> {
@@ -2860,19 +2869,191 @@ export { instance as i18n };
2860
2869
  export default instance;
2861
2870
  `;
2862
2871
  }
2863
- function scaffoldLocaleFiles(cwd, localesDir, locales, namespaces, logger) {
2872
+ function scaffoldSourceFiles(cwd, sourceDir, namespaces, logger) {
2873
+ const dir = join8(cwd, sourceDir);
2874
+ if (!existsSync8(dir)) {
2875
+ mkdirSync3(dir, { recursive: true });
2876
+ }
2877
+ for (const ns of namespaces) {
2878
+ const filePath = join8(dir, `${ns}.ts`);
2879
+ if (!existsSync8(filePath)) {
2880
+ writeFileSync4(filePath, buildDefaultNsFile(ns), "utf-8");
2881
+ logger.info(`\u5DF2\u751F\u6210\u7FFB\u8BD1\u6E90\u6587\u4EF6: ${sourceDir}/${ns}.ts`);
2882
+ }
2883
+ }
2884
+ const indexPath = join8(dir, "index.ts");
2885
+ if (!existsSync8(indexPath)) {
2886
+ const imports = namespaces.map((ns) => `import ${ns} from "./${ns}";`).join("\n");
2887
+ const entries = namespaces.join(",\n ");
2888
+ const content = `${imports}
2889
+
2890
+ const resources = {
2891
+ ${entries},
2892
+ } as const;
2893
+
2894
+ export default resources;
2895
+ `;
2896
+ writeFileSync4(indexPath, content, "utf-8");
2897
+ logger.info(`\u5DF2\u751F\u6210\u7FFB\u8BD1\u7D22\u5F15: ${sourceDir}/index.ts`);
2898
+ }
2899
+ }
2900
+ function buildDefaultNsFile(ns) {
2901
+ if (ns === "common") {
2902
+ return `export default {
2903
+ welcome: "\u6B22\u8FCE\u4F7F\u7528",
2904
+ loading: "\u52A0\u8F7D\u4E2D...",
2905
+ confirm: "\u786E\u5B9A",
2906
+ cancel: "\u53D6\u6D88",
2907
+ save: "\u4FDD\u5B58",
2908
+ delete: "\u5220\u9664",
2909
+ edit: "\u7F16\u8F91",
2910
+ back: "\u8FD4\u56DE",
2911
+ } as const;
2912
+ `;
2913
+ }
2914
+ return `export default {
2915
+ title: "${ns}",
2916
+ } as const;
2917
+ `;
2918
+ }
2919
+ function scaffoldResourcesFile(cwd, sourceDir, namespaces, locales, defaultLocale, logger) {
2920
+ const parentDir = join8(cwd, sourceDir, "..");
2921
+ const filePath = join8(parentDir, "resources.ts");
2922
+ if (existsSync8(filePath)) return;
2923
+ const content = `import resources from "./default";
2924
+
2925
+ export const DEFAULT_LOCALE = "${defaultLocale}";
2926
+
2927
+ export const SUPPORTED_LOCALES = ${JSON.stringify(locales)} as const;
2928
+
2929
+ export type SupportedLocale = (typeof SUPPORTED_LOCALES)[number];
2930
+
2931
+ export type DefaultResources = typeof resources;
2932
+
2933
+ export type NS = keyof DefaultResources;
2934
+
2935
+ export const normalizeLocale = (locale?: string): SupportedLocale => {
2936
+ if (!locale) return DEFAULT_LOCALE as SupportedLocale;
2937
+
2938
+ for (const l of SUPPORTED_LOCALES) {
2939
+ if (l.startsWith(locale) || locale.startsWith(l.split("-")[0])) {
2940
+ return l;
2941
+ }
2942
+ }
2943
+
2944
+ return DEFAULT_LOCALE as SupportedLocale;
2945
+ };
2946
+
2947
+ export const localeOptions = ${JSON.stringify(
2948
+ locales.map((l) => ({ value: l, label: getLocaleLabel(l) })),
2949
+ null,
2950
+ 2
2951
+ )} as const;
2952
+ `;
2953
+ writeFileSync4(filePath, content, "utf-8");
2954
+ logger.info(`\u5DF2\u751F\u6210\u7C7B\u578B\u6587\u4EF6: ${sourceDir}/../resources.ts`);
2955
+ }
2956
+ function getLocaleLabel(locale) {
2957
+ const map = {
2958
+ "zh-CN": "\u7B80\u4F53\u4E2D\u6587",
2959
+ "zh-TW": "\u7E41\u9AD4\u4E2D\u6587",
2960
+ "en-US": "English",
2961
+ "ja-JP": "\u65E5\u672C\u8A9E",
2962
+ "ko-KR": "\uD55C\uAD6D\uC5B4",
2963
+ "de-DE": "Deutsch",
2964
+ "fr-FR": "Fran\xE7ais",
2965
+ "es-ES": "Espa\xF1ol",
2966
+ "pt-BR": "Portugu\xEAs",
2967
+ "ru-RU": "\u0420\u0443\u0441\u0441\u043A\u0438\u0439",
2968
+ "it-IT": "Italiano",
2969
+ "vi-VN": "Ti\u1EBFng Vi\u1EC7t",
2970
+ "ar": "\u0627\u0644\u0639\u0631\u0628\u064A\u0629"
2971
+ };
2972
+ return map[locale] || locale;
2973
+ }
2974
+ function scaffoldConvertScript(cwd, sourceDir, localesDir, defaultLocale, logger) {
2975
+ const scriptsDir = join8(cwd, "scripts");
2976
+ const scriptPath = join8(scriptsDir, "i18n-gen.js");
2977
+ if (existsSync8(scriptPath)) return;
2978
+ if (!existsSync8(scriptsDir)) {
2979
+ mkdirSync3(scriptsDir, { recursive: true });
2980
+ }
2981
+ const content = `const fs = require("fs");
2982
+ const path = require("path");
2983
+
2984
+ const sourceDir = path.join(__dirname, "../${sourceDir}");
2985
+ const targetDir = path.join(__dirname, "../${localesDir}/${defaultLocale}");
2986
+
2987
+ const files = fs
2988
+ .readdirSync(sourceDir)
2989
+ .filter((file) => file.endsWith(".ts") && file !== "index.ts")
2990
+ .map((file) => path.basename(file, ".ts"));
2991
+
2992
+ require("ts-node/register");
2993
+
2994
+ if (!fs.existsSync(targetDir)) {
2995
+ fs.mkdirSync(targetDir, { recursive: true });
2996
+ }
2997
+
2998
+ console.log("\u5F00\u59CB\u8F6C\u6362 TypeScript \u6587\u4EF6\u5230 JSON...\\n");
2999
+
3000
+ files.forEach((fileName) => {
3001
+ try {
3002
+ const modulePath = path.join(sourceDir, \`\${fileName}.ts\`);
3003
+ delete require.cache[require.resolve(modulePath)];
3004
+ const moduleContent = require(modulePath).default;
3005
+ const jsonContent = JSON.stringify(moduleContent, null, 2);
3006
+ const targetPath = path.join(targetDir, \`\${fileName}.json\`);
3007
+ fs.writeFileSync(targetPath, jsonContent, "utf8");
3008
+ console.log(\` \${fileName}.ts \u2192 \${fileName}.json\`);
3009
+ } catch (error) {
3010
+ console.error(\` \u8F6C\u6362 \${fileName}.ts \u5931\u8D25:\`, error.message);
3011
+ }
3012
+ });
3013
+
3014
+ console.log("\\n\u8F6C\u6362\u5B8C\u6210\uFF01");
3015
+ `;
3016
+ writeFileSync4(scriptPath, content, "utf-8");
3017
+ logger.info("\u5DF2\u751F\u6210\u8F6C\u6362\u811A\u672C: scripts/i18n-gen.js");
3018
+ }
3019
+ function scaffoldI18nRc(cwd, localesDir, defaultLocale, locales, logger) {
3020
+ const filePath = join8(cwd, ".i18nrc.js");
3021
+ if (existsSync8(filePath)) return;
3022
+ const outputLocales = locales.filter((l) => l !== defaultLocale).map((l) => `"${l}"`).join(", ");
3023
+ const content = `const { defineConfig } = require("@lobehub/i18n-cli");
3024
+
3025
+ module.exports = defineConfig({
3026
+ entry: "${localesDir}/${defaultLocale}",
3027
+ entryLocale: "${defaultLocale}",
3028
+ output: "${localesDir}",
3029
+ outputLocales: [${outputLocales}],
3030
+ });
3031
+ `;
3032
+ writeFileSync4(filePath, content, "utf-8");
3033
+ logger.info("\u5DF2\u751F\u6210\u7FFB\u8BD1\u914D\u7F6E: .i18nrc.js\uFF08@lobehub/i18n-cli\uFF09");
3034
+ }
3035
+ function scaffoldLocaleJsonDirs(cwd, localesDir, locales, defaultLocale, namespaces, logger) {
2864
3036
  const baseDir = join8(cwd, localesDir);
2865
3037
  for (const locale of locales) {
2866
3038
  const localeDir = join8(baseDir, locale);
2867
3039
  if (!existsSync8(localeDir)) {
2868
3040
  mkdirSync3(localeDir, { recursive: true });
2869
3041
  }
3042
+ if (locale === defaultLocale) continue;
2870
3043
  for (const ns of namespaces) {
2871
3044
  const filePath = join8(localeDir, `${ns}.json`);
2872
3045
  if (!existsSync8(filePath)) {
2873
- const isDefault = locale === locales[0];
2874
- const content = isDefault ? JSON.stringify({ welcome: "\u6B22\u8FCE\u4F7F\u7528" }, null, 2) : JSON.stringify({ welcome: "Welcome" }, null, 2);
2875
- writeFileSync4(filePath, content + "\n", "utf-8");
3046
+ const placeholder = ns === "common" ? JSON.stringify({
3047
+ welcome: "Welcome",
3048
+ loading: "Loading...",
3049
+ confirm: "OK",
3050
+ cancel: "Cancel",
3051
+ save: "Save",
3052
+ delete: "Delete",
3053
+ edit: "Edit",
3054
+ back: "Back"
3055
+ }, null, 2) : JSON.stringify({ title: ns }, null, 2);
3056
+ writeFileSync4(filePath, placeholder + "\n", "utf-8");
2876
3057
  logger.info(`\u5DF2\u751F\u6210\u7FFB\u8BD1\u6587\u4EF6: ${localesDir}/${locale}/${ns}.json`);
2877
3058
  }
2878
3059
  }
@@ -2880,22 +3061,37 @@ function scaffoldLocaleFiles(cwd, localesDir, locales, namespaces, logger) {
2880
3061
  }
2881
3062
 
2882
3063
  // src/plugin/builtin/theme.ts
3064
+ import { join as join9 } from "path";
2883
3065
  var themePlugin = createPlugin((options = {}) => ({
2884
3066
  name: "@4399ywkf/plugin-theme",
2885
- version: "1.0.0",
2886
- description: "antd-style \u4E3B\u9898\u7CFB\u7EDF\u63D2\u4EF6",
3067
+ version: "2.0.0",
3068
+ description: "antd-style \u54CD\u5E94\u5F0F\u4E3B\u9898\u7CFB\u7EDF\u63D2\u4EF6",
2887
3069
  setup(context) {
2888
3070
  const {
2889
3071
  darkMode = true,
2890
- defaultAppearance = "auto",
2891
- primaryColor = "blue",
3072
+ defaultAppearance = "dark",
3073
+ primaryColor = "#1677ff",
3074
+ neutralColor,
2892
3075
  prefixCls = "ant",
2893
3076
  cssVar = true,
2894
- globalReset = true
3077
+ globalReset = true,
3078
+ externalTheme = false
2895
3079
  } = options;
2896
3080
  const { logger } = context;
2897
- logger.info(`\u4E3B\u9898\u6A21\u5F0F: ${defaultAppearance}, \u4E3B\u8272: ${primaryColor}`);
3081
+ logger.info(`\u4E3B\u9898\u6A21\u5F0F: ${defaultAppearance}, \u4E3B\u8272: ${primaryColor}, \u54CD\u5E94\u5F0F: \u2713`);
2898
3082
  const hooks = {
3083
+ modifyRspackConfig(config, ctx) {
3084
+ const themePath = join9(ctx.cwd, ".ywkf", "theme.tsx");
3085
+ const currentAlias = config.resolve?.alias ?? {};
3086
+ config.resolve = {
3087
+ ...config.resolve,
3088
+ alias: {
3089
+ ...currentAlias,
3090
+ "@ywkf/theme": themePath
3091
+ }
3092
+ };
3093
+ return config;
3094
+ },
2899
3095
  generateFiles(ctx) {
2900
3096
  return [
2901
3097
  {
@@ -2904,9 +3100,11 @@ var themePlugin = createPlugin((options = {}) => ({
2904
3100
  darkMode,
2905
3101
  defaultAppearance,
2906
3102
  primaryColor,
3103
+ neutralColor,
2907
3104
  prefixCls,
2908
3105
  cssVar,
2909
- globalReset
3106
+ globalReset,
3107
+ externalTheme
2910
3108
  })
2911
3109
  }
2912
3110
  ];
@@ -2917,61 +3115,168 @@ var themePlugin = createPlugin((options = {}) => ({
2917
3115
  `import { ThemeWrapper } from "./theme";`
2918
3116
  ]
2919
3117
  };
3118
+ },
3119
+ modifyBootstrapCode(code) {
3120
+ const providerEntry = ` {
3121
+ component: ThemeWrapper as React.ComponentType<{ children: React.ReactNode }>,
3122
+ props: {},
3123
+ order: 10,
3124
+ }`;
3125
+ if (code.includes("providers: []")) {
3126
+ code = code.replace(
3127
+ "providers: []",
3128
+ `providers: [
3129
+ ${providerEntry},
3130
+ ]`
3131
+ );
3132
+ } else if (code.includes("providers: [")) {
3133
+ code = code.replace(
3134
+ "providers: [",
3135
+ `providers: [
3136
+ ${providerEntry},`
3137
+ );
3138
+ }
3139
+ if (!code.includes("import React")) {
3140
+ code = code.replace(
3141
+ `import { bootstrap`,
3142
+ `import React from "react";
3143
+ import { bootstrap`
3144
+ );
3145
+ }
3146
+ return code;
2920
3147
  }
2921
- // Provider 由生成的 theme.tsx 文件在用户层使用
2922
- // 用户可以在 src/app.config.ts 中通过 providers 引入 ThemeWrapper
2923
3148
  };
2924
3149
  return hooks;
2925
3150
  }
2926
3151
  }));
2927
3152
  function generateThemeProvider(opts) {
2928
- const { darkMode, defaultAppearance, primaryColor, prefixCls, cssVar, globalReset } = opts;
2929
- return `// \u6B64\u6587\u4EF6\u7531 @4399ywkf/plugin-theme \u81EA\u52A8\u751F\u6210
2930
- import React, { useEffect, type ReactNode } from "react";
2931
- import { ThemeProvider, createGlobalStyle } from "antd-style";
3153
+ const {
3154
+ darkMode,
3155
+ defaultAppearance,
3156
+ primaryColor,
3157
+ neutralColor,
3158
+ prefixCls,
3159
+ cssVar,
3160
+ globalReset,
3161
+ externalTheme
3162
+ } = opts;
3163
+ const sections = [];
3164
+ sections.push(`// \u6B64\u6587\u4EF6\u7531 @4399ywkf/plugin-theme \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u52FF\u624B\u52A8\u4FEE\u6539`);
3165
+ sections.push(buildImports({ globalReset, cssVar }));
3166
+ sections.push(TYPES_CODE);
3167
+ sections.push(buildStoreCode({ defaultAppearance, primaryColor, neutralColor }));
3168
+ sections.push(HOOKS_CODE);
3169
+ if (globalReset) sections.push(GLOBAL_RESET_CODE);
3170
+ if (cssVar) sections.push(CSS_VAR_SYNC_CODE);
3171
+ if (darkMode) sections.push(APPEARANCE_SYNC_CODE);
3172
+ if (externalTheme) sections.push(EXTERNAL_THEME_CODE);
3173
+ sections.push(buildWrapperCode({ darkMode, cssVar, globalReset, externalTheme, prefixCls }));
3174
+ return sections.join("\n");
3175
+ }
3176
+ function buildImports(opts) {
3177
+ const reactImports = [
3178
+ "useCallback",
3179
+ "useEffect",
3180
+ ...opts.cssVar ? ["useLayoutEffect", "useRef"] : [],
3181
+ "type ReactNode"
3182
+ ];
3183
+ const antdStyleImports = [
3184
+ "ThemeProvider as AntdThemeProvider",
3185
+ "type GetAntdTheme",
3186
+ ...opts.globalReset ? ["createGlobalStyle", "css"] : []
3187
+ ];
3188
+ return `
3189
+ import React, { ${reactImports.join(", ")} } from "react";
3190
+ import { ${antdStyleImports.join(", ")} } from "antd-style";
3191
+ import { createWithEqualityFn } from "zustand/traditional";
3192
+ import { shallow } from "zustand/shallow";`;
3193
+ }
3194
+ var TYPES_CODE = `
3195
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 Types \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
2932
3196
 
2933
- ${globalReset ? GLOBAL_RESET_CODE : ""}
3197
+ export type ThemeAppearance = "light" | "dark" | "auto";
2934
3198
 
2935
- const DEFAULT_APPEARANCE = "${defaultAppearance}" as const;
3199
+ export interface ThemeState {
3200
+ appearance: ThemeAppearance;
3201
+ primaryColor: string;
3202
+ neutralColor?: string;
3203
+ }
2936
3204
 
2937
- interface ThemeWrapperProps {
2938
- children: ReactNode;
3205
+ export interface ThemeActions {
3206
+ setAppearance: (mode: ThemeAppearance) => void;
3207
+ setPrimaryColor: (color: string) => void;
3208
+ setNeutralColor: (color: string) => void;
3209
+ /** \u6279\u91CF\u66F4\u65B0\u4E3B\u9898\u72B6\u6001 */
3210
+ setTheme: (partial: Partial<ThemeState>) => void;
2939
3211
  }
2940
3212
 
2941
- /**
2942
- * \u4E3B\u9898\u5305\u88F9\u7EC4\u4EF6
2943
- * \u7531 themePlugin \u81EA\u52A8\u6CE8\u5165\u5230\u5E94\u7528\u542F\u52A8\u5C42
2944
- */
2945
- export function ThemeWrapper({ children }: ThemeWrapperProps) {
2946
- ${darkMode ? DARK_MODE_EFFECT : ""}
3213
+ export type ThemeStore = ThemeState & ThemeActions;`;
3214
+ function buildStoreCode(opts) {
3215
+ const neutralLine = opts.neutralColor ? `
3216
+ neutralColor: "${opts.neutralColor}",` : "";
3217
+ return `
3218
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 Theme Store \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
2947
3219
 
2948
- return (
2949
- <ThemeProvider
2950
- prefixCls="${prefixCls}"
2951
- ${defaultAppearance !== "auto" ? `appearance="${defaultAppearance}"` : ""}
2952
- theme={{
2953
- cssVar: ${cssVar},
2954
- token: {
2955
- colorPrimary: "${primaryColor}",
2956
- },
2957
- }}
2958
- themeMode={DEFAULT_APPEARANCE}
2959
- >
2960
- ${globalReset ? "<GlobalReset />" : ""}
2961
- {children}
2962
- </ThemeProvider>
2963
- );
2964
- }
3220
+ const DEFAULT_THEME: ThemeState = {
3221
+ appearance: "${opts.defaultAppearance}",
3222
+ primaryColor: "${opts.primaryColor}",${neutralLine}
3223
+ };
2965
3224
 
2966
- export default ThemeWrapper;
2967
- `;
3225
+ export const useThemeStore = createWithEqualityFn<ThemeStore>()(
3226
+ (set) => ({
3227
+ ...DEFAULT_THEME,
3228
+ setAppearance: (mode) => set({ appearance: mode }),
3229
+ setPrimaryColor: (color) => set({ primaryColor: color }),
3230
+ setNeutralColor: (color) => set({ neutralColor: color }),
3231
+ setTheme: (partial) => set(partial),
3232
+ }),
3233
+ shallow,
3234
+ );`;
2968
3235
  }
3236
+ var HOOKS_CODE = `
3237
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 Convenience Hooks \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
3238
+
3239
+ /** \u83B7\u53D6\u5F53\u524D\u4E3B\u9898\u72B6\u6001\uFF08appearance + primaryColor + neutralColor\uFF09 */
3240
+ export const useTheme = () =>
3241
+ useThemeStore(
3242
+ (s) => ({
3243
+ appearance: s.appearance,
3244
+ primaryColor: s.primaryColor,
3245
+ neutralColor: s.neutralColor,
3246
+ }),
3247
+ shallow,
3248
+ );
3249
+
3250
+ /** \u4EC5\u8BA2\u9605 appearance */
3251
+ export const useAppearance = () => useThemeStore((s) => s.appearance);
3252
+
3253
+ /** \u4EC5\u8BA2\u9605 primaryColor */
3254
+ export const usePrimaryColor = () => useThemeStore((s) => s.primaryColor);`;
2969
3255
  var GLOBAL_RESET_CODE = `
2970
- const GlobalReset = createGlobalStyle\`
3256
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 Global Style \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
3257
+ // \u53C2\u8003 lobe-ui GlobalStyle\uFF1A\u4F7F\u7528 theme tokens \u5B9E\u73B0\u54CD\u5E94\u5F0F\u5168\u5C40\u6837\u5F0F
3258
+
3259
+ const GlobalReset = createGlobalStyle(({ theme }) => css\`
3260
+ :root {
3261
+ --font-settings: "cv01", "tnum", "kern";
3262
+ --font-variations: "opsz" auto, tabular-nums;
3263
+ }
3264
+
2971
3265
  *,
2972
3266
  *::before,
2973
3267
  *::after {
2974
3268
  box-sizing: border-box;
3269
+ vertical-align: baseline;
3270
+ }
3271
+
3272
+ * {
3273
+ scrollbar-color: \${theme.colorFill} transparent;
3274
+ scrollbar-width: thin;
3275
+ }
3276
+
3277
+ html {
3278
+ overscroll-behavior: none;
3279
+ color-scheme: \${theme.isDarkMode ? "dark" : "light"};
2975
3280
  }
2976
3281
 
2977
3282
  html, body, #root, #app {
@@ -2981,34 +3286,191 @@ const GlobalReset = createGlobalStyle\`
2981
3286
  }
2982
3287
 
2983
3288
  body {
2984
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
2985
- "Helvetica Neue", Arial, "Noto Sans", sans-serif;
3289
+ overflow: hidden auto;
3290
+ min-height: 100vh;
3291
+ font-family: \${theme.fontFamily};
3292
+ font-size: \${theme.fontSize}px;
3293
+ font-feature-settings: var(--font-settings);
3294
+ font-variation-settings: var(--font-variations);
3295
+ line-height: 1;
3296
+ color: \${theme.colorTextBase};
3297
+ text-size-adjust: none;
3298
+ text-rendering: optimizelegibility;
3299
+ word-wrap: break-word;
3300
+ background-color: \${theme.colorBgLayout};
2986
3301
  -webkit-font-smoothing: antialiased;
2987
3302
  -moz-osx-font-smoothing: grayscale;
3303
+ -webkit-overflow-scrolling: touch;
3304
+ -webkit-tap-highlight-color: transparent;
2988
3305
  }
2989
- \`;
2990
- `;
2991
- var DARK_MODE_EFFECT = `
3306
+
3307
+ code {
3308
+ font-family: \${theme.fontFamilyCode} !important;
3309
+ }
3310
+
3311
+ ::selection {
3312
+ color: #000;
3313
+ -webkit-text-fill-color: unset !important;
3314
+ }
3315
+ \`);`;
3316
+ var CSS_VAR_SYNC_CODE = `
3317
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 CSS Variable Sync \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
3318
+ // \u5C06 antd-style \u6CE8\u5165\u7684 css-var-* class \u540C\u6B65\u5230 <html>\uFF0C
3319
+ // \u4F7F\u5168\u5C40 CSS / Tailwind \u4E5F\u80FD\u6D88\u8D39 antd CSS \u53D8\u91CF
3320
+
3321
+ const CSS_VAR_PREFIX = "css-var-";
3322
+
3323
+ function useCssVarSync(ref: React.RefObject<HTMLDivElement | null>) {
3324
+ useLayoutEffect(() => {
3325
+ const node = ref.current;
3326
+ if (!node) return;
3327
+
3328
+ const htmlEl = document.documentElement;
3329
+ let currentClasses: string[] = [];
3330
+
3331
+ const sync = () => {
3332
+ for (const cls of currentClasses) htmlEl.classList.remove(cls);
3333
+
3334
+ const next: string[] = [];
3335
+ let el: HTMLElement | null = node;
3336
+ while (el && el !== htmlEl) {
3337
+ for (const cls of el.classList) {
3338
+ if (cls.startsWith(CSS_VAR_PREFIX)) next.push(cls);
3339
+ }
3340
+ el = el.parentElement;
3341
+ }
3342
+
3343
+ for (const cls of next) htmlEl.classList.add(cls);
3344
+ currentClasses = next;
3345
+ };
3346
+
3347
+ sync();
3348
+
3349
+ const observer = new MutationObserver(sync);
3350
+ let el: HTMLElement | null = node;
3351
+ while (el && el !== htmlEl) {
3352
+ observer.observe(el, { attributeFilter: ["class"] });
3353
+ el = el.parentElement;
3354
+ }
3355
+
3356
+ return () => {
3357
+ observer.disconnect();
3358
+ for (const cls of currentClasses) htmlEl.classList.remove(cls);
3359
+ };
3360
+ }, []);
3361
+ }`;
3362
+ var APPEARANCE_SYNC_CODE = `
3363
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 Appearance Sync \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
3364
+
3365
+ function useAppearanceSync(appearance: ThemeAppearance) {
2992
3366
  useEffect(() => {
2993
- if (DEFAULT_APPEARANCE !== "auto") {
2994
- document.documentElement.dataset.theme = DEFAULT_APPEARANCE;
3367
+ if (appearance !== "auto") {
3368
+ document.documentElement.dataset.theme = appearance;
2995
3369
  return;
2996
3370
  }
2997
3371
 
2998
- const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
2999
- document.documentElement.dataset.theme = mediaQuery.matches ? "dark" : "light";
3372
+ const mq = window.matchMedia("(prefers-color-scheme: dark)");
3373
+ document.documentElement.dataset.theme = mq.matches ? "dark" : "light";
3000
3374
 
3001
3375
  function handleChange(e: MediaQueryListEvent) {
3002
3376
  document.documentElement.dataset.theme = e.matches ? "dark" : "light";
3003
3377
  }
3004
3378
 
3005
- mediaQuery.addEventListener("change", handleChange);
3006
- return () => mediaQuery.removeEventListener("change", handleChange);
3379
+ mq.addEventListener("change", handleChange);
3380
+ return () => mq.removeEventListener("change", handleChange);
3381
+ }, [appearance]);
3382
+ }`;
3383
+ var EXTERNAL_THEME_CODE = `
3384
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 External Theme Injection \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
3385
+ // \u5FAE\u524D\u7AEF\u573A\u666F\uFF1A\u76D1\u542C\u4E3B\u5E94\u7528\u4E0B\u53D1\u7684\u4E3B\u9898\u53D8\u66F4
3386
+
3387
+ function useExternalTheme() {
3388
+ useEffect(() => {
3389
+ const hostTheme = (window as any).__YWKF_THEME__;
3390
+ if (hostTheme && typeof hostTheme === "object") {
3391
+ useThemeStore.getState().setTheme(hostTheme);
3392
+ }
3393
+
3394
+ const handler = (e: Event) => {
3395
+ const detail = (e as CustomEvent<Partial<ThemeState>>).detail;
3396
+ if (detail) useThemeStore.getState().setTheme(detail);
3397
+ };
3398
+
3399
+ window.addEventListener("ywkf:theme-change", handler);
3400
+ return () => window.removeEventListener("ywkf:theme-change", handler);
3007
3401
  }, []);
3402
+ }`;
3403
+ function buildWrapperCode(opts) {
3404
+ const { darkMode, cssVar, globalReset, externalTheme, prefixCls } = opts;
3405
+ const refLine = cssVar ? "\n const containerRef = useRef<HTMLDivElement>(null);" : "";
3406
+ const cssVarSyncLine = cssVar ? "\n useCssVarSync(containerRef);" : "";
3407
+ const appearanceSyncLine = darkMode ? "\n useAppearanceSync(appearance);" : "";
3408
+ const externalThemeLine = externalTheme ? "\n useExternalTheme();" : "";
3409
+ const childrenSlot = cssVar ? `<div ref={containerRef} style={{ display: "contents" }}>
3410
+ {children}
3411
+ </div>` : "{children}";
3412
+ return `
3413
+ // \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550 ThemeWrapper \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550
3414
+
3415
+ interface ThemeWrapperProps {
3416
+ children: ReactNode;
3417
+ }
3418
+
3419
+ /**
3420
+ * \u4E3B\u9898\u5305\u88F9\u7EC4\u4EF6
3421
+ *
3422
+ * \u7531 themePlugin \u81EA\u52A8\u6CE8\u5165\u5230\u5E94\u7528\u542F\u52A8\u5C42\uFF0C\u4ECE useThemeStore \u8BFB\u53D6\u4E3B\u9898\u72B6\u6001\u3002
3423
+ * \u4E1A\u52A1\u4FA7\u901A\u8FC7 useThemeStore / useTheme \u6D88\u8D39\u6216\u4FEE\u6539\u4E3B\u9898\u3002
3424
+ */
3425
+ export function ThemeWrapper({ children }: ThemeWrapperProps) {${refLine}
3426
+ const { appearance, primaryColor } = useThemeStore(
3427
+ (s) => ({ appearance: s.appearance, primaryColor: s.primaryColor }),
3428
+ shallow,
3429
+ );${cssVarSyncLine}${appearanceSyncLine}${externalThemeLine}
3430
+
3431
+ const theme = useCallback<GetAntdTheme>(
3432
+ () => ({${cssVar ? "\n cssVar: true," : ""}
3433
+ token: {
3434
+ colorPrimary: primaryColor,
3435
+ // lobe-ui base tokens
3436
+ borderRadius: 8,
3437
+ borderRadiusLG: 12,
3438
+ borderRadiusSM: 6,
3439
+ borderRadiusXS: 4,
3440
+ controlHeight: 36,
3441
+ fontFamily: [
3442
+ '"HarmonyOS Sans", "Segoe UI", "SF Pro Display"',
3443
+ '-apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", Arial',
3444
+ '"PingFang SC", "Hiragino Sans GB", "Microsoft Yahei", "Noto Sans SC", sans-serif',
3445
+ '"Segoe UI Emoji", "Noto Color Emoji"',
3446
+ ].join(", "),
3447
+ fontFamilyCode: [
3448
+ 'Hack, ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas',
3449
+ '"PingFang SC", "Noto Sans SC", monospace',
3450
+ ].join(", "),
3451
+ },
3452
+ }),
3453
+ [primaryColor],
3454
+ );
3455
+
3456
+ return (
3457
+ <AntdThemeProvider
3458
+ prefixCls="${prefixCls}"
3459
+ themeMode={appearance}
3460
+ theme={theme}
3461
+ >
3462
+ ${globalReset ? "<GlobalReset />" : ""}
3463
+ ${childrenSlot}
3464
+ </AntdThemeProvider>
3465
+ );
3466
+ }
3467
+
3468
+ export default ThemeWrapper;
3008
3469
  `;
3470
+ }
3009
3471
 
3010
3472
  // src/plugin/builtin/mock.ts
3011
- import { resolve as resolve2, join as join9 } from "path";
3473
+ import { resolve as resolve2, join as join10 } from "path";
3012
3474
  import { existsSync as existsSync9, readdirSync as readdirSync2, statSync as statSync2 } from "fs";
3013
3475
  var mockPlugin = createPlugin((options = {}) => ({
3014
3476
  name: "@4399ywkf/plugin-mock",
@@ -3063,7 +3525,7 @@ function scanMockFiles(dir) {
3063
3525
  }
3064
3526
  const entries = readdirSync2(dir);
3065
3527
  for (const entry of entries) {
3066
- const fullPath = join9(dir, entry);
3528
+ const fullPath = join10(dir, entry);
3067
3529
  const stat = statSync2(fullPath);
3068
3530
  if (stat.isFile() && /\.(ts|js|mjs)$/.test(entry)) {
3069
3531
  files.push(fullPath);
@@ -3232,7 +3694,8 @@ function buildRequestFile(opts) {
3232
3694
  return `// \u6B64\u6587\u4EF6\u7531 @4399ywkf/plugin-react-query \u81EA\u52A8\u751F\u6210\uFF0C\u8BF7\u52FF\u624B\u52A8\u4FEE\u6539
3233
3695
  // \u5982\u9700\u5B9A\u5236\u62E6\u622A\u5668\uFF0C\u8BF7\u7F16\u8F91 src/request.ts
3234
3696
  import axios from "axios";
3235
- import type { AxiosInstance, InternalAxiosRequestConfig, AxiosResponse, AxiosError } from "axios";
3697
+ import qs from "qs";
3698
+ import type { AxiosInstance, AxiosRequestConfig, InternalAxiosRequestConfig, AxiosResponse, AxiosError } from "axios";
3236
3699
  import type { RequestConfig, Result } from "@4399ywkf/core/runtime";
3237
3700
 
3238
3701
  // ============ \u52A0\u8F7D\u7528\u6237\u914D\u7F6E ============
@@ -3246,9 +3709,38 @@ try {
3246
3709
  // src/request.ts \u4E0D\u5B58\u5728\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u914D\u7F6E
3247
3710
  }
3248
3711
 
3712
+ // ============ \u53C2\u6570\u5E8F\u5217\u5316\uFF08GET \u8BF7\u6C42\u4E13\u7528\uFF09============
3713
+
3714
+ /**
3715
+ * GET \u8BF7\u6C42\u53C2\u6570\u5E8F\u5217\u5316\u89C4\u5219\uFF1A
3716
+ * - \u6570\u7EC4\uFF1Arepeat \u6A21\u5F0F\uFF08key=1&key=2\uFF09
3717
+ * - \u5BF9\u8C61\uFF1AJSON.stringify \u540E\u4F5C\u4E3A\u5B57\u7B26\u4E32\u4F20\u9012
3718
+ * - null / undefined\uFF1AskipNulls \u8DF3\u8FC7
3719
+ * - \u57FA\u672C\u7C7B\u578B\uFF1A\u539F\u6837\u4F20\u9012
3720
+ */
3721
+ export function paramsSerializer(params: Record<string, any>): string {
3722
+ const normalized: Record<string, any> = {};
3723
+
3724
+ Object.keys(params).forEach((key) => {
3725
+ const value = params[key];
3726
+
3727
+ if (value === null || value === undefined) {
3728
+ normalized[key] = value;
3729
+ } else if (Array.isArray(value)) {
3730
+ normalized[key] = value;
3731
+ } else if (typeof value === "object") {
3732
+ normalized[key] = JSON.stringify(value);
3733
+ } else {
3734
+ normalized[key] = value;
3735
+ }
3736
+ });
3737
+
3738
+ return qs.stringify(normalized, { arrayFormat: "repeat", skipNulls: true });
3739
+ }
3740
+
3249
3741
  // ============ \u521B\u5EFA Axios \u5B9E\u4F8B ============
3250
3742
 
3251
- export const request: AxiosInstance = axios.create({
3743
+ const instance: AxiosInstance = axios.create({
3252
3744
  baseURL: userConfig.baseURL ?? ("${baseURL}" || ""),
3253
3745
  timeout: userConfig.timeout ?? ${timeout},
3254
3746
  withCredentials: userConfig.withCredentials ?? false,
@@ -3260,7 +3752,7 @@ export const request: AxiosInstance = axios.create({
3260
3752
 
3261
3753
  // ============ \u8BF7\u6C42\u62E6\u622A\u5668 ============
3262
3754
 
3263
- request.interceptors.request.use(
3755
+ instance.interceptors.request.use(
3264
3756
  (config: InternalAxiosRequestConfig) => {
3265
3757
  // 1. Token \u6CE8\u5165
3266
3758
  if (userConfig.getToken) {
@@ -3291,7 +3783,7 @@ request.interceptors.request.use(
3291
3783
 
3292
3784
  // ============ \u54CD\u5E94\u62E6\u622A\u5668 ============
3293
3785
 
3294
- request.interceptors.response.use(
3786
+ instance.interceptors.response.use(
3295
3787
  (response: AxiosResponse) => {
3296
3788
  // \u7528\u6237\u81EA\u5B9A\u4E49\u54CD\u5E94\u62E6\u622A
3297
3789
  if (userConfig.responseInterceptor) {
@@ -3330,8 +3822,45 @@ request.interceptors.response.use(
3330
3822
  }
3331
3823
  );
3332
3824
 
3825
+ // ============ \u8BF7\u6C42\u5C01\u88C5\u7C7B ============
3826
+
3827
+ type ExtraConfig = AxiosRequestConfig & { suppressErrorNotification?: boolean };
3828
+
3829
+ class Request {
3830
+ constructor(private readonly http: AxiosInstance) {}
3831
+
3832
+ get<T = any>(url: string, params?: Record<string, any>, config?: ExtraConfig): Promise<Result<T>> {
3833
+ return this.http.get(url, {
3834
+ ...config,
3835
+ params,
3836
+ paramsSerializer,
3837
+ });
3838
+ }
3839
+
3840
+ post<T = any>(url: string, data?: any, config?: ExtraConfig): Promise<Result<T>> {
3841
+ return this.http.post(url, data, config);
3842
+ }
3843
+
3844
+ put<T = any>(url: string, data?: any, config?: ExtraConfig): Promise<Result<T>> {
3845
+ return this.http.put(url, data, config);
3846
+ }
3847
+
3848
+ delete<T = any>(url: string, params?: Record<string, any>, config?: ExtraConfig): Promise<Result<T>> {
3849
+ return this.http.delete(url, {
3850
+ ...config,
3851
+ params,
3852
+ paramsSerializer,
3853
+ });
3854
+ }
3855
+
3856
+ patch<T = any>(url: string, data?: any, config?: ExtraConfig): Promise<Result<T>> {
3857
+ return this.http.patch(url, data, config);
3858
+ }
3859
+ }
3860
+
3333
3861
  // ============ \u5BFC\u51FA ============
3334
3862
 
3863
+ export const request = new Request(instance);
3335
3864
  export type { Result };
3336
3865
  export default request;
3337
3866
  `;
@@ -3339,7 +3868,7 @@ export default request;
3339
3868
 
3340
3869
  // src/plugin/builtin/zustand.ts
3341
3870
  import { existsSync as existsSync10, mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "fs";
3342
- import { join as join10 } from "path";
3871
+ import { join as join11 } from "path";
3343
3872
  var zustandPlugin = createPlugin((options = {}) => ({
3344
3873
  name: "@4399ywkf/plugin-zustand",
3345
3874
  version: "1.0.0",
@@ -3347,7 +3876,7 @@ var zustandPlugin = createPlugin((options = {}) => ({
3347
3876
  setup(context) {
3348
3877
  const { scaffold = true, storeDir = "store" } = options;
3349
3878
  const { cwd, logger } = context;
3350
- const storePath = join10(cwd, storeDir);
3879
+ const storePath = join11(cwd, storeDir);
3351
3880
  if (scaffold && !existsSync10(storePath)) {
3352
3881
  scaffoldStore(storePath, logger);
3353
3882
  }
@@ -3376,10 +3905,10 @@ var zustandPlugin = createPlugin((options = {}) => ({
3376
3905
  function scaffoldStore(storePath, logger) {
3377
3906
  const dirs = [
3378
3907
  storePath,
3379
- join10(storePath, "middleware"),
3380
- join10(storePath, "app"),
3381
- join10(storePath, "app", "slices"),
3382
- join10(storePath, "app", "slices", "counter")
3908
+ join11(storePath, "middleware"),
3909
+ join11(storePath, "app"),
3910
+ join11(storePath, "app", "slices"),
3911
+ join11(storePath, "app", "slices", "counter")
3383
3912
  ];
3384
3913
  for (const dir of dirs) {
3385
3914
  if (!existsSync10(dir)) {
@@ -3387,36 +3916,36 @@ function scaffoldStore(storePath, logger) {
3387
3916
  }
3388
3917
  }
3389
3918
  writeFileSync5(
3390
- join10(storePath, "middleware", "createDevtools.ts"),
3919
+ join11(storePath, "middleware", "createDevtools.ts"),
3391
3920
  TPL_CREATE_DEVTOOLS,
3392
3921
  "utf-8"
3393
3922
  );
3394
3923
  writeFileSync5(
3395
- join10(storePath, "app", "slices", "counter", "initialState.ts"),
3924
+ join11(storePath, "app", "slices", "counter", "initialState.ts"),
3396
3925
  TPL_COUNTER_INITIAL_STATE,
3397
3926
  "utf-8"
3398
3927
  );
3399
3928
  writeFileSync5(
3400
- join10(storePath, "app", "slices", "counter", "actions.ts"),
3929
+ join11(storePath, "app", "slices", "counter", "actions.ts"),
3401
3930
  TPL_COUNTER_ACTIONS,
3402
3931
  "utf-8"
3403
3932
  );
3404
3933
  writeFileSync5(
3405
- join10(storePath, "app", "initialState.ts"),
3934
+ join11(storePath, "app", "initialState.ts"),
3406
3935
  TPL_APP_INITIAL_STATE,
3407
3936
  "utf-8"
3408
3937
  );
3409
3938
  writeFileSync5(
3410
- join10(storePath, "app", "store.ts"),
3939
+ join11(storePath, "app", "store.ts"),
3411
3940
  TPL_APP_STORE,
3412
3941
  "utf-8"
3413
3942
  );
3414
3943
  writeFileSync5(
3415
- join10(storePath, "app", "index.tsx"),
3944
+ join11(storePath, "app", "index.tsx"),
3416
3945
  TPL_APP_INDEX,
3417
3946
  "utf-8"
3418
3947
  );
3419
- writeFileSync5(join10(storePath, "index.ts"), TPL_STORE_INDEX, "utf-8");
3948
+ writeFileSync5(join11(storePath, "index.ts"), TPL_STORE_INDEX, "utf-8");
3420
3949
  logger.info("\u5DF2\u751F\u6210 store/ \u811A\u624B\u67B6\uFF08Agent/Slice \u67B6\u6784\uFF09");
3421
3950
  }
3422
3951
  var TPL_CREATE_DEVTOOLS = `import type { DevtoolsOptions } from "zustand/middleware";
@@ -3673,7 +4202,7 @@ import chalk from "chalk";
3673
4202
  import os from "os";
3674
4203
  import { createRequire as createRequire3 } from "module";
3675
4204
  import { fileURLToPath as fileURLToPath2 } from "url";
3676
- import { dirname as dirname2, join as join11 } from "path";
4205
+ import { dirname as dirname2, join as join12 } from "path";
3677
4206
  var __filename = fileURLToPath2(import.meta.url);
3678
4207
  var __dirname2 = dirname2(__filename);
3679
4208
  var require4 = createRequire3(import.meta.url);
@@ -3681,7 +4210,7 @@ var _version = null;
3681
4210
  function getFrameworkVersion() {
3682
4211
  if (_version) return _version;
3683
4212
  try {
3684
- const pkgPath = join11(__dirname2, "../../package.json");
4213
+ const pkgPath = join12(__dirname2, "../../package.json");
3685
4214
  const pkg = require4(pkgPath);
3686
4215
  _version = pkg.version || "0.0.0";
3687
4216
  } catch {