@h-ai/cli 0.1.0-alpha.65 → 0.1.0-alpha.66
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/README.en.md +13 -7
- package/README.ja.md +13 -7
- package/README.md +14 -8
- package/dist/{chunk-IPG3QNYK.js → chunk-FWN5B54L.js} +36 -4
- package/dist/chunk-FWN5B54L.js.map +1 -0
- package/dist/{chunk-47V5OT22.js → chunk-QYX6V7H2.js} +17 -43
- package/dist/chunk-QYX6V7H2.js.map +1 -0
- package/dist/cli-config-templates-3XSFIXBP.js +5 -0
- package/dist/{cli-config-templates-SJ2MBIR7.js.map → cli-config-templates-3XSFIXBP.js.map} +1 -1
- package/dist/{cli-skill-templates-A5VIR5J6.js → cli-skill-templates-TSYEQTCY.js} +3 -3
- package/dist/{cli-skill-templates-A5VIR5J6.js.map → cli-skill-templates-TSYEQTCY.js.map} +1 -1
- package/dist/index.js +273 -208
- package/dist/index.js.map +1 -1
- package/dist/{src-6PPBKQ6Q.js → src-RDQ2EIBT.js} +506 -488
- package/dist/src-RDQ2EIBT.js.map +1 -0
- package/package.json +8 -8
- package/templates/apps/api/.dockerignore.hbs +4 -5
- package/templates/apps/api/.gitignore.hbs +2 -1
- package/templates/apps/api/Dockerfile.hbs +2 -15
- package/templates/apps/api/apps/{{projectName}}-service/README.md.hbs +2 -2
- package/templates/apps/api/apps/{{projectName}}-service/package.json.hbs +0 -1
- package/templates/apps/api/hai.build.json.hbs +1 -0
- package/templates/apps/api/package.json.hbs +5 -8
- package/templates/apps/fullstack/.dockerignore.hbs +4 -5
- package/templates/apps/fullstack/.gitignore.hbs +2 -1
- package/templates/apps/fullstack/Dockerfile.hbs +3 -15
- package/templates/apps/fullstack/apps/{{projectName}}-app/README.md.hbs +0 -3
- package/templates/apps/fullstack/apps/{{projectName}}-app/package.json.hbs +0 -2
- package/templates/apps/fullstack/apps/{{projectName}}-app/vite.config.ts.hbs +2 -2
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/README.md.hbs +3 -6
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/package.json.hbs +2 -3
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/src/lib.rs.hbs +73 -2
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/tauri.conf.json.hbs +2 -2
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/vite.config.ts.hbs +2 -2
- package/templates/apps/fullstack/apps/{{projectName}}-web/README.md.hbs +2 -6
- package/templates/apps/fullstack/apps/{{projectName}}-web/package.json.hbs +0 -2
- package/templates/apps/fullstack/apps/{{projectName}}-web/vite.config.ts.hbs +2 -2
- package/templates/apps/fullstack/e2e/fullstack.spec.ts.hbs +1 -0
- package/templates/apps/fullstack/hai.build.json.hbs +7 -0
- package/templates/apps/fullstack/package.json.hbs +5 -12
- package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +2 -2
- package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +0 -1
- package/templates/apps/fullstack/packages/{{projectName}}-shared/README.md.hbs +1 -1
- package/templates/apps/mobile-app/index.html.hbs +1 -0
- package/templates/apps/mobile-app/public/runtime-config.js +1 -0
- package/templates/apps/mobile-app/src/lib/api.ts.hbs +2 -1
- package/templates/apps/mobile-app/src/lib/app-config.ts.hbs +3 -2
- package/templates/base/.dockerignore.hbs +4 -5
- package/templates/base/.gitignore.hbs +2 -1
- package/templates/base/Dockerfile.hbs +5 -22
- package/templates/base/docker/nginx.conf.hbs +6 -0
- package/templates/base/hai.build.json.hbs +1 -0
- package/templates/base/package.json.hbs +13 -17
- package/templates/base/svelte.config.js.hbs +2 -0
- package/templates/base/vite.config.ts.hbs +6 -2
- package/templates/shared/.gitattributes +5 -0
- package/templates/shared/container-runtime-config.sh +30 -0
- package/templates/shared/run-e2e.mjs +65 -0
- package/templates/shared/vite-runtime-config.ts +54 -0
- package/templates/skills/hai-app-create/development.md +3 -1
- package/templates/skills/hai-app-create/reference.md +2 -2
- package/templates/skills/hai-build/SKILL.md +16 -1
- package/templates/skills/hai-deploy/SKILL.md +52 -260
- package/templates/skills/hai-deploy/middleware.md +8 -14
- package/templates/skills/hai-ui/reference.md +2 -0
- package/dist/chunk-47V5OT22.js.map +0 -1
- package/dist/chunk-IPG3QNYK.js.map +0 -1
- package/dist/cli-config-templates-SJ2MBIR7.js +0 -5
- package/dist/src-6PPBKQ6Q.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { generateConfigFile, runtimeEnvironmentVariables, renderEnvironment, moduleEnvironmentVariables, parameterizeConfig } from './chunk-
|
|
3
|
-
import { cliM } from './chunk-
|
|
2
|
+
import { generateConfigFile, runtimeEnvironmentVariables, renderEnvironment, moduleEnvironmentVariables, parameterizeConfig } from './chunk-QYX6V7H2.js';
|
|
3
|
+
import { cliM } from './chunk-FWN5B54L.js';
|
|
4
4
|
import './chunk-2H7UOFLK.js';
|
|
5
|
-
import
|
|
5
|
+
import process4 from 'process';
|
|
6
6
|
import { cac } from 'cac';
|
|
7
7
|
import chalk from 'chalk';
|
|
8
|
-
import path2, { resolve, join } from 'path';
|
|
8
|
+
import path2, { resolve, join, dirname } from 'path';
|
|
9
9
|
import { fileURLToPath, pathToFileURL } from 'url';
|
|
10
10
|
import { wrapAnsi } from 'fast-wrap-ansi';
|
|
11
11
|
import fse from 'fs-extra';
|
|
@@ -14,27 +14,27 @@ import { core } from '@h-ai/core';
|
|
|
14
14
|
import ora from 'ora';
|
|
15
15
|
import prompts from 'prompts';
|
|
16
16
|
import { Buffer } from 'buffer';
|
|
17
|
-
import { execSync, execFileSync } from 'child_process';
|
|
18
|
-
import { randomBytes } from 'crypto';
|
|
17
|
+
import { execSync, execFileSync, spawn } from 'child_process';
|
|
18
|
+
import { randomBytes, createHash } from 'crypto';
|
|
19
19
|
import { stringify, parseDocument } from 'yaml';
|
|
20
|
-
import { existsSync,
|
|
20
|
+
import { readFileSync, mkdirSync, mkdtempSync, existsSync, createReadStream, writeFileSync, renameSync, rmSync } from 'fs';
|
|
21
21
|
import { createRequire } from 'module';
|
|
22
22
|
|
|
23
23
|
var CAMEL_CASE_SEPARATOR_REGEX = /[-_\s]+(.)?/g;
|
|
24
24
|
var LEADING_CHAR_REGEX = /^./;
|
|
25
25
|
function writeCliMessage(message) {
|
|
26
|
-
|
|
26
|
+
process4.stdout.write(`${message}
|
|
27
27
|
`);
|
|
28
28
|
}
|
|
29
29
|
function writeCliError(message, error) {
|
|
30
|
-
|
|
30
|
+
process4.stderr.write(`${message}
|
|
31
31
|
`);
|
|
32
32
|
if (error !== void 0)
|
|
33
|
-
|
|
33
|
+
process4.stderr.write(`${error instanceof Error ? error.message : String(error)}
|
|
34
34
|
`);
|
|
35
35
|
}
|
|
36
36
|
function formatPromptDescription(description) {
|
|
37
|
-
return wrapAnsi(description, Math.max(1, (
|
|
37
|
+
return wrapAnsi(description, Math.max(1, (process4.stdout.columns || 80) - 32), { hard: true });
|
|
38
38
|
}
|
|
39
39
|
function toCamelCase(str) {
|
|
40
40
|
return str.replace(CAMEL_CASE_SEPARATOR_REGEX, (_, c) => c ? c.toUpperCase() : "").replace(LEADING_CHAR_REGEX, (c) => c.toLowerCase());
|
|
@@ -208,6 +208,7 @@ var HAI_CATALOG_PACKAGE_NAMES = [
|
|
|
208
208
|
"@h-ai/audit",
|
|
209
209
|
"@h-ai/cache",
|
|
210
210
|
"@h-ai/capacitor",
|
|
211
|
+
"@h-ai/cli",
|
|
211
212
|
"@h-ai/core",
|
|
212
213
|
"@h-ai/crypto",
|
|
213
214
|
"@h-ai/datapipe",
|
|
@@ -388,6 +389,7 @@ function buildFullstackPackageSpecifiers(useCatalogProtocol) {
|
|
|
388
389
|
function buildApiWorkspaceCatalogPackages(featureMap) {
|
|
389
390
|
const packageNames = [
|
|
390
391
|
...API_WORKSPACE_EXTERNAL_CATALOG_PACKAGE_NAMES,
|
|
392
|
+
"@h-ai/cli",
|
|
391
393
|
"@h-ai/api-client",
|
|
392
394
|
"@h-ai/api-contract",
|
|
393
395
|
"@h-ai/core",
|
|
@@ -422,7 +424,7 @@ function buildApiWorkspaceCatalogPackages(featureMap) {
|
|
|
422
424
|
return pickCatalogPackages(packageNames, FULLSTACK_CATALOG_PACKAGES);
|
|
423
425
|
}
|
|
424
426
|
function buildAppHaiCatalogPackages(options) {
|
|
425
|
-
const packageNames = [];
|
|
427
|
+
const packageNames = ["@h-ai/cli"];
|
|
426
428
|
if (options.isSvelteOnlyApp) {
|
|
427
429
|
packageNames.push("@h-ai/api-client", "@h-ai/api-contract", "@h-ai/capacitor", "@h-ai/ui");
|
|
428
430
|
return pickCatalogPackages(packageNames, HAI_CATALOG_PACKAGES);
|
|
@@ -469,6 +471,7 @@ function buildAppHaiCatalogPackages(options) {
|
|
|
469
471
|
function buildFullstackCatalogPackages(frontends, deploy = false) {
|
|
470
472
|
const packageNames = [
|
|
471
473
|
...FULLSTACK_ROOT_CATALOG_PACKAGE_NAMES,
|
|
474
|
+
"@h-ai/cli",
|
|
472
475
|
...FULLSTACK_CONTRACT_CATALOG_PACKAGE_NAMES,
|
|
473
476
|
...FULLSTACK_SERV_CATALOG_PACKAGE_NAMES,
|
|
474
477
|
...FULLSTACK_SHARED_CATALOG_PACKAGE_NAMES
|
|
@@ -772,6 +775,12 @@ async function generateFromTemplates(projectPath, context) {
|
|
|
772
775
|
}
|
|
773
776
|
}
|
|
774
777
|
await renderDynamicFiles(root, projectPath, context);
|
|
778
|
+
await fse.copy(path2.join(root, "shared", "run-e2e.mjs"), path2.join(projectPath, "scripts", "run-e2e.mjs"));
|
|
779
|
+
await fse.copy(path2.join(root, "shared", ".gitattributes"), path2.join(projectPath, ".gitattributes"));
|
|
780
|
+
if (context.isSvelteOnlyApp) {
|
|
781
|
+
await fse.copy(path2.join(root, "shared", "vite-runtime-config.ts"), path2.join(projectPath, "scripts", "vite-runtime-config.ts"));
|
|
782
|
+
await fse.copy(path2.join(root, "shared", "container-runtime-config.sh"), path2.join(projectPath, "docker", "19-runtime-config.sh"));
|
|
783
|
+
}
|
|
775
784
|
if (context.isSvelteOnlyApp || context.appType === "fullstack") {
|
|
776
785
|
const navigationDir = context.appType === "fullstack" ? path2.join(projectPath, "packages", `${context.projectName}-shared`, "src", "lib", "navigation") : path2.join(projectPath, "src", "lib", "navigation");
|
|
777
786
|
await fse.copy(path2.join(root, "shared", "hash-router.svelte.ts"), path2.join(navigationDir, "hash-router.svelte.ts"));
|
|
@@ -1132,7 +1141,7 @@ async function createProject(options) {
|
|
|
1132
1141
|
});
|
|
1133
1142
|
await generateFromTemplates(projectPath, context);
|
|
1134
1143
|
{
|
|
1135
|
-
const { generateConfigFile: generateConfigFile2, generateEnvExample } = await import('./cli-config-templates-
|
|
1144
|
+
const { generateConfigFile: generateConfigFile2, generateEnvExample } = await import('./cli-config-templates-3XSFIXBP.js');
|
|
1136
1145
|
const configs = resolvedOptions.moduleConfigs;
|
|
1137
1146
|
const isApiWorkspace = resolvedOptions.appType === "api";
|
|
1138
1147
|
const isFullstack = resolvedOptions.appType === "fullstack";
|
|
@@ -1206,7 +1215,7 @@ HAI_ADMIN_DEFAULT_PASSWORD=${password}
|
|
|
1206
1215
|
await writeFile(path2.join(envDirectory, ".env.local"), "# \u672C\u673A\u79C1\u6709\u914D\u7F6E\uFF0C\u4E0D\u63D0\u4EA4 Git\uFF1B\u8986\u76D6\u516C\u5171\u57FA\u7840\u548C\u73AF\u5883\u914D\u7F6E\u3002\n");
|
|
1207
1216
|
}
|
|
1208
1217
|
}
|
|
1209
|
-
const { generateSkillFiles } = await import('./cli-skill-templates-
|
|
1218
|
+
const { generateSkillFiles } = await import('./cli-skill-templates-TSYEQTCY.js');
|
|
1210
1219
|
await generateSkillFiles(
|
|
1211
1220
|
projectPath,
|
|
1212
1221
|
resolvedOptions.features,
|
|
@@ -1253,7 +1262,7 @@ async function resolveOptions(options) {
|
|
|
1253
1262
|
writeCliMessage("");
|
|
1254
1263
|
const onCancel = () => {
|
|
1255
1264
|
writeCliMessage(chalk.red("\n\u5DF2\u53D6\u6D88"));
|
|
1256
|
-
|
|
1265
|
+
process4.exit(1);
|
|
1257
1266
|
};
|
|
1258
1267
|
let projectName = options.name;
|
|
1259
1268
|
if (!projectName && useDefaults) {
|
|
@@ -1509,7 +1518,7 @@ async function promptModuleConfigs(features, projectName) {
|
|
|
1509
1518
|
const configs = {};
|
|
1510
1519
|
const onCancel = () => {
|
|
1511
1520
|
writeCliMessage(chalk.red("\n\u5DF2\u53D6\u6D88"));
|
|
1512
|
-
|
|
1521
|
+
process4.exit(1);
|
|
1513
1522
|
};
|
|
1514
1523
|
writeCliMessage("");
|
|
1515
1524
|
writeCliMessage(chalk.bold(" \u2699 \u6A21\u5757\u914D\u7F6E"));
|
|
@@ -1749,7 +1758,7 @@ function generateEnvironmentReadme() {
|
|
|
1749
1758
|
| \u5F00\u53D1 / \u6D4B\u8BD5\u6A21\u5F0F / \u751F\u4EA7\u6A21\u5F0F\u9884\u89C8 | \`pnpm dev\` / \`dev:test\` / \`dev:prod\` |
|
|
1750
1759
|
| \u7C7B\u578B\u68C0\u67E5\uFF08check \u4E3A\u522B\u540D\uFF09 | \`pnpm typecheck\` |
|
|
1751
1760
|
| \u68C0\u67E5 / \u81EA\u52A8\u4FEE\u590D\u683C\u5F0F | \`pnpm lint\` / \`lint:fix\` |
|
|
1752
|
-
| \u6784\u5EFA / \
|
|
1761
|
+
| \u6E90\u7801\u6784\u5EFA / \u955C\u50CF\u6784\u5EFA | \`pnpm build\` / \`pnpm build --target docker\` |
|
|
1753
1762
|
| \u5355\u5143\u6D4B\u8BD5 / \u76D1\u542C / \u6D4F\u89C8\u5668\u9A8C\u6536 | \`pnpm test\` / \`test:watch\` / \`test:e2e\` |
|
|
1754
1763
|
| Node \u670D\u52A1\u6309\u73AF\u5883\u542F\u52A8\uFF08\u6784\u5EFA\u540E\uFF09 | \`pnpm start\` / \`start:test\` / \`start:prod\` |
|
|
1755
1764
|
|
|
@@ -1757,23 +1766,6 @@ Vite \u5BA2\u6237\u7AEF\u4F7F\u7528 \`preview\` \u9884\u89C8\u9759\u6001\u4EA7\u
|
|
|
1757
1766
|
}
|
|
1758
1767
|
function generateReadme(name, appTypeLabel, pm, appType) {
|
|
1759
1768
|
const install = getInstallCommand(pm);
|
|
1760
|
-
const isStaticImage = appType === "mobile-app";
|
|
1761
|
-
const containerPort = isStaticImage ? 8080 : 3e3;
|
|
1762
|
-
const runtimeOptions = isStaticImage ? "" : ` --env-file .env --mount type=bind,source=/absolute/path/to/config,target=/app/config,readonly --mount type=volume,source=${name}-data,target=/app/data`;
|
|
1763
|
-
const embeddedDataBuild = isStaticImage ? "" : `
|
|
1764
|
-
# \u5E26 data/ \u521D\u59CB\u6570\u636E\u6784\u5EFA\uFF08\u4E8C\u9009\u4E00\uFF09
|
|
1765
|
-
${getRunCommand(pm, "docker:build:data")}
|
|
1766
|
-
${getRunCommand(pm, "podman:build:data")}`;
|
|
1767
|
-
const runtimeNotes = isStaticImage ? "- \u8BE5\u6A21\u677F\u751F\u6210\u9759\u6001 Web \u955C\u50CF\uFF0C\u4E0D\u5305\u542B\u53EF\u5199\u6570\u636E\u5E93\u76EE\u5F55\u3002" : `\u4EE5\u4E0A\u4E09\u4E2A\u8FD0\u884C\u65F6\u53C2\u6570\u5747\u53EF\u6309\u9700\u5220\u9664\uFF1A
|
|
1768
|
-
|
|
1769
|
-
| \u53C2\u6570 | \u7528\u9014 | \u53EF\u9009\u6027 |
|
|
1770
|
-
| --- | --- | --- |
|
|
1771
|
-
| \`--env-file .env\` | \u6279\u91CF\u4F20\u5165\u73AF\u5883\u53D8\u91CF\uFF1B\u4E5F\u53EF\u6539\u7528\u591A\u4E2A \`-e NAME=value\`\u3002 | \u53EF\u9009\uFF1B\u5220\u9664\u540E\u4F7F\u7528\u955C\u50CF\u548C YAML \u9ED8\u8BA4\u503C\u3002 |
|
|
1772
|
-
| \`--mount type=bind,...target=/app/config,readonly\` | \u7528\u5BBF\u4E3B\u673A\u914D\u7F6E\u76EE\u5F55\u8986\u76D6\u955C\u50CF\u5185 \`/app/config\`\uFF1B\u5FC5\u987B\u628A \`source\` \u6539\u6210\u771F\u5B9E\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\`readonly\` \u9632\u6B62\u5BB9\u5668\u4FEE\u6539\u914D\u7F6E\u3002 | \u53EF\u9009\uFF1B\u5220\u9664\u540E\u4F7F\u7528\u955C\u50CF\u81EA\u5E26\u914D\u7F6E\u3002 |
|
|
1773
|
-
| \`--mount type=volume,...target=/app/data\` | \u521B\u5EFA\u6216\u590D\u7528 named volume\uFF0C\u6301\u4E45\u5316 SQLite \u548C\u672C\u5730\u5B58\u50A8\u3002 | \u53EF\u9009\u4F46\u751F\u4EA7\u73AF\u5883\u5EFA\u8BAE\u4FDD\u7559\uFF1B\u5220\u9664\u540E\u6570\u636E\u53EA\u5199\u5165\u5BB9\u5668\u5C42\uFF0C\u4F7F\u7528 \`--rm\` \u5220\u9664\u5BB9\u5668\u65F6\u4F1A\u4E22\u5931\u3002 |
|
|
1774
|
-
|
|
1775
|
-
- \u5E26\u6570\u636E\u6784\u5EFA\u4F1A\u628A\u5F53\u524D \`data/\`\uFF08\u4F8B\u5982\u9884\u7F6E SQLite \u6587\u4EF6\uFF09\u56FA\u5316\u4E3A\u955C\u50CF\u521D\u59CB\u5FEB\u7167\uFF1B\u8FD0\u884C\u540E\u4EA7\u751F\u7684\u65B0\u6570\u636E\u4ECD\u5E94\u5199\u5165 \`/app/data\` volume\u3002`;
|
|
1776
|
-
const testPath = isStaticImage ? "/health" : "/";
|
|
1777
1769
|
return `# ${name}
|
|
1778
1770
|
|
|
1779
1771
|
\u57FA\u4E8E hai Agent Framework \u6784\u5EFA\u7684${appTypeLabel}\u5E94\u7528\u3002
|
|
@@ -1799,31 +1791,20 @@ ${getRunCommand(pm, "i18n:compile")}
|
|
|
1799
1791
|
${getRunCommand(pm, "preview")}
|
|
1800
1792
|
\`\`\`
|
|
1801
1793
|
|
|
1802
|
-
## \
|
|
1803
|
-
|
|
1804
|
-
### \u6784\u5EFA\u955C\u50CF
|
|
1805
|
-
|
|
1806
|
-
\`\`\`bash
|
|
1807
|
-
# \u666E\u901A\u6784\u5EFA\uFF08\u4E8C\u9009\u4E00\uFF09
|
|
1808
|
-
${getRunCommand(pm, "docker:build")}
|
|
1809
|
-
${getRunCommand(pm, "podman:build")}${embeddedDataBuild}
|
|
1810
|
-
\`\`\`
|
|
1811
|
-
|
|
1812
|
-
### \u8FD0\u884C\u955C\u50CF
|
|
1794
|
+
## \u6784\u5EFA\u4E0E\u90E8\u7F72
|
|
1813
1795
|
|
|
1814
1796
|
\`\`\`bash
|
|
1815
|
-
#
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
docker stop ${name}
|
|
1797
|
+
# \u9ED8\u8BA4\u53EA\u7F16\u8BD1\u6E90\u7801\uFF1B\u4E0D\u9009\u62E9\u90E8\u7F72\u73AF\u5883
|
|
1798
|
+
${pm} build
|
|
1799
|
+
# \u6784\u5EFA\u5E76\u5BFC\u51FA API/Web \u955C\u50CF\uFF0Cauto \u4F18\u5148 Podman\u3001\u5176\u6B21 Docker
|
|
1800
|
+
${pm} build --target docker
|
|
1801
|
+
# \u9009\u62E9\u73AF\u5883\u3001\u4E2D\u95F4\u4EF6\u5E76\u4E0A\u4F20\u4E00\u4E2A Compose tar\uFF1B\u4E0D\u4F1A\u91CD\u65B0\u6784\u5EFA
|
|
1802
|
+
${pm} exec hai deploy . --env test
|
|
1803
|
+
# \u65E0\u6CD5\u8FDE\u63A5\u670D\u52A1\u5668\u65F6\u53EA\u751F\u6210\u5305\uFF0C\u6309\u8F93\u51FA\u8BF4\u660E\u624B\u5DE5\u642C\u8FD0\u548C\u542F\u52A8
|
|
1804
|
+
${pm} exec hai deploy . --env prod --bundle-only
|
|
1824
1805
|
\`\`\`
|
|
1825
1806
|
|
|
1826
|
-
|
|
1807
|
+
\u955C\u50CF\u6784\u5EFA\u914D\u7F6E\u89C1 \`hai.build.json\`\u3002\u6784\u5EFA\u4EA7\u7269\u4FDD\u5B58\u5728 \`.hai/build/docker/<buildId>\`\uFF0C\u53EF\u7528 \`--artifact-dir\` \u9009\u62E9\u540C\u4E00\u4EFD\u4EA7\u7269\u90E8\u7F72\u5230 test/prod\u3002\u90E8\u7F72\u5305\u542B\u79C1\u6709\u914D\u7F6E\uFF0C\u4E0D\u80FD\u63D0\u4EA4 Git\u3002\u73AF\u5883\u5DF2\u914D\u7F6E\u5B8C\u5907\u53EF\u52A0 \`--skip-middleware\`\u3002\u670D\u52A1\u8FD0\u884C\u6570\u636E\u7531 volume \u6301\u4E45\u5316\uFF0C\u955C\u50CF\u4E0D\u6253\u5305\u672C\u673A data\u3002API/Web \u8054\u5408\u90E8\u7F72\u516C\u5F00 Web \u5165\u53E3\u5E76\u4EE3\u7406\u540C\u6E90 API\uFF1B\u6CA1\u6709 Web \u4EA7\u7269\u65F6\u53EA\u90E8\u7F72\u670D\u52A1\u3002
|
|
1827
1808
|
|
|
1828
1809
|
${generateAiDevelopmentReadme()}## \u6587\u6863
|
|
1829
1810
|
|
|
@@ -1860,50 +1841,20 @@ ${pm} test
|
|
|
1860
1841
|
${pm} test:e2e
|
|
1861
1842
|
\`\`\`
|
|
1862
1843
|
|
|
1863
|
-
## \
|
|
1864
|
-
|
|
1865
|
-
### \u6784\u5EFA\u955C\u50CF
|
|
1866
|
-
|
|
1867
|
-
\`\`\`bash
|
|
1868
|
-
# \u666E\u901A\u6784\u5EFA\uFF08\u4E8C\u9009\u4E00\uFF09
|
|
1869
|
-
${pm} docker:build
|
|
1870
|
-
${pm} podman:build
|
|
1871
|
-
|
|
1872
|
-
# \u5C06 apps/${name}-service/data \u4F5C\u4E3A\u955C\u50CF\u521D\u59CB\u6570\u636E\u6784\u5EFA\uFF08\u4E8C\u9009\u4E00\uFF09
|
|
1873
|
-
${pm} docker:build:data
|
|
1874
|
-
${pm} podman:build:data
|
|
1875
|
-
\`\`\`
|
|
1876
|
-
|
|
1877
|
-
### \u8FD0\u884C\u955C\u50CF
|
|
1844
|
+
## \u6784\u5EFA\u4E0E\u90E8\u7F72
|
|
1878
1845
|
|
|
1879
1846
|
\`\`\`bash
|
|
1880
|
-
# \
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
\`\`\`bash
|
|
1890
|
-
curl --fail http://127.0.0.1:3000/health
|
|
1891
|
-
curl --fail http://127.0.0.1:3000/ready
|
|
1892
|
-
curl --fail --request POST http://127.0.0.1:3000/api/v1/app/info \\
|
|
1893
|
-
--header "Content-Type: application/json" --data '{}'
|
|
1894
|
-
docker stop ${name}
|
|
1847
|
+
# \u9ED8\u8BA4\u53EA\u7F16\u8BD1\u6E90\u7801\uFF1B\u4E0D\u9009\u62E9\u90E8\u7F72\u73AF\u5883
|
|
1848
|
+
${pm} build
|
|
1849
|
+
# \u6784\u5EFA\u5E76\u5BFC\u51FA API/Web \u955C\u50CF\uFF0Cauto \u4F18\u5148 Podman\u3001\u5176\u6B21 Docker
|
|
1850
|
+
${pm} build --target docker
|
|
1851
|
+
# \u9009\u62E9\u73AF\u5883\u3001\u4E2D\u95F4\u4EF6\u5E76\u4E0A\u4F20\u4E00\u4E2A Compose tar\uFF1B\u4E0D\u4F1A\u91CD\u65B0\u6784\u5EFA
|
|
1852
|
+
${pm} exec hai deploy apps/${name}-service --env test
|
|
1853
|
+
# \u65E0\u6CD5\u8FDE\u63A5\u670D\u52A1\u5668\u65F6\u53EA\u751F\u6210\u5305\uFF0C\u6309\u8F93\u51FA\u8BF4\u660E\u624B\u5DE5\u642C\u8FD0\u548C\u542F\u52A8
|
|
1854
|
+
${pm} exec hai deploy apps/${name}-service --env prod --bundle-only
|
|
1895
1855
|
\`\`\`
|
|
1896
1856
|
|
|
1897
|
-
- \u914D\u7F6E\
|
|
1898
|
-
- \u5E26\u6570\u636E\u6784\u5EFA\u4F1A\u628A \`apps/${name}-service/data\` \u56FA\u5316\u4E3A\u955C\u50CF\u521D\u59CB\u6570\u636E\uFF1B\u751F\u4EA7\u5199\u5165\u4ECD\u5EFA\u8BAE\u4F7F\u7528 \`/app/data\` volume\u3002
|
|
1899
|
-
|
|
1900
|
-
\u4EE5\u4E0A\u4E09\u4E2A\u8FD0\u884C\u65F6\u53C2\u6570\u5747\u53EF\u6309\u9700\u5220\u9664\uFF1A
|
|
1901
|
-
|
|
1902
|
-
| \u53C2\u6570 | \u7528\u9014 | \u53EF\u9009\u6027 |
|
|
1903
|
-
| --- | --- | --- |
|
|
1904
|
-
| \`--env-file .env\` | \u6279\u91CF\u4F20\u5165\u73AF\u5883\u53D8\u91CF\uFF1B\u4E5F\u53EF\u6539\u7528\u591A\u4E2A \`-e NAME=value\`\u3002 | \u53EF\u9009\uFF1B\u5220\u9664\u540E\u4F7F\u7528\u955C\u50CF\u548C YAML \u9ED8\u8BA4\u503C\u3002 |
|
|
1905
|
-
| \`--mount type=bind,...target=/app/config,readonly\` | \u7528\u5BBF\u4E3B\u673A\u914D\u7F6E\u76EE\u5F55\u8986\u76D6\u955C\u50CF\u5185 \`/app/config\`\uFF1B\u5FC5\u987B\u628A \`source\` \u6539\u6210\u771F\u5B9E\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\`readonly\` \u9632\u6B62\u5BB9\u5668\u4FEE\u6539\u914D\u7F6E\u3002 | \u53EF\u9009\uFF1B\u5220\u9664\u540E\u4F7F\u7528\u955C\u50CF\u81EA\u5E26\u914D\u7F6E\u3002 |
|
|
1906
|
-
| \`--mount type=volume,...target=/app/data\` | \u521B\u5EFA\u6216\u590D\u7528 named volume\uFF0C\u6301\u4E45\u5316 SQLite \u548C\u672C\u5730\u5B58\u50A8\u3002 | \u53EF\u9009\u4F46\u751F\u4EA7\u73AF\u5883\u5EFA\u8BAE\u4FDD\u7559\uFF1B\u5220\u9664\u540E\u6570\u636E\u53EA\u5199\u5165\u5BB9\u5668\u5C42\uFF0C\u4F7F\u7528 \`--rm\` \u5220\u9664\u5BB9\u5668\u65F6\u4F1A\u4E22\u5931\u3002 |
|
|
1857
|
+
\u955C\u50CF\u6784\u5EFA\u914D\u7F6E\u89C1 \`hai.build.json\`\u3002\u6784\u5EFA\u4EA7\u7269\u4FDD\u5B58\u5728 \`.hai/build/docker/<buildId>\`\uFF0C\u53EF\u7528 \`--artifact-dir\` \u9009\u62E9\u540C\u4E00\u4EFD\u4EA7\u7269\u90E8\u7F72\u5230 test/prod\u3002\u90E8\u7F72\u5305\u542B\u79C1\u6709\u914D\u7F6E\uFF0C\u4E0D\u80FD\u63D0\u4EA4 Git\u3002\u73AF\u5883\u5DF2\u914D\u7F6E\u5B8C\u5907\u53EF\u52A0 \`--skip-middleware\`\u3002\u670D\u52A1\u8FD0\u884C\u6570\u636E\u7531 volume \u6301\u4E45\u5316\uFF0C\u955C\u50CF\u4E0D\u6253\u5305\u672C\u673A data\u3002API/Web \u8054\u5408\u90E8\u7F72\u516C\u5F00 Web \u5165\u53E3\u5E76\u4EE3\u7406\u540C\u6E90 API\uFF1B\u6CA1\u6709 Web \u4EA7\u7269\u65F6\u53EA\u90E8\u7F72\u670D\u52A1\u3002
|
|
1907
1858
|
|
|
1908
1859
|
## \u6269\u5C55\u5EFA\u8BAE
|
|
1909
1860
|
|
|
@@ -1921,20 +1872,6 @@ ${generateAiDevelopmentReadme()}## \u6587\u6863
|
|
|
1921
1872
|
}
|
|
1922
1873
|
function generateFullstackReadme(name, pm, frontends) {
|
|
1923
1874
|
const enabledFrontends = frontends.map((target) => FRONTEND_TARGETS[target].name).join(" / ");
|
|
1924
|
-
const webBuildCommands = frontends.includes("web") ? `
|
|
1925
|
-
# Web \u9759\u6001\u955C\u50CF\uFF08\u4E8C\u9009\u4E00\uFF09
|
|
1926
|
-
${pm} docker:build:web
|
|
1927
|
-
${pm} podman:build:web` : "";
|
|
1928
|
-
const webRunCommand = frontends.includes("web") ? `
|
|
1929
|
-
|
|
1930
|
-
# Web\uFF1BPUBLIC_API_BASE \u5728\u5BB9\u5668\u542F\u52A8\u65F6\u6CE8\u5165\uFF0C\u4E0D\u9700\u8981\u91CD\u65B0\u6784\u5EFA\u955C\u50CF
|
|
1931
|
-
docker run --rm -d --name ${name}-web -p 8080:8080 \\
|
|
1932
|
-
-e PUBLIC_API_BASE=https://api.example.com \\
|
|
1933
|
-
${name}-web:latest` : "";
|
|
1934
|
-
const webTestCommands = frontends.includes("web") ? `curl --fail http://127.0.0.1:8080/health
|
|
1935
|
-
curl --fail http://127.0.0.1:8080/runtime-config.js
|
|
1936
|
-
` : "";
|
|
1937
|
-
const containerNames = frontends.includes("web") ? `${name} ${name}-web` : name;
|
|
1938
1875
|
return `# ${name}
|
|
1939
1876
|
|
|
1940
1877
|
\u57FA\u4E8E hai Agent Framework \u6784\u5EFA\u7684\u524D\u540E\u7AEF\u5206\u79BB\u591A\u5305\u5DE5\u7A0B\u3002
|
|
@@ -1981,77 +1918,34 @@ CLI \u5DF2\u5728\u6839\u76EE\u5F55\u751F\u6210 \`.env.local\`\uFF0C\u5176\u4E2D
|
|
|
1981
1918
|
|
|
1982
1919
|
${generateEnvironmentReadme()}
|
|
1983
1920
|
|
|
1984
|
-
## \u5F00\u53D1\
|
|
1921
|
+
## \u5F00\u53D1\u4E0E\u6784\u5EFA
|
|
1985
1922
|
|
|
1986
1923
|
\`\`\`bash
|
|
1987
1924
|
${pm} install
|
|
1988
1925
|
${pm} dev
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
${pm}
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
${pm} package
|
|
1995
|
-
|
|
1996
|
-
# \u90E8\u7F72\u5165\u53E3\uFF1A\u9ED8\u8BA4\u6267\u884C package\uFF0C\u53EF\u66FF\u6362\u4E3A\u56E2\u961F\u81EA\u5DF1\u7684 CI/CD \u53D1\u5E03\u811A\u672C
|
|
1997
|
-
${pm} deploy
|
|
1998
|
-
\`\`\`
|
|
1999
|
-
|
|
2000
|
-
## \u5BB9\u5668\u8FD0\u884C
|
|
2001
|
-
|
|
2002
|
-
\u9ED8\u8BA4\u955C\u50CF\u76F4\u63A5\u8FD0\u884C API Service\uFF0C\u5916\u90E8\u7AEF\u53E3\u4E3A 3000\u3002
|
|
2003
|
-
|
|
2004
|
-
### \u6784\u5EFA\u955C\u50CF
|
|
2005
|
-
|
|
2006
|
-
\`\`\`bash
|
|
2007
|
-
# Service \u666E\u901A\u6784\u5EFA\uFF08\u4E8C\u9009\u4E00\uFF09
|
|
2008
|
-
${pm} docker:build
|
|
2009
|
-
${pm} podman:build
|
|
2010
|
-
|
|
2011
|
-
# \u5C06 packages/${name}-serv/data \u4F5C\u4E3A\u955C\u50CF\u521D\u59CB\u6570\u636E\u6784\u5EFA\uFF08\u4E8C\u9009\u4E00\uFF09
|
|
2012
|
-
${pm} docker:build:data
|
|
2013
|
-
${pm} podman:build:data
|
|
2014
|
-
${webBuildCommands}
|
|
1926
|
+
${pm} typecheck
|
|
1927
|
+
${pm} build
|
|
1928
|
+
${pm} test
|
|
1929
|
+
${pm} test:e2e
|
|
1930
|
+
${frontends.includes("desktop") ? `${pm} build --target desktop --platform windows # Windows \u4E3B\u673A\uFF1BLinux/macOS \u5728\u5BF9\u5E94\u4E3B\u673A\u6784\u5EFA` : ""}
|
|
2015
1931
|
\`\`\`
|
|
2016
1932
|
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
\`\`\`bash
|
|
2020
|
-
# Service\uFF1B\u4F7F\u7528 Podman \u65F6\u5C06 docker \u66FF\u6362\u4E3A podman
|
|
2021
|
-
docker run --rm -d --name ${name} -p 3000:3000 --env-file .env --env-file .env.prod --env-file .env.local \\
|
|
2022
|
-
--mount type=bind,source=/absolute/path/to/config,target=/app/config,readonly \\
|
|
2023
|
-
--mount type=volume,source=${name}-data,target=/app/data \\
|
|
2024
|
-
${name}:latest
|
|
2025
|
-
${webRunCommand}
|
|
2026
|
-
\`\`\`
|
|
1933
|
+
Tauri \u9700\u8981\u76EE\u6807\u7CFB\u7EDF\u7684 Rust target\u3001SDK \u548C\u6253\u5305\u5DE5\u5177\u3002\u6D4B\u8BD5\u4EA7\u751F\u7684\u4E34\u65F6\u5DE5\u7A0B\u3001\u622A\u56FE\u3001\u62A5\u544A\u3001\u5BB9\u5668\u3001\u955C\u50CF\u4E0E\u8FDB\u7A0B\u5E94\u5728 finally/teardown \u4E2D\u81EA\u52A8\u6E05\u7406\uFF0C\u5931\u8D25\u4E5F\u6267\u884C\u3002
|
|
2027
1934
|
|
|
2028
|
-
|
|
1935
|
+
## \u6784\u5EFA\u4E0E\u90E8\u7F72
|
|
2029
1936
|
|
|
2030
1937
|
\`\`\`bash
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
1938
|
+
# \u9ED8\u8BA4\u53EA\u7F16\u8BD1\u6E90\u7801\uFF1B\u4E0D\u9009\u62E9\u90E8\u7F72\u73AF\u5883
|
|
1939
|
+
${pm} build
|
|
1940
|
+
# \u6784\u5EFA\u5E76\u5BFC\u51FA API/Web \u955C\u50CF\uFF0Cauto \u4F18\u5148 Podman\u3001\u5176\u6B21 Docker
|
|
1941
|
+
${pm} build --target docker
|
|
1942
|
+
# \u9009\u62E9\u73AF\u5883\u3001\u4E2D\u95F4\u4EF6\u5E76\u4E0A\u4F20\u4E00\u4E2A Compose tar\uFF1B\u4E0D\u4F1A\u91CD\u65B0\u6784\u5EFA
|
|
1943
|
+
${pm} exec hai deploy packages/${name}-serv --env test
|
|
1944
|
+
# \u65E0\u6CD5\u8FDE\u63A5\u670D\u52A1\u5668\u65F6\u53EA\u751F\u6210\u5305\uFF0C\u6309\u8F93\u51FA\u8BF4\u660E\u624B\u5DE5\u642C\u8FD0\u548C\u542F\u52A8
|
|
1945
|
+
${pm} exec hai deploy packages/${name}-serv --env prod --bundle-only
|
|
2034
1946
|
\`\`\`
|
|
2035
1947
|
|
|
2036
|
-
|
|
2037
|
-
- \u914D\u7F6E\u9ED8\u8BA4\u6765\u81EA \`packages/${name}-serv/config\`\uFF0C\u4E5F\u53EF\u6302\u8F7D\u5230 \`/app/config\`\uFF1BYAML \u4E2D\u7684 \`\${ENV_NAME:default}\` \u53EF\u7531 \`--env-file\` \u6216 \`-e\` \u6CE8\u5165\u3002
|
|
2038
|
-
- \u5E26\u6570\u636E\u6784\u5EFA\u4F1A\u628A \`packages/${name}-serv/data\` \u56FA\u5316\u4E3A\u955C\u50CF\u521D\u59CB\u6570\u636E\uFF1B\u6301\u4E45\u5316\u5199\u5165\u4ECD\u5E94\u4F7F\u7528 volume\u3002
|
|
2039
|
-
- Service \u7531 \`@h-ai/serv\` \u76F4\u63A5\u5BF9\u5916\u76D1\u542C\uFF0C\u4E0D\u989D\u5916\u542F\u52A8 Web \u8F6C\u53D1\u5C42\u3002
|
|
2040
|
-
${frontends.includes("web") ? `- Web \u4F7F\u7528\u72EC\u7ACB\u9759\u6001\u955C\u50CF\u5E76\u652F\u6301\u4E00\u6B21\u6784\u5EFA\u3001\u591A\u73AF\u5883\u90E8\u7F72\uFF1B\u6784\u5EFA\u53EA\u9700\u8FD0\u884C \`${pm} docker:build:web\`\uFF0C\u542F\u52A8\u5BB9\u5668\u65F6\u901A\u8FC7 \`-e PUBLIC_API_BASE=https://api.example.com\` \u6307\u5411 Service \u5BF9\u5916\u5730\u5740\u3002\u672A\u8BBE\u7F6E\u65F6\u9ED8\u8BA4\u4F7F\u7528 Web \u9875\u9762\u81EA\u8EAB origin\u3002` : ""}
|
|
2041
|
-
|
|
2042
|
-
\u4EE5\u4E0A\u4E09\u4E2A Service \u8FD0\u884C\u65F6\u53C2\u6570\u5747\u53EF\u6309\u9700\u5220\u9664\uFF1A
|
|
2043
|
-
|
|
2044
|
-
| \u53C2\u6570 | \u7528\u9014 | \u53EF\u9009\u6027 |
|
|
2045
|
-
| --- | --- | --- |
|
|
2046
|
-
| \`--env-file .env\` | \u6279\u91CF\u4F20\u5165\u73AF\u5883\u53D8\u91CF\uFF1B\u4E5F\u53EF\u6539\u7528\u591A\u4E2A \`-e NAME=value\`\u3002 | \u53EF\u9009\uFF1B\u5220\u9664\u540E\u4F7F\u7528\u955C\u50CF\u548C YAML \u9ED8\u8BA4\u503C\u3002 |
|
|
2047
|
-
| \`--mount type=bind,...target=/app/config,readonly\` | \u7528\u5BBF\u4E3B\u673A\u914D\u7F6E\u76EE\u5F55\u8986\u76D6\u955C\u50CF\u5185 \`/app/config\`\uFF1B\u5FC5\u987B\u628A \`source\` \u6539\u6210\u771F\u5B9E\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\`readonly\` \u9632\u6B62\u5BB9\u5668\u4FEE\u6539\u914D\u7F6E\u3002 | \u53EF\u9009\uFF1B\u5220\u9664\u540E\u4F7F\u7528\u955C\u50CF\u81EA\u5E26\u914D\u7F6E\u3002 |
|
|
2048
|
-
| \`--mount type=volume,...target=/app/data\` | \u521B\u5EFA\u6216\u590D\u7528 named volume\uFF0C\u6301\u4E45\u5316 SQLite \u548C\u672C\u5730\u5B58\u50A8\u3002 | \u53EF\u9009\u4F46\u751F\u4EA7\u73AF\u5883\u5EFA\u8BAE\u4FDD\u7559\uFF1B\u5220\u9664\u540E\u6570\u636E\u53EA\u5199\u5165\u5BB9\u5668\u5C42\uFF0C\u4F7F\u7528 \`--rm\` \u5220\u9664\u5BB9\u5668\u65F6\u4F1A\u4E22\u5931\u3002 |
|
|
2049
|
-
|
|
2050
|
-
\u524D\u7AEF\u5355\u72EC\u4EA4\u4ED8\u547D\u4EE4\uFF1A
|
|
2051
|
-
|
|
2052
|
-
- Web\uFF1A\`${pm} --filter ${name}-web build\` / \`${pm} --filter ${name}-web package\`
|
|
2053
|
-
- App\uFF1A\`${pm} --filter ${name}-app package\`\uFF0CAndroid/iOS \u53EF\u7528 \`cap:build:android:debug\` / \`cap:build:android:release\` / \`cap:build:ios\`
|
|
2054
|
-
- Desktop\uFF1A\`${pm} --filter ${name}-desktop tauri:dev\` / \`${pm} --filter ${name}-desktop package\`
|
|
1948
|
+
\u955C\u50CF\u6784\u5EFA\u914D\u7F6E\u89C1 \`hai.build.json\`\u3002\u6784\u5EFA\u4EA7\u7269\u4FDD\u5B58\u5728 \`.hai/build/docker/<buildId>\`\uFF0C\u53EF\u7528 \`--artifact-dir\` \u9009\u62E9\u540C\u4E00\u4EFD\u4EA7\u7269\u90E8\u7F72\u5230 test/prod\u3002\u90E8\u7F72\u5305\u542B\u79C1\u6709\u914D\u7F6E\uFF0C\u4E0D\u80FD\u63D0\u4EA4 Git\u3002\u73AF\u5883\u5DF2\u914D\u7F6E\u5B8C\u5907\u53EF\u52A0 \`--skip-middleware\`\u3002\u670D\u52A1\u8FD0\u884C\u6570\u636E\u7531 volume \u6301\u4E45\u5316\uFF0C\u955C\u50CF\u4E0D\u6253\u5305\u672C\u673A data\u3002API/Web \u8054\u5408\u90E8\u7F72\u516C\u5F00 Web \u5165\u53E3\u5E76\u4EE3\u7406\u540C\u6E90 API\uFF1B\u6CA1\u6709 Web \u4EA7\u7269\u65F6\u53EA\u90E8\u7F72\u670D\u52A1\u3002
|
|
2055
1949
|
|
|
2056
1950
|
## i18n \u4E0E shared \u534F\u540C
|
|
2057
1951
|
|
|
@@ -2195,7 +2089,7 @@ async function addModule(options) {
|
|
|
2195
2089
|
core.logger.info(`\u53EF\u7528\u6A21\u5757: ${Object.keys(MODULE_MAP).join(", ")}`);
|
|
2196
2090
|
return;
|
|
2197
2091
|
}
|
|
2198
|
-
const { generateProjectAiSupport, resolveSkillNamesForPackages } = await import('./cli-skill-templates-
|
|
2092
|
+
const { generateProjectAiSupport, resolveSkillNamesForPackages } = await import('./cli-skill-templates-TSYEQTCY.js');
|
|
2199
2093
|
if (moduleDef.packages.every((p) => project.haiPackages.includes(p))) {
|
|
2200
2094
|
const generatedFiles2 = await generateProjectAiSupport(
|
|
2201
2095
|
cwd,
|
|
@@ -2301,6 +2195,155 @@ async function addModule(options) {
|
|
|
2301
2195
|
throw error;
|
|
2302
2196
|
}
|
|
2303
2197
|
}
|
|
2198
|
+
async function run(command, args, cwd, quiet = false) {
|
|
2199
|
+
await new Promise((resolve3, reject) => {
|
|
2200
|
+
const env = Object.fromEntries(Object.entries(process4.env).filter(([key]) => !/^(?:HAI_|PUBLIC_|VITE_)/.test(key)));
|
|
2201
|
+
env.NODE_ENV = "production";
|
|
2202
|
+
if (env.CI === "1" || env.CI === "0")
|
|
2203
|
+
env.CI = env.CI === "1" ? "true" : "false";
|
|
2204
|
+
const child = spawn(command, args, { cwd, env, windowsHide: true, stdio: quiet ? "ignore" : "inherit", shell: false });
|
|
2205
|
+
child.once("error", reject);
|
|
2206
|
+
child.once("exit", (code) => code === 0 ? resolve3() : reject(new Error(cliM("cli_build_failed", { params: { command, code: String(code) } }))));
|
|
2207
|
+
});
|
|
2208
|
+
}
|
|
2209
|
+
async function pnpm(args, cwd) {
|
|
2210
|
+
const entry = process4.env.npm_execpath;
|
|
2211
|
+
if (entry && /(?:^|[/\\])pnpm(?:-native)?(?:\.exe|\.[cm]?js)?$/i.test(entry))
|
|
2212
|
+
return /\.[cm]?js$/i.test(entry) ? run(process4.execPath, [entry, ...args], cwd) : run(entry, args, cwd);
|
|
2213
|
+
if (process4.platform === "win32") {
|
|
2214
|
+
const directories = (process4.env.PATH ?? "").split(";");
|
|
2215
|
+
for (const directory of directories) {
|
|
2216
|
+
const executable = join(directory, "pnpm.exe");
|
|
2217
|
+
if (existsSync(executable))
|
|
2218
|
+
return run(executable, args, cwd);
|
|
2219
|
+
for (const relative of ["node_modules/pnpm/bin/pnpm.cjs", "pnpm.cjs"]) {
|
|
2220
|
+
const candidate = join(directory, relative);
|
|
2221
|
+
if (existsSync(candidate))
|
|
2222
|
+
return run(process4.execPath, [candidate, ...args], cwd);
|
|
2223
|
+
}
|
|
2224
|
+
}
|
|
2225
|
+
throw new Error(cliM("cli_build_use_pnpm"));
|
|
2226
|
+
}
|
|
2227
|
+
return run("pnpm", args, cwd);
|
|
2228
|
+
}
|
|
2229
|
+
async function buildCommand(options) {
|
|
2230
|
+
const cwd = resolve(options.cwd ?? process4.cwd());
|
|
2231
|
+
const target = options.target ?? "compile";
|
|
2232
|
+
if (!["compile", "docker", "desktop"].includes(target))
|
|
2233
|
+
throw new Error(cliM("cli_build_target_invalid"));
|
|
2234
|
+
if (target !== "docker" && (options.runtime !== void 0 || options.network !== void 0 || options.sqlitePrebuildMirror !== void 0 || options.httpProxy === false) || target !== "desktop" && (options.platform !== void 0 || options.arch !== void 0)) {
|
|
2235
|
+
throw new Error(cliM("cli_build_options_invalid"));
|
|
2236
|
+
}
|
|
2237
|
+
if (target === "compile") {
|
|
2238
|
+
await pnpm(["run", "compile"], cwd);
|
|
2239
|
+
return;
|
|
2240
|
+
}
|
|
2241
|
+
const metadata = JSON.parse(readFileSync(join(cwd, "package.json"), "utf8"));
|
|
2242
|
+
const appVersion = metadata.version;
|
|
2243
|
+
if (typeof appVersion !== "string" || appVersion.length > 80 || !/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[0-9a-z-]+(?:\.[0-9a-z-]+)*)?(?:\+[0-9a-z-]+(?:\.[0-9a-z-]+)*)?$/i.test(appVersion))
|
|
2244
|
+
throw new Error(cliM("cli_build_version_invalid"));
|
|
2245
|
+
const config = JSON.parse(readFileSync(join(cwd, "hai.build.json"), "utf8"));
|
|
2246
|
+
if (target === "desktop") {
|
|
2247
|
+
const platforms = { win32: "windows", linux: "linux", darwin: "macos" };
|
|
2248
|
+
const host = platforms[process4.platform];
|
|
2249
|
+
const platform = options.platform ?? host;
|
|
2250
|
+
const arch = options.arch ?? process4.arch;
|
|
2251
|
+
if (!platform || platform !== host || !["x64", "arm64"].includes(arch))
|
|
2252
|
+
throw new Error(cliM("cli_build_native_host"));
|
|
2253
|
+
if (!config.desktop?.length)
|
|
2254
|
+
throw new Error(cliM("cli_build_desktop_missing"));
|
|
2255
|
+
const rustTarget = `${arch === "x64" ? "x86_64" : "aarch64"}-${platform === "windows" ? "pc-windows-msvc" : platform === "macos" ? "apple-darwin" : "unknown-linux-gnu"}`;
|
|
2256
|
+
const bundles = platform === "windows" ? "nsis" : platform === "macos" ? "app,dmg" : "deb,appimage";
|
|
2257
|
+
for (const directory of config.desktop)
|
|
2258
|
+
await pnpm(["exec", "tauri", "build", "--target", rustTarget, "--bundles", bundles, "--config", JSON.stringify({ version: appVersion })], resolve(cwd, directory));
|
|
2259
|
+
core.logger.info(cliM("cli_build_native_ready", { params: { target: rustTarget } }));
|
|
2260
|
+
return;
|
|
2261
|
+
}
|
|
2262
|
+
if (!Array.isArray(config.images) || !config.images.length || config.images.filter((image) => image.name === "app").length !== 1 || config.images.length > 2 || new Set(config.images.map((image) => image.name)).size !== config.images.length || config.images.some((image) => !["app", "web"].includes(image.name) || image.containerPort !== void 0 && (!Number.isInteger(image.containerPort) || image.containerPort < 1 || image.containerPort > 65535))) {
|
|
2263
|
+
throw new Error(cliM("cli_build_images_missing"));
|
|
2264
|
+
}
|
|
2265
|
+
const candidates = options.runtime && options.runtime !== "auto" ? [options.runtime] : ["podman", "docker"];
|
|
2266
|
+
if (candidates.some((runtime2) => !["podman", "docker"].includes(runtime2)))
|
|
2267
|
+
throw new Error(cliM("cli_build_runtime_missing"));
|
|
2268
|
+
let runtime;
|
|
2269
|
+
for (const candidate of candidates) {
|
|
2270
|
+
try {
|
|
2271
|
+
await run(candidate, ["version"], cwd, true);
|
|
2272
|
+
runtime = candidate;
|
|
2273
|
+
break;
|
|
2274
|
+
} catch {
|
|
2275
|
+
}
|
|
2276
|
+
}
|
|
2277
|
+
if (!runtime)
|
|
2278
|
+
throw new Error(cliM("cli_build_runtime_missing"));
|
|
2279
|
+
if (options.sqlitePrebuildMirror) {
|
|
2280
|
+
const url = new URL(options.sqlitePrebuildMirror);
|
|
2281
|
+
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.search || url.hash)
|
|
2282
|
+
throw new Error(cliM("cli_build_mirror_invalid"));
|
|
2283
|
+
}
|
|
2284
|
+
const buildId = `${appVersion}-${Date.now()}-${randomBytes(3).toString("hex")}`;
|
|
2285
|
+
const artifact = { version: 2, appVersion, buildId, images: [] };
|
|
2286
|
+
const parent = join(cwd, ".hai/build/docker");
|
|
2287
|
+
mkdirSync(parent, { recursive: true });
|
|
2288
|
+
const staging = mkdtempSync(join(parent, ".building-"));
|
|
2289
|
+
const built = [];
|
|
2290
|
+
try {
|
|
2291
|
+
for (const image of config.images) {
|
|
2292
|
+
if (!["app", "web"].includes(image.name))
|
|
2293
|
+
throw new Error(cliM("cli_build_images_missing"));
|
|
2294
|
+
const context = resolve(cwd, image.context ?? ".");
|
|
2295
|
+
const imageRef = `localhost/hai-${basenameSafe(cwd)}-${image.name}:${buildId.toLowerCase().replaceAll("+", "_")}`;
|
|
2296
|
+
const args = ["build", "-f", resolve(context, image.dockerfile ?? "Dockerfile"), "-t", imageRef];
|
|
2297
|
+
if (options.network !== void 0)
|
|
2298
|
+
args.push("--network", options.network);
|
|
2299
|
+
const ignore = `${resolve(context, image.dockerfile ?? "Dockerfile")}.dockerignore`;
|
|
2300
|
+
if (runtime === "podman" && existsSync(ignore))
|
|
2301
|
+
args.push("--ignorefile", ignore);
|
|
2302
|
+
if (runtime === "podman") {
|
|
2303
|
+
args.push("--format", "docker", "--jobs", "1", ...options.httpProxy === false ? ["--http-proxy=false"] : []);
|
|
2304
|
+
if (options.httpProxy !== false) {
|
|
2305
|
+
for (const key of ["HTTP_PROXY", "HTTPS_PROXY", "FTP_PROXY", "NO_PROXY", "http_proxy", "https_proxy", "ftp_proxy", "no_proxy"]) {
|
|
2306
|
+
if (process4.env[key])
|
|
2307
|
+
args.push("--build-arg", `${key}=${process4.env[key]}`);
|
|
2308
|
+
}
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
if (image.target)
|
|
2312
|
+
args.push("--target", image.target);
|
|
2313
|
+
if (options.sqlitePrebuildMirror)
|
|
2314
|
+
args.push("--build-arg", `SQLITE_PREBUILD_MIRROR=${options.sqlitePrebuildMirror}`);
|
|
2315
|
+
built.push(imageRef);
|
|
2316
|
+
await run(runtime, [...args, context], cwd);
|
|
2317
|
+
const file = `${image.name}-${appVersion}.tar`;
|
|
2318
|
+
await run(runtime, ["save", ...runtime === "podman" ? ["--format", "docker-archive"] : [], "-o", join(staging, file), imageRef], cwd);
|
|
2319
|
+
const hash = createHash("sha256");
|
|
2320
|
+
for await (const chunk of createReadStream(join(staging, file)))
|
|
2321
|
+
hash.update(chunk);
|
|
2322
|
+
artifact.images.push({ name: image.name, file, imageRef, sha256: hash.digest("hex"), ...image.containerPort ? { containerPort: image.containerPort } : {} });
|
|
2323
|
+
}
|
|
2324
|
+
const output = join(parent, buildId);
|
|
2325
|
+
writeFileSync(join(staging, "manifest.json"), `${JSON.stringify(artifact, null, 2)}
|
|
2326
|
+
`);
|
|
2327
|
+
renameSync(staging, output);
|
|
2328
|
+
writeFileSync(join(parent, `latest-${buildId}`), `${buildId}
|
|
2329
|
+
`);
|
|
2330
|
+
renameSync(join(parent, `latest-${buildId}`), join(parent, "latest"));
|
|
2331
|
+
core.logger.info(cliM("cli_build_ready", { params: { path: output, runtime } }));
|
|
2332
|
+
} catch (error) {
|
|
2333
|
+
for (const imageRef of built) {
|
|
2334
|
+
try {
|
|
2335
|
+
await run(runtime, ["image", "rm", imageRef], cwd, true);
|
|
2336
|
+
} catch {
|
|
2337
|
+
}
|
|
2338
|
+
}
|
|
2339
|
+
throw error;
|
|
2340
|
+
} finally {
|
|
2341
|
+
rmSync(staging, { recursive: true, force: true });
|
|
2342
|
+
}
|
|
2343
|
+
}
|
|
2344
|
+
function basenameSafe(directory) {
|
|
2345
|
+
return directory.slice(dirname(directory).length + 1).toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/^-+/, "") || "app";
|
|
2346
|
+
}
|
|
2304
2347
|
function displayDeployValue(name, value) {
|
|
2305
2348
|
if (/PASSWORD|SECRET|TOKEN|APIKEY|PRIVATEKEY|ACCESSKEY|AUTHORIZATION/i.test(name.replace(/[^a-z0-9]/gi, "")) || /(?:^|_)PASS$/i.test(name) || value.includes("PRIVATE KEY"))
|
|
2306
2349
|
return cliM("cli_deploy_secret");
|
|
@@ -2542,15 +2585,21 @@ async function configureDeployMiddleware(module, scan, environment, config, yes
|
|
|
2542
2585
|
function configObject(value) {
|
|
2543
2586
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
2544
2587
|
}
|
|
2545
|
-
async function configureDeployTarget(module, config, environment, nonInteractive) {
|
|
2588
|
+
async function configureDeployTarget(module, config, environment, nonInteractive, bundleOnly) {
|
|
2589
|
+
if (bundleOnly) {
|
|
2590
|
+
const existing = configObject(config.provider);
|
|
2591
|
+
if (existing.type && existing.type !== "docker-ssh")
|
|
2592
|
+
throw new Error(cliM("cli_deploy_bundle_provider"));
|
|
2593
|
+
config.provider = { type: "docker-ssh", remote: { runtime: "auto" }, expose: { hostPort: 3e3 }, ...existing };
|
|
2594
|
+
}
|
|
2546
2595
|
const current = module.ProviderConfigSchema.safeParse(config.provider);
|
|
2547
|
-
if (current.success) {
|
|
2596
|
+
if (current.success && (bundleOnly || current.data.type !== "docker-ssh" || current.data.ssh)) {
|
|
2548
2597
|
config.provider = current.data;
|
|
2549
|
-
core.logger.info(cliM("cli_deploy_target_reused", { params: { target: current.data.type === "docker-ssh" ? `${current.data.ssh.username}@${current.data.ssh.host}:${current.data.ssh.port}` : "Vercel" } }));
|
|
2598
|
+
core.logger.info(cliM("cli_deploy_target_reused", { params: { target: current.data.type === "docker-ssh" ? current.data.ssh ? `${current.data.ssh.username}@${current.data.ssh.host}:${current.data.ssh.port}` : cliM("cli_deploy_bundle_local") : "Vercel" } }));
|
|
2550
2599
|
return;
|
|
2551
2600
|
}
|
|
2552
2601
|
if (nonInteractive)
|
|
2553
|
-
throw new Error(cliM("cli_deploy_target_missing", { params: { fields: current.error.issues.map((issue) => `provider.${issue.path.join(".")}`).join(", ") } }));
|
|
2602
|
+
throw new Error(cliM("cli_deploy_target_missing", { params: { fields: current.success ? "provider.ssh" : current.error.issues.map((issue) => `provider.${issue.path.join(".")}`).join(", ") } }));
|
|
2554
2603
|
const original = configObject(config.provider);
|
|
2555
2604
|
const platform = await prompts({
|
|
2556
2605
|
type: "select",
|
|
@@ -2610,21 +2659,21 @@ async function configureDeployTarget(module, config, environment, nonInteractive
|
|
|
2610
2659
|
}
|
|
2611
2660
|
async function deployCommand(options) {
|
|
2612
2661
|
const spinner = ora();
|
|
2613
|
-
const cwd = options.cwd ??
|
|
2662
|
+
const cwd = options.cwd ?? process4.cwd();
|
|
2614
2663
|
let appDir = resolve(cwd, options.appDir ?? ".");
|
|
2615
2664
|
let closeDeploy = null;
|
|
2616
|
-
const originalEnv = { ...
|
|
2665
|
+
const originalEnv = { ...process4.env };
|
|
2617
2666
|
try {
|
|
2618
2667
|
let environmentName = options.env;
|
|
2619
2668
|
if (!environmentName) {
|
|
2620
|
-
if (!
|
|
2669
|
+
if (!process4.stdin.isTTY)
|
|
2621
2670
|
throw new Error(cliM("cli_deploy_environment_hint"));
|
|
2622
2671
|
const answer = await prompts({ type: "text", name: "environment", message: cliM("cli_deploy_environment"), initial: "prod" });
|
|
2623
2672
|
environmentName = answer.environment;
|
|
2624
2673
|
if (!environmentName)
|
|
2625
2674
|
throw new Error(cliM("cli_deploy_cancelled"));
|
|
2626
2675
|
}
|
|
2627
|
-
if (!options.yes && !
|
|
2676
|
+
if (!options.yes && !process4.stdin.isTTY)
|
|
2628
2677
|
throw new Error(cliM("cli_deploy_environment_hint"));
|
|
2629
2678
|
let deployModule;
|
|
2630
2679
|
try {
|
|
@@ -2634,7 +2683,7 @@ async function deployCommand(options) {
|
|
|
2634
2683
|
localModule = localRequire.resolve("@h-ai/deploy");
|
|
2635
2684
|
} catch {
|
|
2636
2685
|
}
|
|
2637
|
-
deployModule = localModule ? await import(pathToFileURL(localModule).href) : await import('./src-
|
|
2686
|
+
deployModule = localModule ? await import(pathToFileURL(localModule).href) : await import('./src-RDQ2EIBT.js');
|
|
2638
2687
|
} catch {
|
|
2639
2688
|
core.logger.error(chalk.red(cliM("cli_deploy_module_missing")));
|
|
2640
2689
|
core.logger.info(chalk.cyan(" pnpm add @h-ai/deploy"));
|
|
@@ -2649,7 +2698,7 @@ async function deployCommand(options) {
|
|
|
2649
2698
|
const environment = deployModule.loadDeploymentEnvironment({ environment: environmentName, envDir: scan.envDir ?? appDir });
|
|
2650
2699
|
if (!environment.success)
|
|
2651
2700
|
throw new Error(environment.error.message);
|
|
2652
|
-
Object.assign(
|
|
2701
|
+
Object.assign(process4.env, environment.data.values);
|
|
2653
2702
|
spinner.start(cliM("cli_deploy_load_credentials"));
|
|
2654
2703
|
const credResult = deploy.credentials.load();
|
|
2655
2704
|
if (!credResult.success) {
|
|
@@ -2663,14 +2712,14 @@ async function deployCommand(options) {
|
|
|
2663
2712
|
core.logger.info(chalk.cyan(cliM("cli_deploy_config_hint")));
|
|
2664
2713
|
throw new Error(cliM("cli_deploy_config_missing", { params: { path: configPath } }));
|
|
2665
2714
|
}
|
|
2666
|
-
const loadedConfig = deployModule.loadDeploymentConfig("deploy", configPath,
|
|
2715
|
+
const loadedConfig = deployModule.loadDeploymentConfig("deploy", configPath, process4.env);
|
|
2667
2716
|
if (!loadedConfig.success)
|
|
2668
2717
|
throw new Error(loadedConfig.error.message);
|
|
2669
2718
|
const deployConfig = loadedConfig.data;
|
|
2670
2719
|
spinner.succeed(cliM("cli_deploy_config_loaded"));
|
|
2671
|
-
await configureDeployTarget(deployModule, deployConfig, environment.data, options.yes);
|
|
2720
|
+
await configureDeployTarget(deployModule, deployConfig, environment.data, options.yes, options.bundleOnly);
|
|
2672
2721
|
spinner.succeed(cliM("cli_deploy_scanned", { params: { name: scan.appName, sveltekit: String(scan.isSvelteKit), services: scan.requiredServices.join(", ") || cliM("cli_deploy_none") } }));
|
|
2673
|
-
let skipMiddleware = options.skipMiddleware
|
|
2722
|
+
let skipMiddleware = options.skipMiddleware;
|
|
2674
2723
|
if (!skipMiddleware && !options.yes && scan.requiredServices.length) {
|
|
2675
2724
|
const action = await prompts({
|
|
2676
2725
|
type: "select",
|
|
@@ -2687,15 +2736,15 @@ async function deployCommand(options) {
|
|
|
2687
2736
|
const serviceModes = skipMiddleware ? Object.fromEntries(scan.requiredServices.map((service) => [service, "keep"])) : await configureDeployMiddleware(deployModule, scan, environment.data, deployConfig, options.yes);
|
|
2688
2737
|
if (skipMiddleware)
|
|
2689
2738
|
deployConfig.services = void 0;
|
|
2690
|
-
for (const key of Object.keys(
|
|
2739
|
+
for (const key of Object.keys(process4.env)) {
|
|
2691
2740
|
if (originalEnv[key] === void 0)
|
|
2692
|
-
delete
|
|
2741
|
+
delete process4.env[key];
|
|
2693
2742
|
}
|
|
2694
|
-
Object.assign(
|
|
2743
|
+
Object.assign(process4.env, originalEnv);
|
|
2695
2744
|
const refreshed = deployModule.loadDeploymentEnvironment({ environment: environment.data.environment, envDir: environment.data.envDir });
|
|
2696
2745
|
if (!refreshed.success)
|
|
2697
2746
|
throw new Error(refreshed.error.message);
|
|
2698
|
-
Object.assign(
|
|
2747
|
+
Object.assign(process4.env, refreshed.data.values);
|
|
2699
2748
|
spinner.start(cliM("cli_deploy_initializing"));
|
|
2700
2749
|
const validatedConfig = deployModule.DeployConfigSchema.safeParse(deployConfig);
|
|
2701
2750
|
if (!validatedConfig.success)
|
|
@@ -2709,8 +2758,10 @@ async function deployCommand(options) {
|
|
|
2709
2758
|
spinner.start(cliM("cli_deploy_deploying"));
|
|
2710
2759
|
const deployResult = await deploy.deployApp(appDir, {
|
|
2711
2760
|
projectName: options.projectName,
|
|
2712
|
-
|
|
2713
|
-
|
|
2761
|
+
skipMiddleware,
|
|
2762
|
+
artifactDir: options.artifactDir ? resolve(cwd, options.artifactDir) : void 0,
|
|
2763
|
+
bundleOnly: options.bundleOnly,
|
|
2764
|
+
output: options.output ? resolve(cwd, options.output) : void 0,
|
|
2714
2765
|
environment: environment.data.environment,
|
|
2715
2766
|
envDir: environment.data.envDir,
|
|
2716
2767
|
serviceModes
|
|
@@ -2723,12 +2774,12 @@ async function deployCommand(options) {
|
|
|
2723
2774
|
}
|
|
2724
2775
|
throw new Error(cliM("cli_deploy_failed", { params: { message: deployResult.error.message } }));
|
|
2725
2776
|
}
|
|
2726
|
-
spinner.succeed(chalk.green(cliM("cli_deploy_success")));
|
|
2727
|
-
for (const key of Object.keys(
|
|
2777
|
+
spinner.succeed(chalk.green(cliM(deployResult.data.status === "packaged" ? "cli_deploy_bundle_ready" : "cli_deploy_success")));
|
|
2778
|
+
for (const key of Object.keys(process4.env)) {
|
|
2728
2779
|
if (originalEnv[key] === void 0)
|
|
2729
|
-
delete
|
|
2780
|
+
delete process4.env[key];
|
|
2730
2781
|
}
|
|
2731
|
-
Object.assign(
|
|
2782
|
+
Object.assign(process4.env, originalEnv);
|
|
2732
2783
|
const completedEnvironment = deployModule.loadDeploymentEnvironment({ environment: environment.data.environment, envDir: environment.data.envDir });
|
|
2733
2784
|
if (!completedEnvironment.success)
|
|
2734
2785
|
throw new Error(completedEnvironment.error.message);
|
|
@@ -2740,7 +2791,12 @@ async function deployCommand(options) {
|
|
|
2740
2791
|
core.logger.info(cliM("cli_deploy_saved", { params: { name: requirement.envPrefix, value: displayDeployValue(requirement.envPrefix, value) } }));
|
|
2741
2792
|
}
|
|
2742
2793
|
core.logger.info("");
|
|
2743
|
-
|
|
2794
|
+
if (deployResult.data.bundlePath)
|
|
2795
|
+
core.logger.info(cliM("cli_deploy_bundle_path", { params: { path: deployResult.data.bundlePath } }));
|
|
2796
|
+
if (deployResult.data.status === "packaged")
|
|
2797
|
+
core.logger.info(deployResult.data.instructions ?? "");
|
|
2798
|
+
else
|
|
2799
|
+
core.logger.info(chalk.cyan(cliM("cli_deploy_url", { params: { url: deployResult.data.url } })));
|
|
2744
2800
|
core.logger.info(chalk.gray(cliM("cli_deploy_id", { params: { id: deployResult.data.deploymentId } })));
|
|
2745
2801
|
if (deployResult.data.envVarsSet.length > 0) {
|
|
2746
2802
|
core.logger.info(chalk.gray(cliM("cli_deploy_env", { params: { names: deployResult.data.envVarsSet.join(", ") } })));
|
|
@@ -2756,14 +2812,14 @@ async function deployCommand(options) {
|
|
|
2756
2812
|
await closeDeploy();
|
|
2757
2813
|
} catch (error) {
|
|
2758
2814
|
core.logger.error("Failed to close deploy module", { error });
|
|
2759
|
-
|
|
2815
|
+
process4.exitCode = 1;
|
|
2760
2816
|
}
|
|
2761
2817
|
}
|
|
2762
|
-
for (const key of Object.keys(
|
|
2818
|
+
for (const key of Object.keys(process4.env)) {
|
|
2763
2819
|
if (originalEnv[key] === void 0)
|
|
2764
|
-
delete
|
|
2820
|
+
delete process4.env[key];
|
|
2765
2821
|
}
|
|
2766
|
-
Object.assign(
|
|
2822
|
+
Object.assign(process4.env, originalEnv);
|
|
2767
2823
|
}
|
|
2768
2824
|
}
|
|
2769
2825
|
var GENERATORS = {
|
|
@@ -3107,7 +3163,7 @@ async function initProject(options) {
|
|
|
3107
3163
|
const { project, existing, missing } = result;
|
|
3108
3164
|
spinner.succeed(`\u68C0\u6D4B\u5230\u9879\u76EE: ${chalk.cyan(project.name)}`);
|
|
3109
3165
|
if (project.isHaiProject) {
|
|
3110
|
-
const { generateProjectAiSupport, resolveSkillNamesForPackages } = await import('./cli-skill-templates-
|
|
3166
|
+
const { generateProjectAiSupport, resolveSkillNamesForPackages } = await import('./cli-skill-templates-TSYEQTCY.js');
|
|
3111
3167
|
const generatedFiles = await generateProjectAiSupport(cwd, resolveSkillNamesForPackages(project.haiPackages), {
|
|
3112
3168
|
overwriteSkills: false,
|
|
3113
3169
|
overwriteBridgeFiles: false
|
|
@@ -3211,7 +3267,7 @@ cli.command("create [name]", "\u521B\u5EFA\u65B0\u7684 hai \u9879\u76EE").option
|
|
|
3211
3267
|
cwd: options.cwd
|
|
3212
3268
|
});
|
|
3213
3269
|
} catch {
|
|
3214
|
-
|
|
3270
|
+
process4.exitCode = 1;
|
|
3215
3271
|
}
|
|
3216
3272
|
});
|
|
3217
3273
|
cli.command("add [module]", "\u5411\u73B0\u6709\u9879\u76EE\u6DFB\u52A0\u6A21\u5757").option("--no-install", "\u4E0D\u5B89\u88C5\u4F9D\u8D56").action(async (module, options) => {
|
|
@@ -3223,7 +3279,7 @@ cli.command("add [module]", "\u5411\u73B0\u6709\u9879\u76EE\u6DFB\u52A0\u6A21\u5
|
|
|
3223
3279
|
cwd: options.cwd
|
|
3224
3280
|
});
|
|
3225
3281
|
} catch {
|
|
3226
|
-
|
|
3282
|
+
process4.exit(1);
|
|
3227
3283
|
}
|
|
3228
3284
|
});
|
|
3229
3285
|
cli.command("init", "\u521D\u59CB\u5316/\u6821\u9A8C\u9879\u76EE\u914D\u7F6E").option("-f, --force", "\u5F3A\u5236\u91CD\u65B0\u751F\u6210\u914D\u7F6E").action(async (options) => {
|
|
@@ -3234,7 +3290,7 @@ cli.command("init", "\u521D\u59CB\u5316/\u6821\u9A8C\u9879\u76EE\u914D\u7F6E").o
|
|
|
3234
3290
|
cwd: options.cwd
|
|
3235
3291
|
});
|
|
3236
3292
|
} catch {
|
|
3237
|
-
|
|
3293
|
+
process4.exit(1);
|
|
3238
3294
|
}
|
|
3239
3295
|
});
|
|
3240
3296
|
cli.command("generate [type] [name]", "\u751F\u6210\u4EE3\u7801").alias("g").option("-o, --output <path>", "\u8F93\u51FA\u8DEF\u5F84").option("-f, --force", "\u8986\u76D6\u73B0\u6709\u6587\u4EF6").action(async (type, name, options) => {
|
|
@@ -3248,10 +3304,18 @@ cli.command("generate [type] [name]", "\u751F\u6210\u4EE3\u7801").alias("g").opt
|
|
|
3248
3304
|
cwd: options.cwd
|
|
3249
3305
|
});
|
|
3250
3306
|
} catch {
|
|
3251
|
-
|
|
3307
|
+
process4.exit(1);
|
|
3252
3308
|
}
|
|
3253
3309
|
});
|
|
3254
|
-
cli.command("
|
|
3310
|
+
cli.command("build", "\u6784\u5EFA\u6E90\u7801\u3001Docker \u955C\u50CF\u6216 Tauri \u5B89\u88C5\u5305\uFF08\u4E0D\u533A\u5206\u90E8\u7F72\u73AF\u5883\uFF09").option("--target <target>", "\u4EA7\u7269\u7C7B\u578B\uFF1Acompile\uFF08\u9ED8\u8BA4\uFF09/ docker / desktop").option("--runtime <runtime>", "\u672C\u5730\u5BB9\u5668\u5F15\u64CE\uFF1Aauto\uFF08\u4F18\u5148 Podman\uFF09/ podman / docker").option("--network <network>", "\u5BB9\u5668\u6784\u5EFA\u7F51\u7EDC\uFF08\u9ED8\u8BA4\u5F15\u64CE\u8BBE\u7F6E\uFF09\uFF0C\u4F8B\u5982 rootless Podman \u7684 pasta").option("--platform <platform>", "Tauri \u76EE\u6807\u7CFB\u7EDF\uFF1Awindows / linux / macos\uFF08\u5728\u5BF9\u5E94\u7CFB\u7EDF\u6784\u5EFA\uFF09").option("--arch <arch>", "Tauri \u76EE\u6807\u67B6\u6784\uFF1Ax64 / arm64").option("--sqlite-prebuild-mirror <url>", "SQLite \u9884\u7F16\u8BD1\u4E8C\u8FDB\u5236\u955C\u50CF\u6839\u5730\u5740").option("--no-http-proxy", "Podman \u6784\u5EFA\u4E0D\u7EE7\u627F\u672C\u673A\u4EE3\u7406").action(async (options) => {
|
|
3311
|
+
try {
|
|
3312
|
+
await buildCommand(options);
|
|
3313
|
+
} catch (error) {
|
|
3314
|
+
writeCliMessage(error instanceof Error ? error.message : String(error));
|
|
3315
|
+
process4.exitCode = 1;
|
|
3316
|
+
}
|
|
3317
|
+
});
|
|
3318
|
+
cli.command("deploy [appDir]", "\u90E8\u7F72\u5E94\u7528\u5230\u4E91\u5E73\u53F0").option("--env <environment>", "\u90E8\u7F72\u73AF\u5883\uFF08test / prod \u7B49\uFF0C\u5FC5\u987B\u5B58\u5728\u5BF9\u5E94\u73AF\u5883\u6587\u4EF6\uFF09").option("--env-dir <path>", "\u73AF\u5883\u6587\u4EF6\u6240\u5728\u76EE\u5F55\uFF08\u9ED8\u8BA4\u81EA\u52A8\u67E5\u627E\uFF09").option("-y, --yes", "\u6309\u5F53\u524D\u540E\u7AEF\u9ED8\u8BA4\u914D\u7F6E\u90E8\u7F72\uFF0C\u76EE\u6807\u73AF\u5883\u5DF2\u6709\u5B8C\u6574\u914D\u7F6E\u65F6\u4FDD\u6301\u4E0D\u53D8").option("--project-name <name>", "\u9879\u76EE\u540D\u79F0\uFF08\u9ED8\u8BA4\u670D\u52A1\u5305\u540D\uFF0C\u7F3A\u5931\u65F6\u4E3A\u76EE\u5F55\u540D\uFF1B\u9644\u52A0\u73AF\u5883\u540E\u7F00\uFF09").option("--skip-middleware", "\u914D\u7F6E\u5DF2\u5B8C\u5907\uFF0C\u8DF3\u8FC7\u5168\u90E8\u4E2D\u95F4\u4EF6\u5904\u7406\uFF0C\u76F4\u63A5\u90E8\u7F72").option("--artifact-dir <path>", "\u5DF2\u6709\u955C\u50CF\u6784\u5EFA\u4EA7\u7269\u76EE\u5F55\uFF08\u542B manifest.json\uFF09").option("--bundle-only", "\u53EA\u751F\u6210 Compose \u90E8\u7F72 tar\uFF0C\u624B\u5DE5\u642C\u8FD0\uFF1B\u4E0D\u8FDE\u63A5 SSH").option("--output <path>", "\u90E8\u7F72 tar \u8F93\u51FA\u8DEF\u5F84\uFF0C\u81EA\u52A8\u8865\u5E94\u7528\u7248\u672C\u540E\u7F00").action(async (appDir, options) => {
|
|
3255
3319
|
try {
|
|
3256
3320
|
await deployCommand({
|
|
3257
3321
|
appDir,
|
|
@@ -3259,14 +3323,15 @@ cli.command("deploy [appDir]", "\u90E8\u7F72\u5E94\u7528\u5230\u4E91\u5E73\u53F0
|
|
|
3259
3323
|
envDir: options.envDir,
|
|
3260
3324
|
yes: options.yes,
|
|
3261
3325
|
projectName: options.projectName,
|
|
3262
|
-
skipProvision: options.skipProvision,
|
|
3263
3326
|
skipMiddleware: options.skipMiddleware,
|
|
3264
|
-
|
|
3327
|
+
artifactDir: options.artifactDir,
|
|
3328
|
+
bundleOnly: options.bundleOnly,
|
|
3329
|
+
output: options.output,
|
|
3265
3330
|
verbose: options.verbose,
|
|
3266
3331
|
cwd: options.cwd
|
|
3267
3332
|
});
|
|
3268
3333
|
} catch {
|
|
3269
|
-
|
|
3334
|
+
process4.exit(1);
|
|
3270
3335
|
}
|
|
3271
3336
|
});
|
|
3272
3337
|
cli.command("g:page <name>", "\u751F\u6210\u9875\u9762").action(async (name, options) => {
|
|
@@ -3281,7 +3346,7 @@ cli.command("g:api <name>", "\u751F\u6210 API").action(async (name, options) =>
|
|
|
3281
3346
|
cli.command("g:model <name>", "\u751F\u6210\u6570\u636E\u6A21\u578B").action(async (name, options) => {
|
|
3282
3347
|
await generate({ type: "model", name, cwd: options.cwd });
|
|
3283
3348
|
});
|
|
3284
|
-
cli.version(VERSION);
|
|
3349
|
+
cli.version(VERSION, "-V, --version");
|
|
3285
3350
|
cli.help();
|
|
3286
3351
|
var parsed = cli.parse();
|
|
3287
3352
|
if (!cli.matchedCommand && !parsed.options.help && !parsed.options.version) {
|