@h-ai/cli 0.1.0-alpha.15 → 0.1.0-alpha.18
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/{chunk-LANIDJC7.js → chunk-BPO34NRL.js} +3 -3
- package/dist/chunk-BPO34NRL.js.map +1 -0
- package/dist/{chunk-YV7WPUI6.js → chunk-GSMXGUYF.js} +6 -2
- package/dist/chunk-GSMXGUYF.js.map +1 -0
- package/dist/cli-config-templates-JCS7T3NU.js +5 -0
- package/dist/cli-config-templates-JCS7T3NU.js.map +1 -0
- package/dist/cli-skill-templates-IMYZPQRG.js +5 -0
- package/dist/cli-skill-templates-IMYZPQRG.js.map +1 -0
- package/dist/index.js +391 -58
- package/dist/index.js.map +1 -1
- package/dist/{src-RZ4DPYNJ.js → src-N4NPS7AG.js} +1239 -493
- package/dist/src-N4NPS7AG.js.map +1 -0
- package/package.json +8 -7
- package/templates/README.md +10 -3
- package/templates/apps/api/tests/health.test.ts.hbs +26 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/README.md.hbs +21 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/eslint.config.js.hbs +23 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/messages/en-US.json.hbs +34 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/messages/zh-CN.json.hbs +34 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/package.json.hbs +50 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/project.inlang/settings.json.hbs +17 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/app.css.hbs +18 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/app.d.ts.hbs +9 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/app.html.hbs +14 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/routes/+layout.svelte.hbs +18 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/routes/+page.svelte.hbs +162 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/svelte.config.js.hbs +20 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/tests/api.test.ts.hbs +28 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/tsconfig.json.hbs +17 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/vite.config.ts.hbs +29 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/README.md.hbs +21 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/eslint.config.js.hbs +23 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/messages/en-US.json.hbs +34 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/messages/zh-CN.json.hbs +34 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/package.json.hbs +50 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/project.inlang/settings.json.hbs +17 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/app.css.hbs +18 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/app.d.ts.hbs +9 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/app.html.hbs +14 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/routes/+layout.svelte.hbs +18 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/routes/+page.svelte.hbs +162 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/svelte.config.js.hbs +20 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/tests/api.test.ts.hbs +28 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/tsconfig.json.hbs +17 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/vite.config.ts.hbs +29 -0
- package/templates/apps/fullstack/apps/{{projectName}}-miniapp/README.md.hbs +13 -0
- package/templates/apps/fullstack/apps/{{projectName}}-miniapp/messages/en-US.json.hbs +12 -0
- package/templates/apps/fullstack/apps/{{projectName}}-miniapp/messages/zh-CN.json.hbs +12 -0
- package/templates/apps/fullstack/apps/{{projectName}}-miniapp/project.inlang/settings.json.hbs +17 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/README.md.hbs +21 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/eslint.config.js.hbs +23 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/messages/en-US.json.hbs +34 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/messages/zh-CN.json.hbs +34 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/package.json.hbs +50 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/project.inlang/settings.json.hbs +17 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/app.css.hbs +18 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/app.d.ts.hbs +9 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/app.html.hbs +14 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/routes/+layout.svelte.hbs +18 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/routes/+page.svelte.hbs +162 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/svelte.config.js.hbs +20 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/tests/api.test.ts.hbs +28 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/tsconfig.json.hbs +17 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/vite.config.ts.hbs +29 -0
- package/templates/apps/fullstack/e2e/fullstack.spec.ts.hbs +30 -0
- package/templates/apps/fullstack/eslint.config.js +44 -0
- package/templates/apps/fullstack/package.json.hbs +42 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/README.md.hbs +15 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/package.json.hbs +27 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/app-contract.ts.hbs +21 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/app-routes.ts.hbs +27 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/app-schemas.ts.hbs +34 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/index.ts.hbs +4 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/{{projectName}}-contract.ts.hbs +9 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/tests/contract.test.ts.hbs +48 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/tsconfig.json.hbs +9 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/tsup.config.ts.hbs +9 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +14 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +29 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/index.ts.hbs +15 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/app-procedures.ts.hbs +38 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/index.ts.hbs +13 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server-app.ts.hbs +42 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/server-app.test.ts.hbs +49 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tsconfig.json.hbs +10 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tsup.config.ts.hbs +9 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/.gitignore.hbs +3 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/README.md.hbs +39 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/en-US.json.hbs +24 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/zh-CN.json.hbs +24 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/package.json.hbs +44 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/project.inlang/settings.json.hbs +11 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/index.ts.hbs +8 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/api-client.ts.hbs +49 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AppShell.svelte.hbs +60 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/LanguageSwitcher.svelte.hbs +27 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/ThemeSwitcher.svelte.hbs +18 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/theme.svelte.ts.hbs +55 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/tsconfig.json.hbs +17 -0
- package/templates/apps/fullstack/playwright.config.ts.hbs +34 -0
- package/templates/apps/fullstack/pnpm-workspace.yaml +7 -0
- package/templates/apps/fullstack/tsconfig.base.json +15 -0
- package/templates/base/e2e/app.spec.ts.hbs +7 -0
- package/templates/base/eslint.config.js +6 -0
- package/templates/base/package.json.hbs +42 -36
- package/templates/base/src/app.css.hbs +1 -0
- package/templates/base/src/lib/server/init.ts.hbs +3 -3
- package/templates/base/tests/scaffold.test.ts.hbs +27 -0
- package/templates/skills/hai-serv/SKILL.md +24 -11
- package/dist/chunk-LANIDJC7.js.map +0 -1
- package/dist/chunk-YV7WPUI6.js.map +0 -1
- package/dist/config-templates-S5RI2MC6.js +0 -5
- package/dist/config-templates-S5RI2MC6.js.map +0 -1
- package/dist/skill-templates-N5DU5FNX.js +0 -5
- package/dist/skill-templates-N5DU5FNX.js.map +0 -1
- package/dist/src-RZ4DPYNJ.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { generateConfigFile } from './chunk-
|
|
3
|
-
import './chunk-
|
|
2
|
+
import { generateConfigFile } from './chunk-BPO34NRL.js';
|
|
3
|
+
import './chunk-GSMXGUYF.js';
|
|
4
4
|
import './chunk-2H7UOFLK.js';
|
|
5
5
|
import { readFileSync, existsSync } from 'fs';
|
|
6
6
|
import path2, { resolve } from 'path';
|
|
@@ -83,6 +83,67 @@ registerHelpers();
|
|
|
83
83
|
Handlebars.registerHelper("if_eq", function(a, b, options) {
|
|
84
84
|
return a === b ? options.fn(this) : options.inverse(this);
|
|
85
85
|
});
|
|
86
|
+
var HAI_VERSION = "^0.1.0-alpha.16";
|
|
87
|
+
var TEMPLATE_SKIP_IF_EMPTY_MARKER = "@skipIfEmpty";
|
|
88
|
+
var NORMALIZED_RENDER_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".js", ".svelte", ".json", ".css"]);
|
|
89
|
+
var VERSIONS = {
|
|
90
|
+
antfuEslintConfig: "^9.0.0",
|
|
91
|
+
apiContract: HAI_VERSION,
|
|
92
|
+
apiClient: HAI_VERSION,
|
|
93
|
+
core: HAI_VERSION,
|
|
94
|
+
serv: HAI_VERSION,
|
|
95
|
+
ui: HAI_VERSION,
|
|
96
|
+
// UI / Icon
|
|
97
|
+
bitsUi: "^2.18.1",
|
|
98
|
+
iconifyJsonTabler: "^1.2.35",
|
|
99
|
+
iconifyTailwind: "^1.2.3",
|
|
100
|
+
// Tailwind / DaisyUI
|
|
101
|
+
daisyui: "^5.5.20",
|
|
102
|
+
tailwindcss: "^4.3.0",
|
|
103
|
+
tailwindcssVite: "^4.3.0",
|
|
104
|
+
// i18n
|
|
105
|
+
inlangParaglide: "^2.18.1",
|
|
106
|
+
inlangMessageFormat: "^4.4.0",
|
|
107
|
+
// Svelte / Kit
|
|
108
|
+
svelte: "^5.55.9",
|
|
109
|
+
svelteKit: "^2.61.1",
|
|
110
|
+
svelteCheck: "^4.4.8",
|
|
111
|
+
sveltePlugin: "^7.1.2",
|
|
112
|
+
adapterAuto: "^7.0.1",
|
|
113
|
+
adapterStatic: "^3.0.10",
|
|
114
|
+
// Build / Test
|
|
115
|
+
vite: "^8.0.14",
|
|
116
|
+
vitest: "^4.1.7",
|
|
117
|
+
tsup: "^8.5.1",
|
|
118
|
+
rimraf: "^6.1.3",
|
|
119
|
+
// ESLint
|
|
120
|
+
eslint: "^10.4.0",
|
|
121
|
+
eslintPluginFormat: "^2.0.1",
|
|
122
|
+
eslintPluginSvelte: "^3.17.1",
|
|
123
|
+
svelteEslintParser: "^1.6.1",
|
|
124
|
+
// Node / TS
|
|
125
|
+
nodeTypes: "^25.9.1",
|
|
126
|
+
typescript: "^6.0.3",
|
|
127
|
+
// E2E
|
|
128
|
+
playwright: "^1.60.0",
|
|
129
|
+
// Validation
|
|
130
|
+
zod: "^4.4.3"
|
|
131
|
+
};
|
|
132
|
+
var FRONTEND_PORTS_DEFAULT = {
|
|
133
|
+
web: 4173,
|
|
134
|
+
app: 4174,
|
|
135
|
+
desktop: 4175
|
|
136
|
+
};
|
|
137
|
+
var FRONTEND_LABELS = {
|
|
138
|
+
web: "Web",
|
|
139
|
+
app: "App",
|
|
140
|
+
miniapp: "Miniapp",
|
|
141
|
+
desktop: "Desktop"
|
|
142
|
+
};
|
|
143
|
+
var IMPLEMENTED_FRONTENDS = ["web", "app", "desktop"];
|
|
144
|
+
var DEFAULT_FULLSTACK_FRONTENDS = ["web", "app", "desktop"];
|
|
145
|
+
var DEFAULT_THEMES = ["light", "dark"];
|
|
146
|
+
var DEFAULT_THEME_NAME = "light";
|
|
86
147
|
var FEATURE_ROUTE_DIRS = {
|
|
87
148
|
iam: ["routes-shared"],
|
|
88
149
|
storage: ["routes"],
|
|
@@ -99,6 +160,8 @@ var FEATURE_APP_ROUTE_DIRS = {
|
|
|
99
160
|
};
|
|
100
161
|
var FEATURE_ID_REGEX = /^[a-z0-9-]+$/;
|
|
101
162
|
var HBS_SUFFIX_REGEX = /\.hbs$/;
|
|
163
|
+
var NON_IDENTIFIER_CHAR_REGEX = /[^a-z0-9]+/i;
|
|
164
|
+
var IDENTIFIER_START_REGEX = /^[a-z_$]/i;
|
|
102
165
|
function getTemplatesRoot() {
|
|
103
166
|
const currentDir = path2.dirname(fileURLToPath(import.meta.url));
|
|
104
167
|
const distPath = path2.resolve(currentDir, "..", "templates");
|
|
@@ -114,11 +177,14 @@ async function copyStaticDir(src, dest, excludePaths) {
|
|
|
114
177
|
await fse.copy(src, dest, {
|
|
115
178
|
overwrite: true,
|
|
116
179
|
filter: (filePath) => {
|
|
180
|
+
const rel = path2.relative(src, filePath);
|
|
181
|
+
if (rel.includes("{{") || rel.includes("}}")) {
|
|
182
|
+
return false;
|
|
183
|
+
}
|
|
117
184
|
if (filePath.endsWith(".hbs")) {
|
|
118
185
|
return false;
|
|
119
186
|
}
|
|
120
187
|
if (excludePaths && excludePaths.length > 0) {
|
|
121
|
-
const rel = path2.relative(src, filePath);
|
|
122
188
|
return !excludePaths.some((p) => rel === p || rel.startsWith(`${p}${path2.sep}`));
|
|
123
189
|
}
|
|
124
190
|
return true;
|
|
@@ -158,21 +224,99 @@ function buildTemplateContext(options) {
|
|
|
158
224
|
featureMap.db = true;
|
|
159
225
|
}
|
|
160
226
|
const isApi = options.appType === "api";
|
|
227
|
+
const isFullstack = options.appType === "fullstack";
|
|
161
228
|
const isCapacitorApp = options.appType === "android-app";
|
|
162
229
|
return {
|
|
163
230
|
projectName: options.name,
|
|
164
231
|
appType: options.appType,
|
|
165
232
|
features: featureMap,
|
|
166
|
-
hasUi: !isApi,
|
|
167
|
-
hasI18n: !isApi,
|
|
233
|
+
hasUi: !isApi && !isFullstack,
|
|
234
|
+
hasI18n: !isApi && !isFullstack,
|
|
168
235
|
isCapacitorApp,
|
|
169
236
|
defaultLocale: options.moduleConfigs?.core?.defaultLocale ?? "zh-CN",
|
|
170
|
-
packageManager: options.packageManager
|
|
237
|
+
packageManager: options.packageManager,
|
|
238
|
+
fullstack: isFullstack ? buildFullstackTemplateContext(
|
|
239
|
+
options.name,
|
|
240
|
+
options.frontends ?? DEFAULT_FULLSTACK_FRONTENDS,
|
|
241
|
+
options.moduleConfigs
|
|
242
|
+
) : void 0
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
function buildFullstackTemplateContext(projectName, frontendsInput, moduleConfigs) {
|
|
246
|
+
const selectedFrontends = [...new Set(frontendsInput.length > 0 ? frontendsInput : DEFAULT_FULLSTACK_FRONTENDS)];
|
|
247
|
+
const portsConfig = moduleConfigs?.fullstack?.ports ?? {};
|
|
248
|
+
const portFor = (target) => portsConfig[target] ?? FRONTEND_PORTS_DEFAULT[target];
|
|
249
|
+
const frontendApps = selectedFrontends.filter(isImplementedFrontend).map((target) => ({
|
|
250
|
+
target,
|
|
251
|
+
packageName: `${projectName}-${target}`,
|
|
252
|
+
label: FRONTEND_LABELS[target],
|
|
253
|
+
port: portFor(target)
|
|
254
|
+
}));
|
|
255
|
+
return {
|
|
256
|
+
versions: VERSIONS,
|
|
257
|
+
contractPackageName: `${projectName}-contract`,
|
|
258
|
+
contractExportName: `${toIdentifier(projectName)}Contract`,
|
|
259
|
+
servPackageName: `${projectName}-serv`,
|
|
260
|
+
sharedPackageName: `${projectName}-shared`,
|
|
261
|
+
selectedFrontends,
|
|
262
|
+
selectedFrontendsJson: `[${selectedFrontends.map((f) => `'${f}'`).join(", ")}]`,
|
|
263
|
+
frontendApps,
|
|
264
|
+
e2eFrontend: frontendApps[0],
|
|
265
|
+
frontends: {
|
|
266
|
+
web: selectedFrontends.includes("web"),
|
|
267
|
+
app: selectedFrontends.includes("app"),
|
|
268
|
+
miniapp: selectedFrontends.includes("miniapp"),
|
|
269
|
+
desktop: selectedFrontends.includes("desktop")
|
|
270
|
+
},
|
|
271
|
+
ports: {
|
|
272
|
+
web: portFor("web"),
|
|
273
|
+
app: portFor("app"),
|
|
274
|
+
desktop: portFor("desktop")
|
|
275
|
+
},
|
|
276
|
+
hasMiniapp: selectedFrontends.includes("miniapp"),
|
|
277
|
+
i18n: resolveI18nContext(moduleConfigs),
|
|
278
|
+
theme: resolveThemeContext(moduleConfigs)
|
|
171
279
|
};
|
|
172
280
|
}
|
|
281
|
+
function resolveI18nContext(moduleConfigs) {
|
|
282
|
+
const coreLocale = moduleConfigs?.core?.defaultLocale ?? "zh-CN";
|
|
283
|
+
const baseLocale = moduleConfigs?.fullstack?.i18n?.baseLocale ?? coreLocale;
|
|
284
|
+
const fallbackLocale = baseLocale === "en-US" ? "zh-CN" : "en-US";
|
|
285
|
+
const requested = moduleConfigs?.fullstack?.i18n?.locales;
|
|
286
|
+
const locales = requested && requested.length > 0 ? [...new Set(requested)] : [baseLocale, fallbackLocale];
|
|
287
|
+
if (!locales.includes(baseLocale)) {
|
|
288
|
+
locales.unshift(baseLocale);
|
|
289
|
+
}
|
|
290
|
+
return { baseLocale, locales };
|
|
291
|
+
}
|
|
292
|
+
function resolveThemeContext(moduleConfigs) {
|
|
293
|
+
const defaultTheme = moduleConfigs?.fullstack?.theme?.defaultTheme ?? DEFAULT_THEME_NAME;
|
|
294
|
+
const requested = moduleConfigs?.fullstack?.theme?.themes;
|
|
295
|
+
const themes = requested && requested.length > 0 ? [...new Set(requested)] : [...DEFAULT_THEMES];
|
|
296
|
+
if (!themes.includes(defaultTheme)) {
|
|
297
|
+
themes.unshift(defaultTheme);
|
|
298
|
+
}
|
|
299
|
+
return { defaultTheme, themes };
|
|
300
|
+
}
|
|
301
|
+
function isImplementedFrontend(target) {
|
|
302
|
+
return IMPLEMENTED_FRONTENDS.includes(target);
|
|
303
|
+
}
|
|
304
|
+
function toIdentifier(value) {
|
|
305
|
+
const words = value.split(NON_IDENTIFIER_CHAR_REGEX).filter(Boolean);
|
|
306
|
+
const camel = words.map((word, index) => {
|
|
307
|
+
const normalized = word.toLowerCase();
|
|
308
|
+
return index === 0 ? normalized : `${normalized.charAt(0).toUpperCase()}${normalized.slice(1)}`;
|
|
309
|
+
}).join("");
|
|
310
|
+
if (!camel)
|
|
311
|
+
return "app";
|
|
312
|
+
return IDENTIFIER_START_REGEX.test(camel) ? camel : `app${camel}`;
|
|
313
|
+
}
|
|
173
314
|
async function generateFromTemplates(projectPath, context) {
|
|
174
315
|
const root = getTemplatesRoot();
|
|
175
|
-
|
|
316
|
+
const includeBaseTemplate = context.appType !== "fullstack";
|
|
317
|
+
if (includeBaseTemplate) {
|
|
318
|
+
await copyStaticDir(path2.join(root, "base"), projectPath);
|
|
319
|
+
}
|
|
176
320
|
const appDir = path2.join(root, "apps", context.appType);
|
|
177
321
|
if (await fse.pathExists(appDir)) {
|
|
178
322
|
const appExcludes = context.hasI18n ? [] : ["messages"];
|
|
@@ -211,10 +355,12 @@ async function generateFromTemplates(projectPath, context) {
|
|
|
211
355
|
await fse.copy(i18nDir, projectPath, { overwrite: true });
|
|
212
356
|
}
|
|
213
357
|
}
|
|
214
|
-
|
|
358
|
+
if (includeBaseTemplate) {
|
|
359
|
+
await fse.ensureDir(path2.join(projectPath, "static"));
|
|
360
|
+
}
|
|
215
361
|
}
|
|
216
362
|
async function renderDynamicFiles(templatesRoot, projectPath, context) {
|
|
217
|
-
const rootDirs = [
|
|
363
|
+
const rootDirs = context.appType === "fullstack" ? [path2.join(templatesRoot, "apps", context.appType)] : [
|
|
218
364
|
path2.join(templatesRoot, "base"),
|
|
219
365
|
path2.join(templatesRoot, "apps", context.appType)
|
|
220
366
|
];
|
|
@@ -248,17 +394,46 @@ async function renderHbsInDir(dir, destRoot, context) {
|
|
|
248
394
|
const hbsFiles = await findHbsFiles(dir);
|
|
249
395
|
for (const relPath of hbsFiles) {
|
|
250
396
|
const srcPath = path2.join(dir, relPath);
|
|
251
|
-
const
|
|
252
|
-
const destPath = path2.join(destRoot, outRelPath);
|
|
397
|
+
const outRelPathTemplate = relPath.replace(HBS_SUFFIX_REGEX, "");
|
|
253
398
|
const template = await fse.readFile(srcPath, "utf-8");
|
|
254
399
|
const compiled = Handlebars.compile(template, { noEscape: true });
|
|
255
400
|
const rendered = compiled(context);
|
|
401
|
+
if (shouldSkipRenderedFile(template, rendered)) {
|
|
402
|
+
continue;
|
|
403
|
+
}
|
|
404
|
+
const outRelPath = renderOutputPath(outRelPathTemplate, context);
|
|
405
|
+
if (!isSafeRelativePath(outRelPath)) {
|
|
406
|
+
continue;
|
|
407
|
+
}
|
|
408
|
+
const destPath = path2.join(destRoot, outRelPath);
|
|
409
|
+
const normalizedRendered = normalizeRenderedContent(rendered, outRelPath);
|
|
256
410
|
await fse.ensureDir(path2.dirname(destPath));
|
|
257
|
-
await fse.writeFile(destPath,
|
|
411
|
+
await fse.writeFile(destPath, normalizedRendered, "utf-8");
|
|
258
412
|
}
|
|
259
413
|
}
|
|
414
|
+
function normalizeRenderedContent(content, outRelPath) {
|
|
415
|
+
const normalizedLineEndings = content.replace(/\r\n/g, "\n");
|
|
416
|
+
const ext = path2.extname(outRelPath);
|
|
417
|
+
const normalized = NORMALIZED_RENDER_EXTENSIONS.has(ext) ? normalizedLineEndings.replace(/\n{3,}/g, "\n\n") : normalizedLineEndings;
|
|
418
|
+
if (normalized.trim().length === 0) {
|
|
419
|
+
return "";
|
|
420
|
+
}
|
|
421
|
+
return normalized.endsWith("\n") ? normalized : `${normalized}
|
|
422
|
+
`;
|
|
423
|
+
}
|
|
424
|
+
function shouldSkipRenderedFile(template, rendered) {
|
|
425
|
+
return template.includes(TEMPLATE_SKIP_IF_EMPTY_MARKER) && rendered.trim().length === 0;
|
|
426
|
+
}
|
|
427
|
+
function renderOutputPath(pathTemplate, context) {
|
|
428
|
+
const normalizedTemplate = pathTemplate.split(path2.sep).join("/");
|
|
429
|
+
return Handlebars.compile(normalizedTemplate, { noEscape: true })(context);
|
|
430
|
+
}
|
|
431
|
+
function isSafeRelativePath(relativePath) {
|
|
432
|
+
const normalized = path2.normalize(relativePath);
|
|
433
|
+
return !path2.isAbsolute(normalized) && normalized !== ".." && !normalized.startsWith(`..${path2.sep}`);
|
|
434
|
+
}
|
|
260
435
|
|
|
261
|
-
// src/commands/create.ts
|
|
436
|
+
// src/commands/cli-create.ts
|
|
262
437
|
var RE_HTTPS_URL = /^https:\/\/.+/;
|
|
263
438
|
var RE_GIT_SSH_URL = /^git@.+:.+/;
|
|
264
439
|
var APP_TYPES = {
|
|
@@ -286,8 +461,20 @@ var APP_TYPES = {
|
|
|
286
461
|
name: "Android \u5E94\u7528",
|
|
287
462
|
description: "Android \u539F\u751F\u5E94\u7528\uFF08Capacitor + SvelteKit SPA\uFF09\uFF0C\u53EF\u6253\u5305\u4E3A APK",
|
|
288
463
|
defaultFeatures: ["iam", "db", "cache", "crypto", "api-client", "capacitor"]
|
|
464
|
+
},
|
|
465
|
+
"fullstack": {
|
|
466
|
+
name: "\u524D\u540E\u7AEF\u5206\u79BB\u5DE5\u7A0B",
|
|
467
|
+
description: "\u591A\u5305\u5DE5\u4F5C\u533A\uFF0C\u5305\u542B contract\u3001serv\u3001Web/App/Desktop \u524D\u7AEF",
|
|
468
|
+
defaultFeatures: []
|
|
289
469
|
}
|
|
290
470
|
};
|
|
471
|
+
var FRONTEND_TARGETS = {
|
|
472
|
+
web: { name: "Web", description: "\u6D4F\u89C8\u5668 Web \u5E94\u7528", implemented: true },
|
|
473
|
+
app: { name: "App", description: "\u79FB\u52A8\u7AEF H5/App \u524D\u7AEF", implemented: true },
|
|
474
|
+
miniapp: { name: "\u5C0F\u7A0B\u5E8F", description: "\u9884\u7559\u76EE\u6807\uFF0C\u5F53\u524D\u53EA\u751F\u6210\u8BF4\u660E\u5360\u4F4D", implemented: false },
|
|
475
|
+
desktop: { name: "\u684C\u9762\u7AEF", description: "\u684C\u9762\u7AEF\u524D\u7AEF\u5DE5\u7A0B\uFF08Tauri \u9884\u7559\uFF09", implemented: true }
|
|
476
|
+
};
|
|
477
|
+
var DEFAULT_FULLSTACK_FRONTENDS2 = ["web", "app", "desktop"];
|
|
291
478
|
var FEATURES = {
|
|
292
479
|
"iam": {
|
|
293
480
|
id: "iam",
|
|
@@ -470,34 +657,38 @@ async function createProject(options) {
|
|
|
470
657
|
name: resolvedOptions.name,
|
|
471
658
|
appType: resolvedOptions.appType,
|
|
472
659
|
features: resolvedOptions.features,
|
|
660
|
+
frontends: resolvedOptions.frontends,
|
|
473
661
|
moduleConfigs: resolvedOptions.moduleConfigs,
|
|
474
662
|
packageManager: resolvedOptions.packageManager
|
|
475
663
|
});
|
|
476
664
|
await generateFromTemplates(projectPath, context);
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
const
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
665
|
+
if (resolvedOptions.appType !== "fullstack") {
|
|
666
|
+
const { generateConfigFile: generateConfigFile2 } = await import('./cli-config-templates-JCS7T3NU.js');
|
|
667
|
+
const configs = resolvedOptions.moduleConfigs;
|
|
668
|
+
for (const featureId of resolvedOptions.features) {
|
|
669
|
+
const configKey = getFeatureConfigKey(featureId);
|
|
670
|
+
if (configKey) {
|
|
671
|
+
const content = generateConfigFile2(configKey, configs);
|
|
672
|
+
await writeFile(path2.join(projectPath, "config", `_${configKey}.yml`), content);
|
|
673
|
+
}
|
|
484
674
|
}
|
|
675
|
+
await writeFile(
|
|
676
|
+
path2.join(projectPath, "config", "_core.yml"),
|
|
677
|
+
generateConfigFile2("core", configs)
|
|
678
|
+
);
|
|
679
|
+
const { generateEnvExample } = await import('./cli-config-templates-JCS7T3NU.js');
|
|
680
|
+
await writeFile(
|
|
681
|
+
path2.join(projectPath, ".env.example"),
|
|
682
|
+
generateEnvExample(resolvedOptions.features, configs)
|
|
683
|
+
);
|
|
485
684
|
}
|
|
486
|
-
await
|
|
487
|
-
path2.join(projectPath, "config", "_core.yml"),
|
|
488
|
-
generateConfigFile2("core", configs)
|
|
489
|
-
);
|
|
490
|
-
const { generateEnvExample } = await import('./config-templates-S5RI2MC6.js');
|
|
491
|
-
await writeFile(
|
|
492
|
-
path2.join(projectPath, ".env.example"),
|
|
493
|
-
generateEnvExample(resolvedOptions.features, configs)
|
|
494
|
-
);
|
|
495
|
-
const { generateSkillFiles } = await import('./skill-templates-N5DU5FNX.js');
|
|
685
|
+
const { generateSkillFiles } = await import('./cli-skill-templates-IMYZPQRG.js');
|
|
496
686
|
await generateSkillFiles(projectPath, resolvedOptions.features, resolvedOptions.appType);
|
|
497
687
|
const appTypeLabel = APP_TYPES[resolvedOptions.appType].name;
|
|
688
|
+
const readmeContent = resolvedOptions.appType === "fullstack" ? generateFullstackReadme(resolvedOptions.name, resolvedOptions.packageManager, resolvedOptions.frontends) : generateReadme(resolvedOptions.name, appTypeLabel, resolvedOptions.packageManager);
|
|
498
689
|
await writeFile(
|
|
499
690
|
path2.join(projectPath, "README.md"),
|
|
500
|
-
|
|
691
|
+
readmeContent
|
|
501
692
|
);
|
|
502
693
|
spinner.succeed();
|
|
503
694
|
if (resolvedOptions.git) {
|
|
@@ -527,6 +718,7 @@ async function createProject(options) {
|
|
|
527
718
|
}
|
|
528
719
|
}
|
|
529
720
|
async function resolveOptions(options) {
|
|
721
|
+
const useDefaults = options.yes ?? false;
|
|
530
722
|
core.logger.info("", {});
|
|
531
723
|
core.logger.info(chalk.bold.cyan(" \u{1F680} hai Agent Framework"));
|
|
532
724
|
core.logger.info(chalk.gray(" AI-Native \xB7 Configuration-Driven \xB7 Security-First"));
|
|
@@ -536,7 +728,9 @@ async function resolveOptions(options) {
|
|
|
536
728
|
process3.exit(1);
|
|
537
729
|
};
|
|
538
730
|
let projectName = options.name;
|
|
539
|
-
if (!projectName) {
|
|
731
|
+
if (!projectName && useDefaults) {
|
|
732
|
+
projectName = "my-app";
|
|
733
|
+
} else if (!projectName) {
|
|
540
734
|
const { name } = await prompts({
|
|
541
735
|
type: "text",
|
|
542
736
|
name: "name",
|
|
@@ -553,7 +747,9 @@ async function resolveOptions(options) {
|
|
|
553
747
|
projectName = name;
|
|
554
748
|
}
|
|
555
749
|
let resolvedAppType = options.appType;
|
|
556
|
-
if (!resolvedAppType) {
|
|
750
|
+
if (!resolvedAppType && useDefaults) {
|
|
751
|
+
resolvedAppType = "admin";
|
|
752
|
+
} else if (!resolvedAppType) {
|
|
557
753
|
const { appType } = await prompts({
|
|
558
754
|
type: "select",
|
|
559
755
|
name: "appType",
|
|
@@ -567,23 +763,34 @@ async function resolveOptions(options) {
|
|
|
567
763
|
resolvedAppType = appType;
|
|
568
764
|
}
|
|
569
765
|
const selectedAppType = resolvedAppType || "admin";
|
|
766
|
+
const selectedFrontends = selectedAppType === "fullstack" ? await resolveFrontendTargets(options.frontends, useDefaults, onCancel) : [];
|
|
570
767
|
let selectedTemplate = options.template;
|
|
571
|
-
if (
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
768
|
+
if (selectedAppType === "fullstack") {
|
|
769
|
+
selectedTemplate = selectedTemplate ?? "custom";
|
|
770
|
+
} else if (!selectedTemplate) {
|
|
771
|
+
if (useDefaults) {
|
|
772
|
+
selectedTemplate = "default";
|
|
773
|
+
} else {
|
|
774
|
+
const { template } = await prompts({
|
|
775
|
+
type: "select",
|
|
776
|
+
name: "template",
|
|
777
|
+
message: "\u9009\u62E9\u6A21\u677F:",
|
|
778
|
+
choices: Object.values(PROJECT_TEMPLATES).map((t) => ({
|
|
779
|
+
title: `${chalk.bold(t.name.padEnd(10))} ${chalk.gray(t.description)}`,
|
|
780
|
+
value: t.name
|
|
781
|
+
})),
|
|
782
|
+
initial: 1
|
|
783
|
+
}, { onCancel });
|
|
784
|
+
selectedTemplate = template;
|
|
785
|
+
}
|
|
583
786
|
}
|
|
584
787
|
let selectedFeatures = [];
|
|
585
788
|
const appTypeDefaults = APP_TYPES[selectedAppType].defaultFeatures;
|
|
586
|
-
if (
|
|
789
|
+
if (selectedAppType === "fullstack") {
|
|
790
|
+
selectedFeatures = [];
|
|
791
|
+
} else if (selectedTemplate === "custom" && !options.features && useDefaults) {
|
|
792
|
+
selectedFeatures = resolveFeatureDependencies(appTypeDefaults);
|
|
793
|
+
} else if (selectedTemplate === "custom" && !options.features) {
|
|
587
794
|
const featureChoices = SELECTABLE_FEATURES.map((id) => ({
|
|
588
795
|
title: `${chalk.bold(FEATURES[id].name.padEnd(10))} ${chalk.gray(FEATURES[id].description)}`,
|
|
589
796
|
value: id,
|
|
@@ -606,9 +813,11 @@ async function resolveOptions(options) {
|
|
|
606
813
|
const merged = /* @__PURE__ */ new Set([...templateFeatures, ...appTypeDefaults]);
|
|
607
814
|
selectedFeatures = resolveFeatureDependencies(Array.from(merged));
|
|
608
815
|
}
|
|
609
|
-
const moduleConfigs = options.moduleConfigs ?? await promptModuleConfigs(selectedFeatures, projectName);
|
|
816
|
+
const moduleConfigs = selectedAppType === "fullstack" ? options.moduleConfigs ?? {} : options.moduleConfigs ?? (useDefaults ? buildDefaultModuleConfigs(selectedFeatures, projectName) : await promptModuleConfigs(selectedFeatures, projectName));
|
|
610
817
|
let addExamples = options.examples;
|
|
611
|
-
if (addExamples === void 0) {
|
|
818
|
+
if (addExamples === void 0 && useDefaults) {
|
|
819
|
+
addExamples = true;
|
|
820
|
+
} else if (addExamples === void 0) {
|
|
612
821
|
const { examples } = await prompts({
|
|
613
822
|
type: "confirm",
|
|
614
823
|
name: "examples",
|
|
@@ -618,7 +827,10 @@ async function resolveOptions(options) {
|
|
|
618
827
|
addExamples = examples;
|
|
619
828
|
}
|
|
620
829
|
const detected = await detectPackageManager(options.cwd ?? ".");
|
|
621
|
-
let packageManager = options.packageManager;
|
|
830
|
+
let packageManager = selectedAppType === "fullstack" ? "pnpm" : options.packageManager;
|
|
831
|
+
if (!packageManager && useDefaults) {
|
|
832
|
+
packageManager = detected;
|
|
833
|
+
}
|
|
622
834
|
if (!packageManager) {
|
|
623
835
|
const { pm } = await prompts({
|
|
624
836
|
type: "select",
|
|
@@ -634,7 +846,9 @@ async function resolveOptions(options) {
|
|
|
634
846
|
packageManager = pm;
|
|
635
847
|
}
|
|
636
848
|
let install = options.install;
|
|
637
|
-
if (install === void 0) {
|
|
849
|
+
if (install === void 0 && useDefaults) {
|
|
850
|
+
install = true;
|
|
851
|
+
} else if (install === void 0) {
|
|
638
852
|
const { doInstall } = await prompts({
|
|
639
853
|
type: "confirm",
|
|
640
854
|
name: "doInstall",
|
|
@@ -644,7 +858,9 @@ async function resolveOptions(options) {
|
|
|
644
858
|
install = doInstall;
|
|
645
859
|
}
|
|
646
860
|
let git = options.git;
|
|
647
|
-
if (git === void 0) {
|
|
861
|
+
if (git === void 0 && useDefaults) {
|
|
862
|
+
git = true;
|
|
863
|
+
} else if (git === void 0) {
|
|
648
864
|
const { initGit } = await prompts({
|
|
649
865
|
type: "confirm",
|
|
650
866
|
name: "initGit",
|
|
@@ -654,7 +870,9 @@ async function resolveOptions(options) {
|
|
|
654
870
|
git = initGit;
|
|
655
871
|
}
|
|
656
872
|
let gitRemote = options.gitRemote;
|
|
657
|
-
if (git && gitRemote === void 0) {
|
|
873
|
+
if (git && gitRemote === void 0 && useDefaults) {
|
|
874
|
+
gitRemote = "";
|
|
875
|
+
} else if (git && gitRemote === void 0) {
|
|
658
876
|
const { remote } = await prompts({
|
|
659
877
|
type: "text",
|
|
660
878
|
name: "remote",
|
|
@@ -673,6 +891,7 @@ async function resolveOptions(options) {
|
|
|
673
891
|
return {
|
|
674
892
|
name: projectName,
|
|
675
893
|
appType: selectedAppType,
|
|
894
|
+
frontends: selectedFrontends,
|
|
676
895
|
template: selectedTemplate ?? "default",
|
|
677
896
|
features: selectedFeatures,
|
|
678
897
|
moduleConfigs,
|
|
@@ -681,10 +900,58 @@ async function resolveOptions(options) {
|
|
|
681
900
|
packageManager: packageManager || "pnpm",
|
|
682
901
|
git: git ?? true,
|
|
683
902
|
gitRemote: gitRemote ?? "",
|
|
903
|
+
yes: useDefaults,
|
|
684
904
|
verbose: options.verbose ?? false,
|
|
685
905
|
cwd: options.cwd ?? "."
|
|
686
906
|
};
|
|
687
907
|
}
|
|
908
|
+
function buildDefaultModuleConfigs(features, projectName) {
|
|
909
|
+
const configs = {
|
|
910
|
+
core: { name: projectName, defaultLocale: "zh-CN" }
|
|
911
|
+
};
|
|
912
|
+
if (features.includes("db")) {
|
|
913
|
+
configs.db = { type: "sqlite", database: "./data/app.db" };
|
|
914
|
+
}
|
|
915
|
+
if (features.includes("cache")) {
|
|
916
|
+
configs.cache = { type: "memory" };
|
|
917
|
+
}
|
|
918
|
+
if (features.includes("iam")) {
|
|
919
|
+
configs.iam = { loginPassword: true, loginOtp: false };
|
|
920
|
+
}
|
|
921
|
+
if (features.includes("storage")) {
|
|
922
|
+
configs.storage = { type: "local", localPath: "./data/uploads" };
|
|
923
|
+
}
|
|
924
|
+
if (features.includes("ai")) {
|
|
925
|
+
configs.ai = { defaultProvider: "openai", model: "gpt-4o-mini" };
|
|
926
|
+
}
|
|
927
|
+
return configs;
|
|
928
|
+
}
|
|
929
|
+
async function resolveFrontendTargets(frontends, useDefaults, onCancel) {
|
|
930
|
+
if (frontends && frontends.length > 0) {
|
|
931
|
+
return normalizeFrontendTargets(frontends);
|
|
932
|
+
}
|
|
933
|
+
if (useDefaults) {
|
|
934
|
+
return DEFAULT_FULLSTACK_FRONTENDS2;
|
|
935
|
+
}
|
|
936
|
+
const { selectedFrontends } = await prompts({
|
|
937
|
+
type: "multiselect",
|
|
938
|
+
name: "selectedFrontends",
|
|
939
|
+
message: "\u9009\u62E9\u524D\u7AEF\u76EE\u6807 (\u7A7A\u683C\u9009\u62E9\uFF0C\u56DE\u8F66\u786E\u8BA4):",
|
|
940
|
+
choices: Object.entries(FRONTEND_TARGETS).map(([id, target]) => ({
|
|
941
|
+
title: `${chalk.bold(target.name.padEnd(8))} ${chalk.gray(target.description)}`,
|
|
942
|
+
value: id,
|
|
943
|
+
selected: DEFAULT_FULLSTACK_FRONTENDS2.includes(id)
|
|
944
|
+
})),
|
|
945
|
+
hint: "- \u5C0F\u7A0B\u5E8F\u5F53\u524D\u4E3A\u9884\u7559\u5360\u4F4D\uFF0C\u4E0D\u751F\u6210\u53EF\u8FD0\u884C\u5DE5\u7A0B",
|
|
946
|
+
instructions: false
|
|
947
|
+
}, { onCancel });
|
|
948
|
+
return normalizeFrontendTargets(selectedFrontends ?? DEFAULT_FULLSTACK_FRONTENDS2);
|
|
949
|
+
}
|
|
950
|
+
function normalizeFrontendTargets(frontends) {
|
|
951
|
+
const validTargets = new Set(Object.keys(FRONTEND_TARGETS));
|
|
952
|
+
const result = frontends.filter((target) => validTargets.has(target));
|
|
953
|
+
return [...new Set(result.length > 0 ? result : DEFAULT_FULLSTACK_FRONTENDS2)];
|
|
954
|
+
}
|
|
688
955
|
function resolveFeatureDependencies(features) {
|
|
689
956
|
const result = new Set(features);
|
|
690
957
|
let changed = true;
|
|
@@ -890,6 +1157,7 @@ ${pm} dev
|
|
|
890
1157
|
|
|
891
1158
|
\`\`\`bash
|
|
892
1159
|
${pm} build
|
|
1160
|
+
${pm} i18n:compile
|
|
893
1161
|
${pm} preview
|
|
894
1162
|
\`\`\`
|
|
895
1163
|
|
|
@@ -900,6 +1168,62 @@ ${pm} preview
|
|
|
900
1168
|
- [Svelte 5](https://svelte.dev/)
|
|
901
1169
|
`;
|
|
902
1170
|
}
|
|
1171
|
+
function generateFullstackReadme(name, pm, frontends) {
|
|
1172
|
+
const enabledFrontends = frontends.map((target) => FRONTEND_TARGETS[target].name).join(" / ");
|
|
1173
|
+
return `# ${name}
|
|
1174
|
+
|
|
1175
|
+
\u57FA\u4E8E hai Agent Framework \u6784\u5EFA\u7684\u524D\u540E\u7AEF\u5206\u79BB\u591A\u5305\u5DE5\u7A0B\u3002
|
|
1176
|
+
|
|
1177
|
+
## \u5DE5\u7A0B\u7ED3\u6784
|
|
1178
|
+
|
|
1179
|
+
- \`packages/${name}-contract\`\uFF1A\u524D\u540E\u7AEF\u5171\u4EAB API \u5951\u7EA6\u3001Zod Schema \u4E0E\u7C7B\u578B
|
|
1180
|
+
- \`packages/${name}-serv\`\uFF1A\u540E\u7AEF API Service\uFF08\u901A\u8FC7 \`@h-ai/serv\` \u66B4\u9732\u6700\u5C0F HTTP App \u62BD\u8C61\uFF0C\u4E0D\u76F4\u63A5\u66B4\u9732 Hono\uFF09
|
|
1181
|
+
- \`packages/${name}-shared\`\uFF1A\u8DE8\u7AEF\u5171\u4EAB Shell\u3001\u4E3B\u9898\u3001\u8BED\u8A00\u5207\u6362\u3001API client \u4E0E\u5171\u4EAB messages
|
|
1182
|
+
- \`apps/${name}-web\`\uFF1AWeb \u524D\u7AEF${frontends.includes("web") ? "" : "\uFF08\u672A\u542F\u7528\uFF09"}
|
|
1183
|
+
- \`apps/${name}-app\`\uFF1A\u79FB\u52A8\u7AEF App/H5 \u524D\u7AEF${frontends.includes("app") ? "" : "\uFF08\u672A\u542F\u7528\uFF09"}
|
|
1184
|
+
- \`apps/${name}-desktop\`\uFF1A\u684C\u9762\u7AEF\u524D\u7AEF${frontends.includes("desktop") ? "" : "\uFF08\u672A\u542F\u7528\uFF09"}
|
|
1185
|
+
- \`apps/${name}-miniapp\`\uFF1A\u5C0F\u7A0B\u5E8F\u9884\u7559\u8BF4\u660E\u4E0E\u672C\u7AEF inlang messages${frontends.includes("miniapp") ? "\uFF08\u5360\u4F4D\uFF0C\u4E0D\u53C2\u4E0E\u6784\u5EFA\uFF09" : "\uFF08\u672A\u542F\u7528\uFF09"}
|
|
1186
|
+
|
|
1187
|
+
\u5DF2\u542F\u7528\u524D\u7AEF\uFF1A${enabledFrontends || "Web / App / Desktop"}
|
|
1188
|
+
|
|
1189
|
+
## \u5F00\u53D1
|
|
1190
|
+
|
|
1191
|
+
\`\`\`bash
|
|
1192
|
+
${pm} install
|
|
1193
|
+
${pm} dev
|
|
1194
|
+
\`\`\`
|
|
1195
|
+
|
|
1196
|
+
## i18n \u4E0E shared \u534F\u540C
|
|
1197
|
+
|
|
1198
|
+
- shared\uFF1A\`packages/${name}-shared/project.inlang\` + \`messages/\`\uFF0C\u53EA\u653E\u8DE8\u7AEF\u5171\u4EAB\u7EC4\u4EF6\u6587\u6848\u3002
|
|
1199
|
+
- web/app/desktop\uFF1A\u6BCF\u4E2A\u5E94\u7528\u90FD\u6709\u81EA\u5DF1\u7684 \`project.inlang\` + \`messages/\`\uFF0C\u7528\u4E8E\u672C\u7AEF\u9875\u9762\u4E0E\u4EA7\u54C1\u6587\u6848\u3002
|
|
1200
|
+
- miniapp\uFF1A\u5F53\u524D\u662F\u5360\u4F4D\uFF0C\u4F46\u4E5F\u6709\u81EA\u5DF1\u7684 \`project.inlang\` + \`messages/\`\uFF0C\u4FBF\u4E8E\u540E\u7EED\u63A5\u5165\u771F\u5B9E\u5C0F\u7A0B\u5E8F\u6846\u67B6\u3002
|
|
1201
|
+
- \u65B0\u589E locale \u65F6\uFF0Cshared \u4E0E\u6240\u6709\u542F\u7528\u524D\u7AEF\u7684 \`locales\` \u5FC5\u987B\u540C\u6B65\uFF1B\u8BED\u8A00\u5207\u6362\u5668\u4F1A\u540C\u65F6\u66F4\u65B0 shared runtime \u4E0E\u5BBF\u4E3B\u5E94\u7528 runtime\u3002
|
|
1202
|
+
- \`${pm} i18n:compile\` \u4F1A\u7EDF\u4E00\u7F16\u8BD1 shared \u4E0E\u6BCF\u4E2A\u542F\u7528\u524D\u7AEF\u7684 Paraglide \u8F93\u51FA\uFF1B\u5404\u524D\u7AEF\u4E5F\u53EF\u5355\u72EC\u8FD0\u884C \`${pm} --filter ${name}-web paraglide:compile\` \u7B49\u547D\u4EE4\u3002
|
|
1203
|
+
|
|
1204
|
+
## \u81EA\u5B9A\u4E49\u5EFA\u8BAE
|
|
1205
|
+
|
|
1206
|
+
- \u6539\u5168\u5C40 Shell/\u4E3B\u9898/\u8BED\u8A00\u5207\u6362\uFF1A\u7F16\u8F91 \`packages/${name}-shared\`\u3002
|
|
1207
|
+
- \u6539\u67D0\u4E2A\u524D\u7AEF\u9875\u9762\u548C\u6587\u6848\uFF1A\u7F16\u8F91\u5BF9\u5E94 \`apps/${name}-*/src/routes\` \u4E0E \`apps/${name}-*/messages\`\u3002
|
|
1208
|
+
- \u6539\u4E3B\u9898\u5217\u8868\uFF1A\u8C03\u6574\u811A\u624B\u67B6\u914D\u7F6E\u4E2D\u7684 \`fullstack.theme.themes\`\uFF0C\u6216\u76F4\u63A5\u7F16\u8F91\u5404\u7AEF \`src/app.css\` \u7684 daisyUI \`themes\`\u3002
|
|
1209
|
+
|
|
1210
|
+
## \u8D28\u91CF\u95E8\u7981
|
|
1211
|
+
|
|
1212
|
+
\`\`\`bash
|
|
1213
|
+
${pm} typecheck
|
|
1214
|
+
${pm} lint
|
|
1215
|
+
${pm} test
|
|
1216
|
+
${pm} test:e2e
|
|
1217
|
+
\`\`\`
|
|
1218
|
+
|
|
1219
|
+
## \u6587\u6863
|
|
1220
|
+
|
|
1221
|
+
- [hai Agent Framework](https://github.com/hai-series/hai-framework)
|
|
1222
|
+
- [SvelteKit](https://kit.svelte.dev/)
|
|
1223
|
+
- [@h-ai/serv](./.agents/skills/hai-serv/SKILL.md)
|
|
1224
|
+
- [@h-ai/ui](./.agents/skills/hai-ui/SKILL.md)
|
|
1225
|
+
`;
|
|
1226
|
+
}
|
|
903
1227
|
function printCompletionMessage(options) {
|
|
904
1228
|
core.logger.info("", {});
|
|
905
1229
|
core.logger.info(chalk.green("\u2714 \u9879\u76EE\u521B\u5EFA\u6210\u529F\uFF01"));
|
|
@@ -919,7 +1243,13 @@ function printCompletionMessage(options) {
|
|
|
919
1243
|
if (!options.install) {
|
|
920
1244
|
core.logger.info(chalk.cyan(` ${options.packageManager} install`));
|
|
921
1245
|
}
|
|
922
|
-
|
|
1246
|
+
if (options.appType === "fullstack") {
|
|
1247
|
+
core.logger.info(chalk.cyan(` ${options.packageManager} typecheck`));
|
|
1248
|
+
core.logger.info(chalk.cyan(` ${options.packageManager} test`));
|
|
1249
|
+
core.logger.info(chalk.cyan(` ${options.packageManager} test:e2e`));
|
|
1250
|
+
} else {
|
|
1251
|
+
core.logger.info(chalk.cyan(` ${options.packageManager} dev`));
|
|
1252
|
+
}
|
|
923
1253
|
core.logger.info("", {});
|
|
924
1254
|
}
|
|
925
1255
|
async function detectProject(cwd) {
|
|
@@ -943,7 +1273,7 @@ async function detectProject(cwd) {
|
|
|
943
1273
|
}
|
|
944
1274
|
}
|
|
945
1275
|
|
|
946
|
-
// src/commands/add.ts
|
|
1276
|
+
// src/commands/cli-add.ts
|
|
947
1277
|
var MODULE_MAP = {
|
|
948
1278
|
// iam 依赖 crypto(password hash)/ db(user 存储)/ cache(session 缓存)
|
|
949
1279
|
"iam": { packages: ["@h-ai/iam"], deps: ["crypto", "db", "cache"], configKey: "iam", description: "\u8EAB\u4EFD\u4E0E\u8BBF\u95EE\u7BA1\u7406" },
|
|
@@ -1002,7 +1332,7 @@ async function addModule(options) {
|
|
|
1002
1332
|
core.logger.info(`\u53EF\u7528\u6A21\u5757: ${Object.keys(MODULE_MAP).join(", ")}`);
|
|
1003
1333
|
return;
|
|
1004
1334
|
}
|
|
1005
|
-
const { generateProjectAiSupport, resolveSkillNamesForPackages } = await import('./skill-templates-
|
|
1335
|
+
const { generateProjectAiSupport, resolveSkillNamesForPackages } = await import('./cli-skill-templates-IMYZPQRG.js');
|
|
1006
1336
|
if (moduleDef.packages.every((p) => project.haiPackages.includes(p))) {
|
|
1007
1337
|
const generatedFiles2 = await generateProjectAiSupport(
|
|
1008
1338
|
cwd,
|
|
@@ -1116,7 +1446,7 @@ async function deployCommand(options) {
|
|
|
1116
1446
|
try {
|
|
1117
1447
|
let deployModule;
|
|
1118
1448
|
try {
|
|
1119
|
-
deployModule = await import('./src-
|
|
1449
|
+
deployModule = await import('./src-N4NPS7AG.js');
|
|
1120
1450
|
} catch {
|
|
1121
1451
|
core.logger.error(chalk.red("Deploy module not found. Install @h-ai/deploy first:"));
|
|
1122
1452
|
core.logger.info(chalk.cyan(" pnpm add @h-ai/deploy"));
|
|
@@ -1592,7 +1922,7 @@ async function initProject(options) {
|
|
|
1592
1922
|
}
|
|
1593
1923
|
}
|
|
1594
1924
|
|
|
1595
|
-
// src/
|
|
1925
|
+
// src/cli-main.ts
|
|
1596
1926
|
function readCliVersion() {
|
|
1597
1927
|
try {
|
|
1598
1928
|
const here = path2.dirname(fileURLToPath(import.meta.url));
|
|
@@ -1607,12 +1937,14 @@ var VERSION = readCliVersion();
|
|
|
1607
1937
|
var cli = cac("hai");
|
|
1608
1938
|
cli.option("-v, --verbose", "\u663E\u793A\u8BE6\u7EC6\u8F93\u51FA");
|
|
1609
1939
|
cli.option("-C, --cwd <path>", "\u5DE5\u4F5C\u76EE\u5F55");
|
|
1610
|
-
cli.command("create [name]", "\u521B\u5EFA\u65B0\u7684 hai \u9879\u76EE").option("--type <type>", "\u5E94\u7528\u7C7B\u578B (admin, website, h5, api)").option("-t, --template <template>", "\u9879\u76EE\u6A21\u677F (minimal, default, full, custom)").option("-f, --features <features>", "\u529F\u80FD\u5217\u8868 (\u9017\u53F7\u5206\u9694: iam,db,cache,ai,storage,crypto)").option("--examples", "\u6DFB\u52A0\u793A\u4F8B\u4EE3\u7801").option("--no-examples", "\u4E0D\u6DFB\u52A0\u793A\u4F8B\u4EE3\u7801").option("--no-install", "\u4E0D\u5B89\u88C5\u4F9D\u8D56").option("-p, --package-manager <pm>", "\u5305\u7BA1\u7406\u5668 (pnpm, npm, yarn)").option("--no-git", "\u4E0D\u521D\u59CB\u5316 Git").option("--git-remote <url>", "Git \u8FDC\u7A0B\u4ED3\u5E93\u5730\u5740").action(async (name, options) => {
|
|
1940
|
+
cli.command("create [name]", "\u521B\u5EFA\u65B0\u7684 hai \u9879\u76EE").option("--type <type>", "\u5E94\u7528\u7C7B\u578B (admin, website, h5, api, android-app, fullstack)").option("--frontends <targets>", "\u524D\u540E\u7AEF\u5206\u79BB\u5DE5\u7A0B\u524D\u7AEF\u76EE\u6807 (\u9017\u53F7\u5206\u9694: web,app,miniapp,desktop)").option("-t, --template <template>", "\u9879\u76EE\u6A21\u677F (minimal, default, full, custom)").option("-f, --features <features>", "\u529F\u80FD\u5217\u8868 (\u9017\u53F7\u5206\u9694: iam,db,cache,ai,storage,crypto)").option("--examples", "\u6DFB\u52A0\u793A\u4F8B\u4EE3\u7801").option("--no-examples", "\u4E0D\u6DFB\u52A0\u793A\u4F8B\u4EE3\u7801").option("--no-install", "\u4E0D\u5B89\u88C5\u4F9D\u8D56").option("-p, --package-manager <pm>", "\u5305\u7BA1\u7406\u5668 (pnpm, npm, yarn)").option("--no-git", "\u4E0D\u521D\u59CB\u5316 Git").option("--git-remote <url>", "Git \u8FDC\u7A0B\u4ED3\u5E93\u5730\u5740").option("-y, --yes", "\u4F7F\u7528\u9ED8\u8BA4\u914D\u7F6E\uFF0C\u8DF3\u8FC7\u4EA4\u4E92").action(async (name, options) => {
|
|
1611
1941
|
try {
|
|
1612
1942
|
const features = typeof options.features === "string" ? options.features.split(",").map((f) => f.trim()) : void 0;
|
|
1943
|
+
const frontends = typeof options.frontends === "string" ? options.frontends.split(",").map((f) => f.trim()).filter(Boolean) : void 0;
|
|
1613
1944
|
await createProject({
|
|
1614
1945
|
name: name ?? "",
|
|
1615
1946
|
appType: options.type,
|
|
1947
|
+
frontends,
|
|
1616
1948
|
template: options.template,
|
|
1617
1949
|
features,
|
|
1618
1950
|
examples: options.examples,
|
|
@@ -1620,6 +1952,7 @@ cli.command("create [name]", "\u521B\u5EFA\u65B0\u7684 hai \u9879\u76EE").option
|
|
|
1620
1952
|
packageManager: options.packageManager,
|
|
1621
1953
|
git: options.git,
|
|
1622
1954
|
gitRemote: options.gitRemote,
|
|
1955
|
+
yes: options.yes,
|
|
1623
1956
|
verbose: options.verbose,
|
|
1624
1957
|
cwd: options.cwd
|
|
1625
1958
|
});
|