@h-ai/cli 1.0.0-beta.5 → 1.0.0-beta.7
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 +24 -10
- package/README.ja.md +24 -10
- package/README.md +24 -10
- package/dist/{chunk-YHSX7AQX.js → chunk-7DNIMG2H.js} +89 -14
- package/dist/chunk-7DNIMG2H.js.map +1 -0
- package/dist/{chunk-YVNNMC4H.js → chunk-RT5OZJKM.js} +644 -11
- package/dist/chunk-RT5OZJKM.js.map +1 -0
- package/dist/{chunk-VUWM43KR.js → chunk-XI5SKOOR.js} +6673 -723
- package/dist/chunk-XI5SKOOR.js.map +1 -0
- package/dist/cli-config-templates-5KS3AE4H.js +5 -0
- package/dist/{cli-config-templates-LUJGDQNW.js.map → cli-config-templates-5KS3AE4H.js.map} +1 -1
- package/dist/{cli-skill-templates-COTP767H.js → cli-skill-templates-S2YH642Z.js} +3 -3
- package/dist/{cli-skill-templates-COTP767H.js.map → cli-skill-templates-S2YH642Z.js.map} +1 -1
- package/dist/index.js +395 -387
- package/dist/index.js.map +1 -1
- package/dist/metafile-esm.json +1 -1
- package/dist/src-CX5IJGYM.js +5 -0
- package/dist/src-CX5IJGYM.js.map +1 -0
- package/package.json +11 -11
- package/templates/README.md +4 -0
- package/templates/apps/api/apps/{{projectName}}-serv/README.md.hbs +1 -1
- package/templates/apps/api/apps/{{projectName}}-serv/package.json.hbs +4 -4
- package/templates/apps/api/apps/{{projectName}}-serv/src/lib/server/init.ts.hbs +41 -2
- package/templates/apps/api/images/serv.Dockerfile.hbs +11 -6
- package/templates/apps/fullstack/docs/security-configuration.md.hbs +1 -1
- package/templates/apps/fullstack/images/serv.Dockerfile.hbs +11 -6
- package/templates/apps/fullstack/images/web.Dockerfile.hbs +11 -5
- package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +6 -6
- package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +4 -4
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/index.ts.hbs +1 -2
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/runtime.ts.hbs +26 -2
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/app-server.test.ts.hbs +0 -1
- package/templates/base/images/web.Dockerfile.hbs +20 -10
- package/templates/base/package.json.hbs +8 -3
- package/templates/base/src/lib/server/init.ts.hbs +40 -2
- package/templates/shared/run-node.mjs +45 -0
- package/templates/skills/hai-ai/SKILL.md +6 -2
- package/templates/skills/hai-ai/acp.md +143 -0
- package/templates/skills/hai-ai/guide.md +2 -2
- package/templates/skills/hai-ai/resources.md +69 -0
- package/templates/skills/hai-app-create/development.md +9 -8
- package/templates/skills/hai-app-create/reference.md +1 -1
- package/templates/skills/hai-build/SKILL.md +5 -2
- package/templates/skills/hai-build/reference.md +16 -2
- package/templates/skills/hai-ci/SKILL.md +2 -0
- package/templates/skills/hai-core/SKILL.md +2 -2
- package/templates/skills/hai-core/reference.md +3 -3
- package/templates/skills/hai-core/request-access.md +1 -1
- package/templates/skills/hai-crypto/reference.md +1 -1
- package/templates/skills/hai-deploy/SKILL.md +8 -4
- package/templates/skills/hai-deploy/middleware.md +9 -9
- package/templates/skills/hai-iam/reference.md +2 -2
- package/templates/skills/hai-serv/reference.md +1 -1
- package/dist/chunk-VUWM43KR.js.map +0 -1
- package/dist/chunk-YHSX7AQX.js.map +0 -1
- package/dist/chunk-YVNNMC4H.js.map +0 -1
- package/dist/cli-config-templates-LUJGDQNW.js +0 -5
- package/dist/src-24PXSKE6.js +0 -5
- package/dist/src-24PXSKE6.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { generateConfigFile, runtimeEnvironmentVariables, renderEnvironment, generateProductionEnvironment, moduleEnvironmentVariables, documentConfig, parameterizeConfig } from './chunk-
|
|
3
|
-
import { cliM } from './chunk-
|
|
4
|
-
import {
|
|
2
|
+
import { generateConfigFile, runtimeEnvironmentVariables, renderEnvironment, generateProductionEnvironment, moduleEnvironmentVariables, documentConfig, parameterizeConfig } from './chunk-RT5OZJKM.js';
|
|
3
|
+
import { cliM } from './chunk-7DNIMG2H.js';
|
|
4
|
+
import { normalizeProjectName, resolveImageReference, resolveDownloadProxy } from './chunk-XI5SKOOR.js';
|
|
5
5
|
import './chunk-ZSDEVXZ7.js';
|
|
6
|
-
import
|
|
6
|
+
import process5 from 'process';
|
|
7
7
|
import { cac } from 'cac';
|
|
8
8
|
import chalk from 'chalk';
|
|
9
9
|
import path2, { resolve, dirname, join, relative, isAbsolute } from 'path';
|
|
@@ -14,11 +14,15 @@ import Handlebars2 from 'handlebars';
|
|
|
14
14
|
import { parseEnv } from 'util';
|
|
15
15
|
import ora from 'ora';
|
|
16
16
|
import prompts from 'prompts';
|
|
17
|
-
import { parse, stringify, parseAllDocuments
|
|
17
|
+
import { parse, stringify, parseAllDocuments } from 'yaml';
|
|
18
18
|
import { Buffer } from 'buffer';
|
|
19
19
|
import { execSync, execFileSync, spawn } from 'child_process';
|
|
20
20
|
import { randomBytes, createECDH, randomUUID, createHash } from 'crypto';
|
|
21
21
|
import { readFileSync, existsSync, mkdirSync, mkdtempSync, appendFileSync, createReadStream, writeFileSync, renameSync, rmSync, realpathSync, readdirSync, statSync, copyFileSync } from 'fs';
|
|
22
|
+
import { connect } from 'net';
|
|
23
|
+
import { Writable, Transform } from 'stream';
|
|
24
|
+
import { pipeline } from 'stream/promises';
|
|
25
|
+
import { StringDecoder } from 'string_decoder';
|
|
22
26
|
import { createRequire, findPackageJSON } from 'module';
|
|
23
27
|
import { core, ok, err as err$1, HaiCommonError } from '@h-ai/core';
|
|
24
28
|
import { stat, readFile, glob } from 'fs/promises';
|
|
@@ -28,20 +32,20 @@ import { gunzipSync } from 'zlib';
|
|
|
28
32
|
var CAMEL_CASE_SEPARATOR_REGEX = /[-_\s]+(.)?/g;
|
|
29
33
|
var LEADING_CHAR_REGEX = /^./;
|
|
30
34
|
function writeCliMessage(message) {
|
|
31
|
-
|
|
35
|
+
process5.stdout.write(`${message}
|
|
32
36
|
`);
|
|
33
37
|
}
|
|
34
38
|
function writeCliError(message, error) {
|
|
35
|
-
|
|
39
|
+
process5.stderr.write(`${message}
|
|
36
40
|
`);
|
|
37
41
|
if (error && typeof error === "object" && "error" in error)
|
|
38
42
|
error = error.error;
|
|
39
43
|
if (error !== void 0)
|
|
40
|
-
|
|
44
|
+
process5.stderr.write(`${error instanceof Error ? error.message : String(error)}
|
|
41
45
|
`);
|
|
42
46
|
}
|
|
43
47
|
function formatPromptDescription(description) {
|
|
44
|
-
return wrapAnsi(description, Math.max(1, (
|
|
48
|
+
return wrapAnsi(description, Math.max(1, (process5.stdout.columns || 80) - 32), { hard: true });
|
|
45
49
|
}
|
|
46
50
|
function toCamelCase(str) {
|
|
47
51
|
return str.replace(CAMEL_CASE_SEPARATOR_REGEX, (_, c) => c ? c.toUpperCase() : "").replace(LEADING_CHAR_REGEX, (c) => c.toLowerCase());
|
|
@@ -129,11 +133,10 @@ Handlebars2.registerHelper("html", (value) => Handlebars2.escapeExpression(value
|
|
|
129
133
|
Handlebars2.registerHelper("yaml", (key, value) => stringify({ [key]: value }).trim());
|
|
130
134
|
Handlebars2.registerHelper("jsString", (value) => `'${JSON.stringify(value).slice(1, -1).replace(/\\"/g, '"').replace(/'/g, "\\'")}'`);
|
|
131
135
|
Handlebars2.registerHelper("moduleConfig", function(moduleKey, enabled) {
|
|
132
|
-
const generated = generateConfigFile(moduleKey, this.moduleConfigs).trimEnd();
|
|
136
|
+
const generated = generateConfigFile(moduleKey, this.moduleConfigs, Boolean(enabled)).trimEnd();
|
|
133
137
|
const content = moduleKey === "feedback" ? generated.replace("HAI_FEEDBACK_APPID:my-app", `HAI_FEEDBACK_APPID:${this.projectName}`) : generated;
|
|
134
138
|
const configured = this.appType === "fullstack" && moduleKey === "iam" ? content.replace("HAI_IAM_SEEDDEFAULTDATA:true", "HAI_IAM_SEEDDEFAULTDATA:false").replace("variant: card", "variant: split") : content;
|
|
135
|
-
return
|
|
136
|
-
${configured.split("\n").map((line) => line ? `# ${line}` : "").join("\n")}`;
|
|
139
|
+
return configured;
|
|
137
140
|
});
|
|
138
141
|
var TEMPLATE_SKIP_IF_EMPTY_MARKER = "@skipIfEmpty";
|
|
139
142
|
var NORMALIZED_RENDER_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".js", ".svelte", ".json", ".css"]);
|
|
@@ -456,7 +459,11 @@ function buildApiWorkspaceCatalogPackages(featureMap) {
|
|
|
456
459
|
function buildAppHaiCatalogPackages(options) {
|
|
457
460
|
const packageNames = ["@h-ai/cli"];
|
|
458
461
|
if (options.isSvelteOnlyApp) {
|
|
459
|
-
packageNames.push("@h-ai/api-client", "@h-ai/
|
|
462
|
+
packageNames.push("@h-ai/api-client", "@h-ai/capacitor", "@h-ai/core", "@h-ai/ui");
|
|
463
|
+
if (options.featureMap.iam)
|
|
464
|
+
packageNames.push("@h-ai/api-contract");
|
|
465
|
+
if (options.featureMap.deploy)
|
|
466
|
+
packageNames.push("@h-ai/deploy");
|
|
460
467
|
if (options.featureMap.crypto)
|
|
461
468
|
packageNames.push("@h-ai/crypto");
|
|
462
469
|
return pickCatalogPackages(packageNames, HAI_CATALOG_PACKAGES);
|
|
@@ -828,6 +835,7 @@ async function generateFromTemplates(projectPath, context) {
|
|
|
828
835
|
}
|
|
829
836
|
await renderDynamicFiles(root, projectPath, context);
|
|
830
837
|
await fse.copy(path2.join(root, "shared", "run-e2e.mjs"), path2.join(projectPath, "scripts", "run-e2e.mjs"));
|
|
838
|
+
await fse.copy(path2.join(root, "shared", "run-node.mjs"), path2.join(projectPath, "scripts", "run-node.mjs"));
|
|
831
839
|
await fse.copy(path2.join(root, "shared", "e2e-env.ts"), path2.join(projectPath, "scripts", "e2e-env.ts"));
|
|
832
840
|
await fse.copy(path2.join(root, "shared", "build-metadata.ts"), path2.join(projectPath, "scripts", "build-metadata.ts"));
|
|
833
841
|
await fse.copy(path2.join(root, "shared", "public-base-path.mjs"), path2.join(projectPath, "scripts", "public-base-path.mjs"));
|
|
@@ -1223,7 +1231,14 @@ var FEATURES = {
|
|
|
1223
1231
|
packages: ["@h-ai/capacitor"]
|
|
1224
1232
|
}
|
|
1225
1233
|
};
|
|
1226
|
-
var
|
|
1234
|
+
var TEMPLATE_FEATURES = {
|
|
1235
|
+
"admin": ["iam", "reach"],
|
|
1236
|
+
"website": [],
|
|
1237
|
+
"h5": ["iam", "reach"],
|
|
1238
|
+
"api": ["iam", "reach", "storage", "feedback"],
|
|
1239
|
+
"mobile-app": ["iam", "crypto", "api-client", "capacitor"],
|
|
1240
|
+
"fullstack": ["iam", "storage", "audit", "reach", "scheduler", "feedback"]
|
|
1241
|
+
};
|
|
1227
1242
|
var PROJECT_NAME_REGEX = /^[a-z0-9-]+$/;
|
|
1228
1243
|
async function createProject(options) {
|
|
1229
1244
|
const spinner = ora();
|
|
@@ -1266,30 +1281,23 @@ async function createProject(options) {
|
|
|
1266
1281
|
});
|
|
1267
1282
|
await generateFromTemplates(projectPath, context);
|
|
1268
1283
|
{
|
|
1269
|
-
const { generateConfigFile: generateConfigFile2, generateEnvExample, generateProductionEnvironment: generateProductionEnvironment2 } = await import('./cli-config-templates-
|
|
1284
|
+
const { generateConfigFile: generateConfigFile2, generateEnvExample, generateProductionEnvironment: generateProductionEnvironment2 } = await import('./cli-config-templates-5KS3AE4H.js');
|
|
1270
1285
|
const configs = resolvedOptions.moduleConfigs;
|
|
1271
1286
|
const isApiWorkspace = resolvedOptions.appType === "api";
|
|
1272
1287
|
const isFullstack = resolvedOptions.appType === "fullstack";
|
|
1273
1288
|
const configDir = isApiWorkspace ? path2.join(projectPath, "apps", `${resolvedOptions.name}-serv`, "config") : isFullstack ? path2.join(projectPath, "packages", `${resolvedOptions.name}-serv`, "config") : path2.join(projectPath, "config");
|
|
1274
1289
|
const envExamplePath = isApiWorkspace ? path2.join(projectPath, "apps", `${resolvedOptions.name}-serv`, ".env.example") : path2.join(projectPath, ".env.example");
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
if (!isApiWorkspace && !isFullstack) {
|
|
1287
|
-
await writeFile(
|
|
1288
|
-
path2.join(configDir, "_core.yml"),
|
|
1289
|
-
generateConfigFile2("core", configs)
|
|
1290
|
-
);
|
|
1291
|
-
if (!context.isSvelteOnlyApp)
|
|
1292
|
-
await writeFile(path2.join(configDir, "_kit.yml"), generateConfigFile2("kit", configs));
|
|
1290
|
+
const enabledConfigs = /* @__PURE__ */ new Set(["core", ...context.isSvelteOnlyApp ? [] : resolvedOptions.features.map(getFeatureConfigKey).filter(Boolean)]);
|
|
1291
|
+
if (isApiWorkspace || isFullstack)
|
|
1292
|
+
enabledConfigs.add("serv");
|
|
1293
|
+
else if (!context.isSvelteOnlyApp)
|
|
1294
|
+
enabledConfigs.add("kit");
|
|
1295
|
+
for (const configKey of ["core", "serv", "kit", "db", "cache", "iam", "storage", "audit", "reach", "ai", "vecdb", "payment", "scheduler", "feedback"]) {
|
|
1296
|
+
const configPath = path2.join(configDir, `_${configKey}.yml`);
|
|
1297
|
+
if ((isApiWorkspace || isFullstack) && await fse.pathExists(configPath))
|
|
1298
|
+
continue;
|
|
1299
|
+
const content = generateConfigFile2(configKey, configs, enabledConfigs.has(configKey));
|
|
1300
|
+
await writeFile(configPath, configKey === "feedback" ? content.replace("HAI_FEEDBACK_APPID:my-app", `HAI_FEEDBACK_APPID:${resolvedOptions.name}`) : content);
|
|
1293
1301
|
}
|
|
1294
1302
|
const configContents = {};
|
|
1295
1303
|
for (const file of await fse.readdir(configDir)) {
|
|
@@ -1297,7 +1305,7 @@ async function createProject(options) {
|
|
|
1297
1305
|
configContents[file.slice(1, -4)] = await fse.readFile(path2.join(configDir, file), "utf8");
|
|
1298
1306
|
}
|
|
1299
1307
|
const envFeatures = context.isSvelteOnlyApp ? [] : isFullstack ? [.../* @__PURE__ */ new Set([...resolvedOptions.features, "reach"])] : resolvedOptions.features;
|
|
1300
|
-
const envContents = generateEnvExample(envFeatures, configs,
|
|
1308
|
+
const envContents = generateEnvExample(envFeatures, configs, true, configContents);
|
|
1301
1309
|
let envExample = isApiWorkspace ? envContents : isFullstack ? `${envContents}
|
|
1302
1310
|
# First-start administrator password; must satisfy the IAM password policy.
|
|
1303
1311
|
HAI_ADMIN_DEFAULT_PASSWORD=
|
|
@@ -1333,13 +1341,14 @@ ${runtimeExample.split("\n").map((line) => line && !line.startsWith("#") ? `# ${
|
|
|
1333
1341
|
${sharedVariables.join("\n")}
|
|
1334
1342
|
`);
|
|
1335
1343
|
for (const [mode, environment] of [["dev", "development"], ["test", "test"], ["prod", "production"]]) {
|
|
1336
|
-
let
|
|
1344
|
+
let privateValues = "# \u6A21\u5F0F\u79C1\u6709\u914D\u7F6E\uFF0C\u4E0D\u63D0\u4EA4 Git\uFF1B\u5404\u8282\u70B9\u901A\u8FC7\u53D7\u7BA1\u914D\u7F6E\u5171\u4EAB\u5BF9\u5E94\u79D8\u5BC6\u3002\n";
|
|
1345
|
+
const values = mode === "prod" ? generateProductionEnvironment2(envFeatures, configs) : `# \u516C\u5171 ${mode} \u73AF\u5883\u914D\u7F6E\uFF1B\u672C\u673A\u79C1\u6709\u503C\u653E .env.local\uFF0C\u8FDB\u7A0B\u73AF\u5883\u53D8\u91CF\u4F18\u5148\u3002
|
|
1337
1346
|
HAI_CORE_ENV=${environment}
|
|
1338
1347
|
HAI_CORE_LOGGING_LEVEL=${mode === "test" ? "warn" : "debug"}
|
|
1339
1348
|
`;
|
|
1340
1349
|
if (isFullstack) {
|
|
1341
1350
|
for (const name of ["HAI_ADMIN_DEFAULT_PASSWORD", "HAI_AUDIT_ADMIN_PASSWORD", "HAI_CONFIG_ADMIN_PASSWORD", "HAI_BUSINESS_OPERATOR_PASSWORD"])
|
|
1342
|
-
|
|
1351
|
+
privateValues += `
|
|
1343
1352
|
${name}=Aa1!${randomBytes(24).toString("base64url")}
|
|
1344
1353
|
`;
|
|
1345
1354
|
}
|
|
@@ -1348,15 +1357,16 @@ ${name}=Aa1!${randomBytes(24).toString("base64url")}
|
|
|
1348
1357
|
key.generateKeys();
|
|
1349
1358
|
const id = `${mode}-${randomBytes(6).toString("hex")}`;
|
|
1350
1359
|
const ring = { activeKeyId: id, keys: { [id]: { publicKey: key.getPublicKey("hex"), privateKey: key.getPrivateKey("hex").padStart(64, "0") } } };
|
|
1351
|
-
|
|
1360
|
+
privateValues += `
|
|
1352
1361
|
HAI_CRYPTO_TRANSPORT_SERVERKEYRING='${JSON.stringify(ring)}'
|
|
1353
1362
|
`;
|
|
1354
1363
|
}
|
|
1355
1364
|
await writeFile(path2.join(envDirectory, `.env.${mode}`), values);
|
|
1365
|
+
await fse.writeFile(path2.join(envDirectory, `.env.${mode}.local`), privateValues, { mode: 384 });
|
|
1356
1366
|
}
|
|
1357
|
-
await fse.writeFile(path2.join(envDirectory, ".env.local"), "# \u672C\u673A\u79C1\u6709\u8986\u76D6\uFF0C\u4E0D\u63D0\u4EA4 Git\uFF1B\u521D\u59CB\
|
|
1367
|
+
await fse.writeFile(path2.join(envDirectory, ".env.local"), "# \u672C\u673A\u901A\u7528\u79C1\u6709\u8986\u76D6\uFF0C\u4E0D\u63D0\u4EA4 Git\uFF1B\u521D\u59CB\u5BC6\u7801\u548C\u4F20\u8F93\u5BC6\u94A5\u73AF\u5206\u522B\u4F4D\u4E8E .env.dev.local / .env.test.local / .env.prod.local\u3002\n", { mode: 384 });
|
|
1358
1368
|
}
|
|
1359
|
-
const { generateSkillFiles } = await import('./cli-skill-templates-
|
|
1369
|
+
const { generateSkillFiles } = await import('./cli-skill-templates-S2YH642Z.js');
|
|
1360
1370
|
await generateSkillFiles(
|
|
1361
1371
|
projectPath,
|
|
1362
1372
|
resolvedOptions.features,
|
|
@@ -1403,7 +1413,7 @@ async function resolveOptions(options) {
|
|
|
1403
1413
|
writeCliMessage("");
|
|
1404
1414
|
const onCancel = () => {
|
|
1405
1415
|
writeCliMessage(chalk.red(cliM("cli_cancelledLine")));
|
|
1406
|
-
|
|
1416
|
+
process5.exit(1);
|
|
1407
1417
|
};
|
|
1408
1418
|
let projectName = options.name;
|
|
1409
1419
|
if (!projectName && useDefaults) {
|
|
@@ -1445,7 +1455,7 @@ ${formatPromptDescription(cliM("cli_selectHint"))}`,
|
|
|
1445
1455
|
}
|
|
1446
1456
|
const selectedAppType = resolvedAppType || "admin";
|
|
1447
1457
|
const selectedFrontends = selectedAppType === "fullstack" ? await resolveFrontendTargets(options.frontends, useDefaults, onCancel) : [];
|
|
1448
|
-
let selectedFeatures = selectedAppType === "mobile-app" ? [
|
|
1458
|
+
let selectedFeatures = selectedAppType === "mobile-app" ? [...TEMPLATE_FEATURES[selectedAppType]] : resolveFeatureDependencies(TEMPLATE_FEATURES[selectedAppType]);
|
|
1449
1459
|
selectedFeatures = selectedFeatures.filter((feature) => feature !== "deploy");
|
|
1450
1460
|
if (options.deploy !== false)
|
|
1451
1461
|
selectedFeatures.push("deploy");
|
|
@@ -1607,7 +1617,7 @@ async function promptModuleConfigs(features, projectName) {
|
|
|
1607
1617
|
const configs = {};
|
|
1608
1618
|
const onCancel = () => {
|
|
1609
1619
|
writeCliMessage(chalk.red(cliM("cli_cancelledLine")));
|
|
1610
|
-
|
|
1620
|
+
process5.exit(1);
|
|
1611
1621
|
};
|
|
1612
1622
|
writeCliMessage("");
|
|
1613
1623
|
writeCliMessage(chalk.bold(cliM("cli_createModuleConfig")));
|
|
@@ -1848,9 +1858,11 @@ function generateAiDevelopmentReadme() {
|
|
|
1848
1858
|
function generateEnvironmentReadme() {
|
|
1849
1859
|
return `### \u5206\u73AF\u5883\u914D\u7F6E
|
|
1850
1860
|
|
|
1851
|
-
\u8FD0\u884C\u53C2\u6570\u5728 \`.env.example\` \u4E2D\u9010\u9879\u8BF4\u660E\u7528\u9014\u3001\u679A\u4E3E\u548C\u8303\u56F4\u3002\`.env\` \u4E3A\u516C\u5171\u57FA\u7840\uFF0C\`.env.dev\` / \`.env.test\` / \`.env.prod\` \u4E3A\u73AF\u5883\u8986\u76D6\uFF0C\u5747\u63D0\u4EA4 Git\uFF1B\`.env.local\` \u4E3A\u672C\u673A\u79C1\u6709\u8986\u76D6\uFF0C\u4E0D\u63D0\u4EA4 Git\u3002\u4F18\u5148\u7EA7\u4E3A\u8FDB\u7A0B
|
|
1861
|
+
\u8FD0\u884C\u53C2\u6570\u5728 \`.env.example\` \u4E2D\u9010\u9879\u8BF4\u660E\u7528\u9014\u3001\u679A\u4E3E\u548C\u8303\u56F4\u3002\`.env\` \u4E3A\u516C\u5171\u57FA\u7840\uFF0C\`.env.dev\` / \`.env.test\` / \`.env.prod\` \u4E3A\u73AF\u5883\u8986\u76D6\uFF0C\u5747\u63D0\u4EA4 Git\uFF1B\`.env.local\` \u4E3A\u672C\u673A\u79C1\u6709\u8986\u76D6\uFF0C\u4E0D\u63D0\u4EA4 Git\u3002\u4F18\u5148\u7EA7\u4E3A\u8FDB\u7A0B > \`.env.<mode>.local\` > \`.env.local\` > \`.env.<mode>\` > \`.env\` > YAML\u3002\u540C\u6765\u6E90\u5148\u7236 JSON \u540E\u7EC6\u9879\uFF0C\u9AD8\u6765\u6E90\u6574\u6BB5\u66FF\u6362\u5148\u6E05\u9664\u4F4E\u6765\u6E90\u7EC6\u9879\u3002YAML \u663E\u5F0F\u5F15\u7528 \`HAI_<\u914D\u7F6E\u540D>_<\u8DEF\u5F84>\` \u5E76\u4FDD\u7559\u672C\u5730\u56DE\u9000\uFF0CcamelCase \u4E0D\u62C6\u8BCD\u3002\u5B8C\u6574\u547D\u4EE4\u3001\u52A0\u8F7D\u4F18\u5148\u7EA7\u548C Provider \u5207\u6362\u89C1 [\u73AF\u5883\u914D\u7F6E](.agents/skills/hai-app-create/development.md#\u73AF\u5883\u914D\u7F6E)\u3002
|
|
1862
|
+
|
|
1863
|
+
\u4F9D\u8D56\u53EA\u5305\u542B\u6A21\u677F\u5B9E\u9645\u4F7F\u7528\u7684\u6A21\u5757\uFF1Bconfig \u4E0E \`.env.example\` \u4FDD\u7559\u6240\u6709\u6A21\u5757\u7684\u5B8C\u6574\u53C2\u8003\uFF0C\u672A\u542F\u7528\u9879\u4EE5\u6CE8\u91CA\u63D0\u4F9B\uFF0C\u4E0D\u8FDB\u5165\u516C\u5171\u73AF\u5883\u9ED8\u8BA4\u503C\u3002\u65B0\u589E\u529F\u80FD\u65F6\u6DFB\u52A0\u4F9D\u8D56\u3001\u542F\u7528\u6240\u9700\u914D\u7F6E\uFF0C\u518D\u63A5\u5165\u521D\u59CB\u5316\u3001\u53CD\u5E8F\u5173\u95ED\u548C\u4E1A\u52A1\u4EE3\u7801\uFF1B\u5B89\u88C5\u4F9D\u8D56\u4E0D\u4F1A\u81EA\u52A8\u63A5\u5165\u6A21\u5757\u3002\u7EAF\u5BA2\u6237\u7AEF\u7684\u670D\u52A1\u7AEF\u914D\u7F6E\u4EC5\u4F9B\u540E\u7EED\u540E\u7AEF\u96C6\u6210\u53C2\u8003\uFF0C\u79D8\u5BC6\u4E0D\u5F97\u6CE8\u5165\u6D4F\u89C8\u5668\u3002
|
|
1852
1864
|
|
|
1853
|
-
\u751F\u4EA7 .env.prod \u6309\u5DF2\u542F\u7528\u6A21\u5757\u9009\u62E9\u5171\u4EAB PostgreSQL\uFF08\u660E\u786E\u9009\u62E9 MySQL \u65F6\u4FDD\u7559\uFF09\u3001Redis\u3001S3\u3001Qdrant\uFF0C\u9ED8\u8BA4\u4F7F\u7528 Compose \u5185\u90E8\u670D\u52A1\u540D db/cache/storage/vecdb\u3002\u5BC6\u7801\u3001S3 \u51ED\u636E\u3001\u6A21\u578B Key \u4E0E\u53D7\u4FDD\u62A4 Qdrant \u7684 Key \u53EA\u7531\u79C1\u6709\u73AF\u5883\u6CE8\u5165\uFF1B\u5BB9\u5668\u5916\u8FD0\u884C\u8986\u76D6\u5185\u90E8\u8FDE\u63A5\u5730\u5740\u3002\u751F\u4EA7 Reach \u5FC5\u987B\u6CE8\u5165\u771F\u5B9E HAI_REACH_PROVIDERS JSON\uFF0C\u516C\u5171\u7A7A\u6570\u7EC4\u4F1A\u62D2\u7EDD\u542F\u52A8\
|
|
1865
|
+
\u751F\u4EA7 .env.prod \u6309\u5DF2\u542F\u7528\u6A21\u5757\u9009\u62E9\u5171\u4EAB PostgreSQL\uFF08\u660E\u786E\u9009\u62E9 MySQL \u65F6\u4FDD\u7559\uFF09\u3001Redis\u3001S3\u3001Qdrant\uFF0C\u9ED8\u8BA4\u4F7F\u7528 Compose \u5185\u90E8\u670D\u52A1\u540D db/cache/storage/vecdb\u3002\u5BC6\u7801\u3001S3 \u51ED\u636E\u3001\u6A21\u578B Key \u4E0E\u53D7\u4FDD\u62A4 Qdrant \u7684 Key \u53EA\u7531\u79C1\u6709\u73AF\u5883\u6CE8\u5165\uFF1B\u5BB9\u5668\u5916\u8FD0\u884C\u8986\u76D6\u5185\u90E8\u8FDE\u63A5\u5730\u5740\u3002\u751F\u4EA7 Reach \u5FC5\u987B\u6CE8\u5165\u771F\u5B9E HAI_REACH_PROVIDERS JSON\uFF0C\u516C\u5171\u7A7A\u6570\u7EC4\u4F1A\u62D2\u7EDD\u542F\u52A8\u3002\u540E\u7EED\u901A\u8FC7 hai add ai \u8865\u9F50 db+vecdb \u4F9D\u8D56\u65F6\uFF0C\u8FD8\u987B\u5728\u5E94\u7528\u5165\u53E3\u63A5\u5165\u521D\u59CB\u5316\u548C\u53CD\u5E8F\u5173\u95ED\uFF0C\u4E0D\u80FD\u4EC5\u5B89\u88C5\u4F9D\u8D56\u3002
|
|
1854
1866
|
|
|
1855
1867
|
| \u7528\u9014 | \u547D\u4EE4 |
|
|
1856
1868
|
| --- | --- |
|
|
@@ -1873,6 +1885,7 @@ function generateBuildDeploymentReadme(pm, appDir) {
|
|
|
1873
1885
|
|
|
1874
1886
|
\u81EA\u5EFAS3\u7684\u5185\u90E8endpoint\u4E0E\u6D4F\u89C8\u5668publicEndpoint\u5206\u5F00\u3002publicEndpoint\u53EF\u8BBE\u7F6E\u4E3Ahttps://example.com/delivery/files\u7B49\u5E26\u76EE\u5F55\u5730\u5740\uFF0C\u4E0D\u542B\u6876\u540D\u3001\u51ED\u636E\u6216\u67E5\u8BE2\uFF1B\u8FD4\u56DEURL\u4FDD\u7559\u6876\u540D\uFF0CWeb Nginx\u6216SSR/API gateway\u53BB\u6389\u5165\u53E3\u524D\u7F00\uFF0C\u4FDD\u7559\u539F\u59CBS3\u8DEF\u5F84\u3001Host\u4E0E\u67E5\u8BE2\u540E\u76F4\u63A5\u8F6C\u53D1storage\uFF0C\u5927\u6587\u4EF6\u4E0D\u7ECF\u8FC7Serv\u3002\u5916\u5C42\u4EE3\u7406\u4FDD\u7559\u5B8C\u6574\u5165\u53E3\u8DEF\u5F84\uFF0C\u4E0D\u91CD\u590D\u53BB\u524D\u7F00\uFF1B\u5916\u90E8S3/CORS\u6309\u5B9E\u9645\u670D\u52A1\u914D\u7F6E\uFF0CLocal\u4E0D\u516C\u5F00\u79C1\u6709\u76EE\u5F55\u3002\u589E\u52A0\u7F51\u5173\u3001\u6539\u53D8\u6876\u6216\u516C\u5F00\u5730\u5740\u65F6\u5168\u91CF\u90E8\u7F72\uFF0C\u5E94\u7528\u589E\u91CF\u4E0E\u56DE\u6EDA\u4FDD\u6301\u539F\u914D\u7F6E\uFF1B\u8BE6\u89C1[\u5B58\u50A8\u4F7F\u7528\u89C4\u8303](.agents/skills/hai-storage/SKILL.md)\u3002
|
|
1875
1887
|
\u6BCF\u4E2A\u955C\u50CF\u5BF9\u5E94 images/ \u4E2D\u4E00\u4E2A Dockerfile\uFF0C\u6839 hai.json \u7684 build \u5206\u533A\u6307\u5B9A\u6587\u4EF6\uFF0Cdeploy \u5206\u533A\u4FDD\u5B58\u6574\u4E2A\u9879\u76EE\u7684\u90E8\u7F72\u914D\u7F6E\u3002
|
|
1888
|
+
\u955C\u50CF\u6784\u5EFA\u53EF\u52A0 --image-source cn --npm-source cn\uFF0C\u5206\u522B\u9009\u62E9\u4E2D\u56FD\u5927\u9646\u955C\u50CF\u6E90\u4E0E npm \u6E90\uFF1B\u8FD8\u652F\u6301 official/custom\u3002\u9996\u6B21\u4EA4\u4E92\u9009\u62E9\u4FDD\u5B58\u5230 hai.json.build.sources\uFF0C--yes \u590D\u7528\u914D\u7F6E\uFF0C\u672A\u914D\u7F6E\u65F6\u4F7F\u7528\u5B98\u65B9\u6E90\u3002\u4EE3\u7406\u7528 --proxy-mode inherit|system|custom|none\uFF0C\u81EA\u5B9A\u4E49\u914D\u5408 --proxy-url\uFF1BDocker/Podman \u5F15\u64CE\u62C9\u53D6\u4EE3\u7406\u9700\u5728\u5F15\u64CE\u4FA7\u8BBE\u7F6E\uFF0C\u6784\u5EFA\u5BB9\u5668\u4F1A\u5355\u72EC\u68C0\u67E5\u4EE3\u7406\u53EF\u8FBE\u6027\u3002\u81EA\u5B9A\u4E49\u6E90\u548C\u65E7\u5DE5\u7A0B Dockerfile \u66F4\u65B0\u89C1 .agents/skills/hai-build/reference.md \u7684\u4E0B\u8F7D\u6E90\u4E0E\u4EE3\u7406\u8BF4\u660E\u3002
|
|
1876
1889
|
\u4E0B\u8F7D\u3001\u5B89\u88C5\u548C\u6574\u7406\u751F\u4EA7\u4F9D\u8D56\u590D\u7528\u540C\u4E00\u4EFD\u5305\u7F13\u5B58\u4E0E SQLite \u9A71\u52A8\u7F13\u5B58\uFF0C\u4F9D\u8D56\u5B89\u88C5\u5148\u4E8E\u6E90\u7801\u590D\u5236\u3002\u524D\u540E\u7AEF\u9ED8\u8BA4\u6700\u591A\u5E76\u884C\u6784\u5EFA\u4E24\u9879\uFF0C--concurrency 1\u53EF\u964D\u4F4E\u8D44\u6E90\u5360\u7528\u3002\u8FD0\u884C\u955C\u50CF\u53BB\u9664\u5E94\u7528\u81EA\u8EAB\u7684\u58F0\u660E\u6587\u4EF6\u3001\u6E90\u7801\u6620\u5C04\u548C\u8BF4\u660E\u6587\u4EF6\u3002
|
|
1877
1890
|
\u9ED8\u8BA4\u5BB9\u5668\u7528\u4E8E CPU \u8FD0\u884C\u6216\u8FDE\u63A5\u8FDC\u7A0B AI \u670D\u52A1\uFF0C\u4E0D\u989D\u5916\u4E0B\u8F7D GPU \u8FD0\u884C\u5E93\uFF1B\u9700\u8981\u4F7F\u7528\u90E8\u7F72\u673A\u5668\u4E0A\u7684 GPU \u65F6\uFF0C\u81EA\u884C\u5B9A\u5236\u955C\u50CF\u548C\u5BB9\u5668\u8FD0\u884C\u53C2\u6570\u3002
|
|
1878
1891
|
|
|
@@ -1896,7 +1909,7 @@ ${pm} exec hai deploy ${appDir} --env prod --services web
|
|
|
1896
1909
|
\u6BCF\u6B21\u79BB\u7EBF\u4EA4\u4ED8\u751F\u6210\u72EC\u7ACB\u76EE\u5F55\uFF0C\u9ED8\u8BA4tar.gz\uFF08\u663E\u5F0F--output release.tar\u53EF\u4FDD\u7559\u672A\u538B\u7F29\uFF09\uFF0C\u5916\u5C42\u4EC5\u542B\u5F52\u6863\u3001deploy.ps1\uFF08Windows\uFF09\u3001deploy.sh\uFF08Linux/macOS\uFF09\u3001deploy-target.json\u3001read-target.awk\u3001deploy-local.sh \u548C README.txt\uFF1BCompose\u3001\u8FD0\u884C\u73AF\u5883\u548C\u6E05\u5355\u4EC5\u5728\u5F52\u6863\u5185\uFF0CREADME\u4E0D\u91CD\u590D\u3002\u4E2D\u95F4\u4EF6\u5F52\u6863\u6309\u955C\u50CF\u5185\u5BB9ID\u7F13\u5B58\u5E76\u5728\u590D\u7528\u524D\u9A8C\u8BC1\u6458\u8981\u3002\u6210\u529F\u540E\u6E05\u7406\u672C\u6B21incoming\u4E0A\u4F20\u4E0E\u89E3\u5305\u76EE\u5F55\uFF0Crelease\u4FDD\u7559\u6062\u590D\u914D\u7F6E\u548C\u72B6\u6001\uFF0C\u955C\u50CF\u7531\u5F15\u64CE\u4FDD\u5B58\u3002\u4EA4\u4E92\u5F0F\u6253\u5305\u5728\u6784\u5EFA\u548C\u4E2D\u95F4\u4EF6\u914D\u7F6E\u540E\u6700\u540E\u8BE2\u95EE\u662F\u5426\u4FDD\u5B58\u6216\u4FEE\u6539 SSH \u4FE1\u606F\uFF0C\u5199\u5165 .env.<\u73AF\u5883>.local \u5E76\u7528\u4E8E\u672C\u6B21\u548C\u540E\u7EED target\uFF1B--yes \u590D\u7528\u5DF2\u6709\u914D\u7F6E\uFF0C\u590D\u5236\u6574\u4E2A\u76EE\u5F55\u5373\u53EF\u3002\u811A\u672C\u6309\u5DF2\u4FDD\u5B58\u7684 SSH \u53C2\u6570\u4E0A\u4F20\u3001\u5BFC\u5165\u3001\u542F\u52A8\u5E76\u9A8C\u8BC1 HTTP\u6216HTTPS\u3002
|
|
1897
1910
|
\u90E8\u7F72\u5411\u5BFC\u53EF\u9009\u5DF2\u6709PEM\u8BC1\u4E66\u4E0E\u79C1\u94A5\u8DEF\u5F84\uFF08\u76F8\u5BF9\u5DE5\u7A0B\u6839\uFF0C\u6821\u9A8C\u540E\u590D\u5236\u5230\u79C1\u6709\u5305\uFF09\u6216Let\u2019s Encrypt\u3002\u5B98\u65B9Certbot\u7533\u8BF7\u5E76\u6BCF12\u5C0F\u65F6\u68C0\u67E5\u7EED\u671F\uFF0CNginx\u81EA\u52A8\u91CD\u8F7D\uFF1B\u9700\u8981\u6761\u6B3E\u786E\u8BA4\u3001\u771F\u5B9E\u90AE\u7BB1\u3001\u516C\u7F51DNS\u300180\u7AEF\u53E3\u53CACA\u7F51\u7EDC\u3002HTTPS\u9ED8\u8BA4443\u3001HTTP\u8DF3\u8F6C\u5F00\u542F\uFF0C\u672A\u914D\u7F6E\u4ECD\u4E3AHTTP\uFF1B\u542F\u505C\u6216\u6539\u6A21\u5F0F/\u57DF\u540D/\u7AEF\u53E3/\u672C\u5730\u8BC1\u4E66\u987B\u5168\u91CF\u3002\u8BC1\u4E66\u72B6\u6001\u4FDD\u7559\u5728\u670D\u52A1\u5668\u5E76\u5907\u4EFD\uFF0C\u9694\u79BB\u76EE\u6807\u4F7F\u7528\u5DF2\u6709\u8BC1\u4E66\u3002--plan\u4E2D\u7684root\u8868\u793A\u5DE5\u7A0B\u6839\uFF0CserviceDir\u8868\u793A\u90E8\u7F72\u670D\u52A1\u6E90\u7801\u4E0E\u914D\u7F6E\u76EE\u5F55\u3002
|
|
1898
1911
|
\u5B8C\u5168\u9694\u79BB\u65F6\u590D\u5236\u6574\u4E2A\u4EA4\u4ED8\u76EE\u5F55\uFF0C\u8FD0\u884C sh deploy-local.sh \u81EA\u52A8\u89E3\u5305\u5E76\u90E8\u7F72\uFF1B\u53EF\u4F20\u5165\u90E8\u7F72\u76EE\u5F55\u8986\u76D6\u9ED8\u8BA4\u4F4D\u7F6E\u3002
|
|
1899
|
-
Node\u540E\u7AEF\
|
|
1912
|
+
Node \u540E\u7AEF\u542F\u52A8\u65F6\u8BFB\u53D6\u670D\u52A1\u5668 config/.env.runtime\uFF0C\u5E94\u7528\u914D\u7F6E\u548C\u6258\u7BA1\u8FDE\u63A5\u5408\u5E76\u5728\u6B64\uFF1B\u4FEE\u6539\u7EC6\u9879\u540E\u91CD\u542F\u540E\u7AEF\u5373\u53EF\u3002\u540C\u6E90\u7EC6\u9879\u8986\u76D6 JSON\uFF0C\u914D\u7F6E\u76EE\u5F55\u53EA\u8BFB\u6302\u8F7D\u5230 /run/hai/config\uFF0C\u539F\u5B50\u66FF\u6362\u6587\u4EF6\u4E5F\u80FD\u8BFB\u53D6\u3002\u5F52\u6863\u4EC5\u6709 apply.sh\u3001manifest.json\u3001config/\u3001images/\u3001.hai/ \u4E94\u4E2A\u9876\u5C42\u5165\u53E3\uFF1B\u5B8C\u6574 Compose\u3001\u52A0\u8F7D\u5668\u3001\u539F\u751F\u73AF\u5883\u3001\u4EE3\u7406/TLS\u3001\u7B56\u7565\u548C\u6821\u9A8C\u548C\u4F4D\u4E8E .hai/\uFF0C\u8F85\u52A9\u811A\u672C\u5185\u5D4C apply.sh\u3002Web/\u4E2D\u95F4\u4EF6\u5C40\u90E8\u66F4\u65B0\u4FDD\u7559\u5E94\u7528\u6587\u4EF6\uFF0C\u5931\u8D25\u5148\u6062\u590D\u5E94\u7528\u914D\u7F6E\u518D\u6062\u590D\u670D\u52A1\uFF1B\u957F\u671F\u4FEE\u6539\u540C\u6B65\u6E90\u73AF\u5883\u3002\u7AEF\u53E3\u3001\u6302\u8F7D\u3001Node \u542F\u52A8\u53C2\u6570\u548C\u4EE3\u7406\u53D8\u66F4\u9700\u90E8\u7F72\u3002
|
|
1900
1913
|
\u90E8\u5206\u66F4\u65B0\u8981\u6C42\u5DF2\u6709\u6210\u529F\u7684\u5B8C\u6574\u90E8\u7F72\uFF0C\u4FDD\u7559\u672A\u9009\u670D\u52A1\u53CA\u6570\u636E\u5377\uFF1B\u5931\u8D25\u8FD4\u56DE\u975E\u96F6\u9000\u51FA\u7801\uFF0C\u5DF2\u6709\u90E8\u7F72\u5C1D\u8BD5\u6062\u590D\u9009\u4E2D\u670D\u52A1\u3002
|
|
1901
1914
|
\u4E2D\u95F4\u4EF6\u8FDE\u63A5\u9F50\u5168\u65F6\u4F7F\u7528 --skip-middleware \u8DF3\u8FC7\u914D\u7F6E\u5411\u5BFC\u3002\u5305\u4E2D\u5305\u542B\u79C1\u6709\u914D\u7F6E\uFF0C\u4E0D\u63D0\u4EA4 Git\u3002
|
|
1902
1915
|
`;
|
|
@@ -1905,7 +1918,7 @@ function generateReadme(name, appTypeLabel, pm, appType) {
|
|
|
1905
1918
|
const install = getInstallCommand(pm);
|
|
1906
1919
|
const staticWebsite = appType === "website" ? `### \u9759\u6001\u7F51\u7AD9\u4E0E GitHub Pages
|
|
1907
1920
|
|
|
1908
|
-
\u9ED8\u8BA4\u4F7F\u7528Node SSR\uFF0C\
|
|
1921
|
+
\u9ED8\u8BA4\u4F7F\u7528Node SSR\uFF0C\u53EA\u5B89\u88C5\u5C55\u793A\u529F\u80FD\u6240\u9700\u7684Core/Kit/UI\uFF0C\u53EF\u76F4\u63A5\u5207\u6362\u9759\u6001\u53D1\u5E03\uFF1B\u5B8C\u6574\u6CE8\u91CA\u914D\u7F6E\u4E0D\u542F\u7528\u6A21\u5757\u3002\u540E\u7EED\u65B0\u589E\u7684\u670D\u52A1\u7AEF\u4E1A\u52A1\u4F9D\u8D56\u3001\u521D\u59CB\u5316\u53CAAPI/actions\u987B\u5148\u79FB\u9664\uFF0C\u5DF2\u6709\u52A8\u6001\u6A21\u5757\u4E0D\u80FD\u4EC5\u6253\u5F00\u5F00\u5173\u9759\u6001\u53D1\u5E03\u3002
|
|
1909
1922
|
|
|
1910
1923
|
\`HAI_BUILD_STATIC=1\`\u663E\u5F0F\u9884\u6E32\u67D3\uFF0C\`PUBLIC_BASE_PATH=/${name}\`\u6307\u5B9A\u9879\u76EE\u7AD9\u76EE\u5F55\uFF08\u65E0\u672B\u5C3E/\uFF0C\u6839\u7AD9\u7559\u7A7A\uFF09\uFF1B\u5728PowerShell\u8BBE\u7F6E\u672C\u6B21\u6784\u5EFA\u73AF\u5883\uFF1A
|
|
1911
1924
|
|
|
@@ -2079,7 +2092,7 @@ Web/App/Desktop \u5171\u4EAB AppShell \u7684 header/footer\u3002\u65B0\u589E\u98
|
|
|
2079
2092
|
|
|
2080
2093
|
${hasFeedback ? "\u666E\u901A\u6210\u5458\u548C\u4E1A\u52A1\u64CD\u4F5C\u5458\u53EF\u4ECE\u9876\u90E8\u201C\u95EE\u9898\u53CD\u9988\u201D\u63D0\u4EA4\u8BF4\u660E\u3001\u622A\u56FE\u4E0E\u65E5\u5FD7\uFF1B\u53EA\u6709 business_operator \u663E\u793A\u53CD\u9988\u7BA1\u7406\u83DC\u5355\u5E76\u80FD\u67E5\u770B\u3001\u5904\u7406\u3001\u64A4\u9500\u548C\u5BFC\u51FA\u95EE\u9898\u5305\u3002\u670D\u52A1\u7AEF\u7EE7\u7EED\u6309\u53EF\u4FE1\u8EAB\u4EFD\u4E0E\u5E94\u7528\u8303\u56F4\u6388\u6743\u3002\u5F00\u53D1\u901A\u77E5\u4F7F\u7528 Console\uFF0C\u751F\u4EA7\u987B\u5728 _feedback.yml \u4E0E _reach.yml \u914D\u7F6E\u6536\u4EF6\u4EBA\u548C\u771F\u5B9E\u90AE\u4EF6\u3002" : ""}
|
|
2081
2094
|
|
|
2082
|
-
CLI \u5728\u6839\u76EE\u5F55 .env.dev\u3001.env.test\u3001.env.prod \u4E2D\u4E3A admin\u3001audit_admin\u3001config_admin\u3001business_operator \u5206\u522B\u751F\u6210\u72EC\u7ACB\u968F\u673A\u5F3A\u5BC6\u7801\uFF0C\u5BF9\u5E94 HAI_ADMIN_DEFAULT_PASSWORD\u3001HAI_AUDIT_ADMIN_PASSWORD\u3001HAI_CONFIG_ADMIN_PASSWORD\u3001HAI_BUSINESS_OPERATOR_PASSWORD\u3002\
|
|
2095
|
+
CLI \u5728\u6839\u76EE\u5F55 .env.dev.local\u3001.env.test.local\u3001.env.prod.local \u4E2D\u4E3A admin\u3001audit_admin\u3001config_admin\u3001business_operator \u5206\u522B\u751F\u6210\u72EC\u7ACB\u968F\u673A\u5F3A\u5BC6\u7801\uFF0C\u5BF9\u5E94 HAI_ADMIN_DEFAULT_PASSWORD\u3001HAI_AUDIT_ADMIN_PASSWORD\u3001HAI_CONFIG_ADMIN_PASSWORD\u3001HAI_BUSINESS_OPERATOR_PASSWORD\u3002\u8FD9\u4E9B\u79C1\u6709\u6587\u4EF6\u4E0D\u63D0\u4EA4 Git\uFF1B\u514B\u9686\u540E\u901A\u8FC7\u53D7\u4FDD\u62A4\u914D\u7F6E\u6216 Secret Manager \u5206\u53D1\u5BF9\u5E94\u73AF\u5883\u79D8\u5BC6\uFF0C\u540C\u4E00\u73AF\u5883\u5404\u8282\u70B9\u5171\u4EAB\u3002\u5171\u4EAB .env.local \u6216\u8FDB\u7A0B\u53D8\u91CF\u53EF\u8986\u76D6\u516C\u5171\u503C\uFF0C\u6A21\u5F0F\u79C1\u6709\u6587\u4EF6\u4F18\u5148\u4E8E\u5171\u4EAB\u79C1\u6709\u6587\u4EF6\u3002\u5DF2\u6709\u8D26\u53F7\u4E0D\u6539\u5BC6\u3001\u4E0D\u91CD\u65B0\u5206\u914D\u804C\u8D23\uFF1B\u672A\u914D\u7F6E\u5BC6\u7801\u7684\u72EC\u7ACB\u804C\u8D23\u8D26\u53F7\u4E0D\u521B\u5EFA\u3002\u5BC6\u7801\u987B\u7B26\u5408 _iam.yml \u7B56\u7565\uFF1B\u542F\u52A8\u5931\u8D25\u4FDD\u7559\u6A21\u5757\u3001\u914D\u7F6E\u5B57\u6BB5\u3001\u9519\u8BEF\u7801\u548C\u7AEF\u53E3\u5360\u7528\u8BCA\u65AD\u3002
|
|
2083
2096
|
|
|
2084
2097
|
\`_iam.yml\` \u53EF\u6309\u4E1A\u52A1\u542F\u7528\u8D26\u53F7\u95F2\u7F6E\u626B\u63CF\u3001\u5BC6\u7801\u590D\u6742\u5EA6/\u671F\u9650\u3001ALTCHA \u6311\u6218\u3001\u5931\u8D25\u7A97\u53E3\u9501\u5B9A\u3001\u4E00\u6B21\u6027\u9080\u8BF7\u3001\u9996\u6B21\u6539\u5BC6\u3001\u654F\u611F\u64CD\u4F5C\u518D\u8BA4\u8BC1\u3001\u767B\u5F55\u65F6\u95F4/IP \u548C\u4F1A\u8BDD\u671F\u9650/\u5E76\u53D1\u7B56\u7565\u3002\u654F\u611F\u64CD\u4F5C\u6E05\u5355\u4F7F\u7528\u670D\u52A1\u7AEF\u64CD\u4F5C\u6807\u8BC6\uFF1B\u754C\u9762\u901A\u8FC7\u77ED\u671F\u5355\u6B21\u7968\u636E\u5B8C\u6210\u518D\u8BA4\u8BC1\u3002\`session.endOnPageHide\` \u9ED8\u8BA4\u5173\u95ED\uFF0C\u5F00\u542F\u65F6\u9875\u9762\u79BB\u5F00\u5C1D\u8BD5\u64A4\u9500\uFF0C\u4F46\u6D4F\u89C8\u5668\u901A\u77E5\u4EC5\u6700\u4F73\u52AA\u529B\uFF0C\u9700\u914D\u5408\u670D\u52A1\u7AEF\u95F2\u7F6E/\u7EDD\u5BF9\u671F\u9650\u3002\`_audit.yml\` \u914D\u7F6E\u4FDD\u7559\u4FDD\u62A4\u3001\u79C1\u6709\u5907\u4EFD\u53CA Reach \u544A\u8B66\uFF1B\u624B\u52A8\u5907\u4EFD\u5931\u8D25\u590D\u7528\u540C\u4E00\u7F16\u53F7\u91CD\u8BD5\uFF0C\u56DE\u6267\u542B key/\u8BB0\u5F55\u6570/SHA-256\uFF0C\u4E0D\u516C\u5F00\u4E0B\u8F7D\u3002\u5F52\u6863\u4E0D\u662F\u539F\u5B50\u6570\u636E\u5E93\u5FEB\u7167\uFF0C\u4E25\u683C\u6062\u590D\u987B\u6682\u505C\u5199\u5165/\u6E05\u7406\u6216\u4F7F\u7528\u539F\u751F\u5907\u4EFD\uFF0C\u5728\u72EC\u7ACB\u73AF\u5883\u6838\u9A8C\u6062\u590D\u3002
|
|
2085
2098
|
|
|
@@ -2087,7 +2100,7 @@ CLI \u5728\u6839\u76EE\u5F55 .env.dev\u3001.env.test\u3001.env.prod \u4E2D\u4E3A
|
|
|
2087
2100
|
|
|
2088
2101
|
\u672C\u5730\u5F00\u53D1\u9ED8\u8BA4 \`PUBLIC_API_BASE=http://127.0.0.1:3000\`\uFF0CVite \u4F7F\u7528\u540C\u6E90\u4EE3\u7406\uFF1B\u90E8\u7F72\u65F6\u6539\u4E3A\u5B9E\u9645\u516C\u7F51 API Origin\uFF0CAndroid \u6A21\u62DF\u5668\u8BBF\u95EE\u5BBF\u4E3B\u673A\u65F6\u4F7F\u7528 \`http://10.0.2.2:3000\`\u3002\u4E0D\u8981\u5C06\u5BC6\u94A5\u653E\u5165\u4EFB\u4F55 \`PUBLIC_\` \u6216 \`VITE_\` \u53D8\u91CF\u3002
|
|
2089
2102
|
|
|
2090
|
-
\u670D\u52A1\u7AEF\u7248\u672C\u5316\u4F20\u8F93\u5BC6\u94A5\u73AF\u5728\u521B\u5EFA\u65F6\u5206\u522B\u5199\u5165 \`.env.dev\`\u3001\`.env.test\`\u3001\`.env.prod\`\uFF0C\u53D8\u91CF\u4E3A \`HAI_CRYPTO_TRANSPORT_SERVERKEYRING\`\uFF0C\u5404\u73AF\u5883\u5BC6\u94A5\u4E0D\u540C\uFF1B\u8FD0\u884C\u65F6\u4E0D\u751F\u6210\u5BC6\u94A5\u3002\u540C\u4E00\u73AF\u5883\u7684\u6240\u6709\u8282\u70B9\u4F7F\u7528\u540C\u4E00 ring \u548C\u5171\u4EAB registry\uFF0C\u4E5F\u53EF\u901A\u8FC7\u8FDB\u7A0B\u73AF\u5883\u6216 Secret Manager \u8986\u76D6\u3002\u79C1\u94A5\u4E0D\u8FDB\u5165 PUBLIC_/VITE_\u3001\u65E5\u5FD7\u6216\u6D4F\u89C8\u5668\u3002
|
|
2103
|
+
\u670D\u52A1\u7AEF\u7248\u672C\u5316\u4F20\u8F93\u5BC6\u94A5\u73AF\u5728\u521B\u5EFA\u65F6\u5206\u522B\u5199\u5165\u4E0D\u63D0\u4EA4 Git \u7684 \`.env.dev.local\`\u3001\`.env.test.local\`\u3001\`.env.prod.local\`\uFF0C\u53D8\u91CF\u4E3A \`HAI_CRYPTO_TRANSPORT_SERVERKEYRING\`\uFF0C\u5404\u73AF\u5883\u5BC6\u94A5\u4E0D\u540C\uFF1B\u8FD0\u884C\u65F6\u4E0D\u751F\u6210\u5BC6\u94A5\u3002\u540C\u4E00\u73AF\u5883\u7684\u6240\u6709\u8282\u70B9\u4F7F\u7528\u540C\u4E00 ring \u548C\u5171\u4EAB registry\uFF0C\u4E5F\u53EF\u901A\u8FC7\u8FDB\u7A0B\u73AF\u5883\u6216 Secret Manager \u8986\u76D6\u3002\u79C1\u94A5\u4E0D\u8FDB\u5165 PUBLIC_/VITE_\u3001\u65E5\u5FD7\u6216\u6D4F\u89C8\u5668\u3002
|
|
2091
2104
|
|
|
2092
2105
|
\u6240\u6709\u4E1A\u52A1 JSON \u8BF7\u6C42\u548C\u54CD\u5E94\u9ED8\u8BA4\u901A\u8FC7 \`@h-ai/crypto\` transport \u53CC\u5411\u52A0\u5BC6\uFF08\u542B\u767B\u5F55\u3001\u5237\u65B0\u3001\u5934\u50CF\u4E0A\u4F20\uFF09\uFF1B\u524D\u7AEF\u7EDF\u4E00\u4F7F\u7528\u5171\u4EAB typed API client\u3002Web \u8BBF\u95EE\u4EE4\u724C\u4EC5\u5B58\u5185\u5B58\u3001\u5237\u65B0\u4EE4\u724C\u7531 HttpOnly Cookie \u4FDD\u5B58\uFF1B\u53D7\u4FE1\u539F\u751F\u7AEF\u4F7F\u7528\u5E73\u53F0\u5B89\u5168\u5B58\u50A8\u6216\u5185\u5B58\u3002\u5934\u50CF\u4E3A\u968F\u673A\u8DEF\u5F84\u53EA\u8BFB\u56FE\u7247\u8D44\u6E90\uFF0C\u652F\u6301 PNG/JPEG/WebP\uFF0C\u6700\u5927 512 KiB\u3002\u5065\u5EB7\u68C0\u67E5\u548C\u53EA\u8BFB\u5934\u50CF\u56FE\u7247\u53EF\u76F4\u63A5\u8BBF\u95EE\u3002
|
|
2093
2106
|
|
|
@@ -2095,7 +2108,7 @@ CLI \u5728\u6839\u76EE\u5F55 .env.dev\u3001.env.test\u3001.env.prod \u4E2D\u4E3A
|
|
|
2095
2108
|
|
|
2096
2109
|
### \u914D\u7F6E\u6269\u5C55
|
|
2097
2110
|
|
|
2098
|
-
\u670D\u52A1\u7AEF \`packages/${name}-serv/config/\` \u59CB\u7EC8\u4FDD\u7559 core\u3001serv\u3001db\u3001cache\u3001iam\u3001storage\u3001audit\u3001reach\u3001ai\u3001vecdb\u3001payment\u3001scheduler\u3001feedback \u5171
|
|
2111
|
+
\u670D\u52A1\u7AEF \`packages/${name}-serv/config/\` \u59CB\u7EC8\u4FDD\u7559 core\u3001serv\u3001kit\u3001db\u3001cache\u3001iam\u3001storage\u3001audit\u3001reach\u3001ai\u3001vecdb\u3001payment\u3001scheduler\u3001feedback \u5171 14 \u4EFD YAML\uFF1B\u6784\u5EFA\u90E8\u7F72\u914D\u7F6E\u7EDF\u4E00\u4F4D\u4E8E\u9879\u76EE\u6839 hai.json\u3002\u53EA\u5B89\u88C5\u7BA1\u7406\u540E\u53F0\u5B9E\u9645\u4F7F\u7528\u7684\u6A21\u5757\uFF1B\u5DF2\u7528\u6A21\u5757\u4FDD\u7559\u5DE5\u4F5C\u9ED8\u8BA4\u503C\uFF0C\u672A\u542F\u7528\u6A21\u5757\u6574\u4EFD\u6CE8\u91CA\uFF0C\u53EF\u9009\u5B57\u6BB5\u548C\u66FF\u4EE3 Provider \u6309\u5757\u6CE8\u91CA\uFF1B\u6839 \`.env.example\` \u4E5F\u4FDD\u7559\u672A\u542F\u7528\u6A21\u5757\u7684\u51ED\u636E\u793A\u4F8B\u3002\u65B0\u589E\u529F\u80FD\u65F6\u5B89\u88C5\u4F9D\u8D56\u5E76\u63A5\u5165\u521D\u59CB\u5316\u3001\u5173\u95ED\u53CA\u4E1A\u52A1\u4EE3\u7801\u3002Reach \u9ED8\u8BA4\u4E3A\u5F00\u53D1\u63A7\u5236\u53F0\u901A\u77E5\uFF0Cfeedback \u4F7F\u7528 email \u522B\u540D\uFF1B\u751F\u4EA7\u6309 \`_reach.yml\` \u6CE8\u91CA\u66FF\u6362\u4E3A SMTP\u3001\u77ED\u4FE1\u6216 API Provider\uFF0C\u5E76\u4FDD\u6301\u540D\u79F0\u552F\u4E00\u3002
|
|
2099
2112
|
|
|
2100
2113
|
\u81EA\u52A8\u751F\u6210\u7684 \`.env\` \u5305\u542B\u5DF2\u542F\u7528\u6A21\u5757\u7684\u73AF\u5883\u53C2\u6570\uFF1BYAML \u663E\u5F0F\u5F15\u7528\u76F8\u540C\u53D8\u91CF\u5E76\u4FDD\u7559\u672C\u5730\u56DE\u9000\u3002\u7F16\u8F91\u73AF\u5883\u53C2\u6570\u4F18\u5148\u4FEE\u6539\u5BF9\u5E94 \`.env\`\uFF1B\u672A\u542F\u7528\u6A21\u5757\u4ECD\u4FDD\u7559\u6CE8\u91CA\u3002
|
|
2101
2114
|
|
|
@@ -2332,7 +2345,7 @@ async function addModule(options) {
|
|
|
2332
2345
|
writeCliMessage(cliM("cli_addAvailableModules", { params: { modules: Object.keys(MODULE_MAP).join(", ") } }));
|
|
2333
2346
|
return;
|
|
2334
2347
|
}
|
|
2335
|
-
const { generateProjectAiSupport, resolveSkillNamesForPackages } = await import('./cli-skill-templates-
|
|
2348
|
+
const { generateProjectAiSupport, resolveSkillNamesForPackages } = await import('./cli-skill-templates-S2YH642Z.js');
|
|
2336
2349
|
if (moduleDef.packages.every((p) => project.haiPackages.includes(p))) {
|
|
2337
2350
|
if (moduleName === "deploy")
|
|
2338
2351
|
await ensureDeployConfig(cwd);
|
|
@@ -2454,7 +2467,7 @@ ${production.join("\n")}`);
|
|
|
2454
2467
|
}
|
|
2455
2468
|
}
|
|
2456
2469
|
async function buildMobileApp(root, directories, platform, run2) {
|
|
2457
|
-
if (!directories.length || platform === "ios" &&
|
|
2470
|
+
if (!directories.length || platform === "ios" && process5.platform !== "darwin")
|
|
2458
2471
|
throw new Error(cliM("cli_build_app_platform"));
|
|
2459
2472
|
const outputs = [];
|
|
2460
2473
|
for (const item of directories) {
|
|
@@ -2492,31 +2505,240 @@ async function buildMobileApp(root, directories, platform, run2) {
|
|
|
2492
2505
|
}
|
|
2493
2506
|
return outputs;
|
|
2494
2507
|
}
|
|
2508
|
+
function object(value) {
|
|
2509
|
+
if (value === void 0)
|
|
2510
|
+
return {};
|
|
2511
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
2512
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2513
|
+
return value;
|
|
2514
|
+
}
|
|
2515
|
+
function registryUrl(value) {
|
|
2516
|
+
try {
|
|
2517
|
+
if (typeof value !== "string")
|
|
2518
|
+
throw new Error("Missing registry");
|
|
2519
|
+
const url = new URL(value);
|
|
2520
|
+
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.search || url.hash)
|
|
2521
|
+
throw new Error("Invalid registry");
|
|
2522
|
+
return url.toString().replace(/\/$/, "");
|
|
2523
|
+
} catch {
|
|
2524
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2525
|
+
}
|
|
2526
|
+
}
|
|
2527
|
+
async function resolveBuildDownloads(directory, options) {
|
|
2528
|
+
const path10 = projectConfigPath(directory);
|
|
2529
|
+
const project = readProjectConfig(path10);
|
|
2530
|
+
const build = object(project.build);
|
|
2531
|
+
const sources = object(build.sources);
|
|
2532
|
+
const savedImage = object(sources.image);
|
|
2533
|
+
const savedNpm = object(sources.npm);
|
|
2534
|
+
const savedProxy = object(build.proxy);
|
|
2535
|
+
const interactive = !!process5.stdin.isTTY && !options.yes;
|
|
2536
|
+
const choose = async (message, values) => {
|
|
2537
|
+
const answer = await prompts({ type: "select", name: "value", message, choices: values.map((value) => ({ title: cliM(`cli_download_${value}`), value })) });
|
|
2538
|
+
if (typeof answer.value !== "string")
|
|
2539
|
+
throw new Error(cliM("cli_deploy_cancelled"));
|
|
2540
|
+
return answer.value;
|
|
2541
|
+
};
|
|
2542
|
+
const mirrorEntries = options.imageMirrors?.split(",").map((entry) => {
|
|
2543
|
+
const separator = entry.indexOf("=");
|
|
2544
|
+
if (separator <= 0 || separator === entry.length - 1)
|
|
2545
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2546
|
+
return [entry.slice(0, separator).trim(), entry.slice(separator + 1).trim()];
|
|
2547
|
+
});
|
|
2548
|
+
if (mirrorEntries && new Set(mirrorEntries.map(([key]) => key)).size !== mirrorEntries.length)
|
|
2549
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2550
|
+
let imageType = options.imageSource ?? (mirrorEntries ? "custom" : savedImage.type);
|
|
2551
|
+
let npmType = options.npmSource ?? (options.npmRegistry ? "custom" : savedNpm.type);
|
|
2552
|
+
const saveImage = imageType === void 0 && interactive;
|
|
2553
|
+
const saveNpm = npmType === void 0 && interactive;
|
|
2554
|
+
if (saveImage)
|
|
2555
|
+
imageType = await choose(cliM("cli_download_choose_image"), ["official", "cn", "custom"]);
|
|
2556
|
+
if (saveNpm)
|
|
2557
|
+
npmType = await choose(cliM("cli_download_choose_npm"), ["official", "cn", "custom"]);
|
|
2558
|
+
imageType ??= "official";
|
|
2559
|
+
npmType ??= "official";
|
|
2560
|
+
if (typeof imageType !== "string" || !["official", "cn", "custom"].includes(imageType) || typeof npmType !== "string" || !["official", "cn", "custom"].includes(npmType))
|
|
2561
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2562
|
+
let registries = mirrorEntries ? Object.fromEntries(mirrorEntries) : savedImage.registries;
|
|
2563
|
+
if (imageType === "custom" && !registries && interactive) {
|
|
2564
|
+
const answer = await prompts({ type: "text", name: "value", message: cliM("cli_download_image_mirrors") });
|
|
2565
|
+
if (typeof answer.value !== "string" || !answer.value.trim())
|
|
2566
|
+
throw new Error(cliM("cli_deploy_cancelled"));
|
|
2567
|
+
registries = Object.fromEntries(answer.value.split(",").map((entry) => {
|
|
2568
|
+
const index = entry.indexOf("=");
|
|
2569
|
+
if (index <= 0)
|
|
2570
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2571
|
+
return [entry.slice(0, index).trim(), entry.slice(index + 1).trim()];
|
|
2572
|
+
}));
|
|
2573
|
+
}
|
|
2574
|
+
const mappings = registries === void 0 ? void 0 : object(registries);
|
|
2575
|
+
if (mappings && Object.entries(mappings).some(([key, value]) => !/^[\w.-]+(?::\d+)?$/.test(key) || typeof value !== "string"))
|
|
2576
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2577
|
+
const imageSource = { type: imageType, ...imageType === "custom" ? { registries: mappings } : {} };
|
|
2578
|
+
if (mirrorEntries && imageType !== "custom")
|
|
2579
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2580
|
+
if (imageType === "custom") {
|
|
2581
|
+
if (!mappings || !Object.keys(mappings).length)
|
|
2582
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2583
|
+
for (const key of Object.keys(mappings)) resolveImageReference(`${key}/hai-source-check:1`, imageSource);
|
|
2584
|
+
}
|
|
2585
|
+
let customRegistry = options.npmRegistry ?? savedNpm.registry;
|
|
2586
|
+
if (npmType === "custom" && !customRegistry && interactive) {
|
|
2587
|
+
const answer = await prompts({ type: "text", name: "value", message: cliM("cli_download_npm_registry") });
|
|
2588
|
+
if (typeof answer.value !== "string" || !answer.value.trim())
|
|
2589
|
+
throw new Error(cliM("cli_deploy_cancelled"));
|
|
2590
|
+
customRegistry = answer.value;
|
|
2591
|
+
}
|
|
2592
|
+
if (options.npmRegistry && npmType !== "custom")
|
|
2593
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2594
|
+
const npmRegistry = npmType === "cn" ? "https://registry.npmmirror.com" : npmType === "official" ? "https://registry.npmjs.org" : registryUrl(customRegistry);
|
|
2595
|
+
const npmSource = { type: npmType, ...npmType === "custom" ? { registry: npmRegistry } : {} };
|
|
2596
|
+
let proxyMode = options.proxyMode ?? (options.proxyUrl ? "custom" : savedProxy.mode);
|
|
2597
|
+
const saveProxy = proxyMode === void 0 && interactive && options.httpProxy !== false;
|
|
2598
|
+
if (saveProxy)
|
|
2599
|
+
proxyMode = await choose(cliM("cli_download_choose_proxy"), ["inherit", "system", "custom", "none"]);
|
|
2600
|
+
proxyMode ??= "inherit";
|
|
2601
|
+
if (options.proxyUrl !== void 0 && proxyMode !== "custom")
|
|
2602
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2603
|
+
if (typeof proxyMode !== "string" || !["inherit", "system", "custom", "none"].includes(proxyMode))
|
|
2604
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2605
|
+
if (options.httpProxy === false && (options.proxyUrl !== void 0 || options.proxyMode !== void 0 && options.proxyMode !== "none"))
|
|
2606
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2607
|
+
let proxyUrl = options.proxyUrl ?? savedProxy.url;
|
|
2608
|
+
if (proxyMode === "custom" && !proxyUrl && interactive) {
|
|
2609
|
+
const answer = await prompts({ type: "text", name: "value", message: cliM("cli_download_proxy_url") });
|
|
2610
|
+
if (typeof answer.value !== "string" || !answer.value.trim())
|
|
2611
|
+
throw new Error(cliM("cli_deploy_cancelled"));
|
|
2612
|
+
proxyUrl = answer.value;
|
|
2613
|
+
}
|
|
2614
|
+
const bypass = options.proxyBypass ?? savedProxy.bypass;
|
|
2615
|
+
if (proxyUrl !== void 0 && typeof proxyUrl !== "string" || bypass !== void 0 && typeof bypass !== "string")
|
|
2616
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2617
|
+
const proxy = { mode: options.httpProxy === false ? "none" : proxyMode, ...proxyMode === "custom" && options.httpProxy !== false ? { url: proxyUrl } : {}, ...bypass !== void 0 ? { bypass } : {} };
|
|
2618
|
+
resolveDownloadProxy(proxy);
|
|
2619
|
+
if (saveImage || saveNpm || saveProxy) {
|
|
2620
|
+
project.build = { ...build, sources: { ...sources, ...saveImage ? { image: imageSource } : {}, ...saveNpm ? { npm: npmSource } : {} }, ...saveProxy ? { proxy } : {} };
|
|
2621
|
+
writeFileSync(path10, `${JSON.stringify(project, null, 2)}
|
|
2622
|
+
`);
|
|
2623
|
+
}
|
|
2624
|
+
return { imageSource, npmRegistry, npmSource, proxy };
|
|
2625
|
+
}
|
|
2626
|
+
function buildProxyArguments(proxy, runtime, network) {
|
|
2627
|
+
const environment = resolveDownloadProxy(proxy);
|
|
2628
|
+
for (const key of ["HTTP_PROXY", "HTTPS_PROXY", "http_proxy", "https_proxy", "ALL_PROXY", "all_proxy"]) {
|
|
2629
|
+
if (!environment[key])
|
|
2630
|
+
continue;
|
|
2631
|
+
const url = new URL(environment[key]);
|
|
2632
|
+
if (network !== "host" && (runtime === "docker" || network !== void 0) && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname)) {
|
|
2633
|
+
url.hostname = runtime === "podman" ? "host.containers.internal" : "host.docker.internal";
|
|
2634
|
+
environment[key] = url.toString().replace(/\/$/, "");
|
|
2635
|
+
}
|
|
2636
|
+
}
|
|
2637
|
+
return Object.entries(environment).flatMap(([key, value]) => ["--build-arg", `${key}=${value}`]);
|
|
2638
|
+
}
|
|
2639
|
+
async function preflightDownloadProxy(runtime, proxy) {
|
|
2640
|
+
const environment = resolveDownloadProxy(proxy);
|
|
2641
|
+
for (const value of new Set([environment.HTTP_PROXY, environment.HTTPS_PROXY].filter(Boolean))) {
|
|
2642
|
+
const url = new URL(value);
|
|
2643
|
+
await new Promise((resolve7, reject) => {
|
|
2644
|
+
const socket = connect({ host: url.hostname.replace(/^\[|\]$/g, ""), port: Number(url.port || (url.protocol === "https:" ? 443 : 80)) });
|
|
2645
|
+
socket.setTimeout(3e3);
|
|
2646
|
+
socket.once("connect", () => {
|
|
2647
|
+
socket.destroy();
|
|
2648
|
+
resolve7();
|
|
2649
|
+
});
|
|
2650
|
+
const fail = () => {
|
|
2651
|
+
socket.destroy();
|
|
2652
|
+
reject(new Error(cliM("cli_download_proxy_unreachable")));
|
|
2653
|
+
};
|
|
2654
|
+
socket.once("error", fail);
|
|
2655
|
+
socket.once("timeout", fail);
|
|
2656
|
+
});
|
|
2657
|
+
}
|
|
2658
|
+
if (!environment.HTTP_PROXY && !environment.HTTPS_PROXY)
|
|
2659
|
+
return;
|
|
2660
|
+
for (const candidate of runtime === "auto" ? ["podman", "docker"] : [runtime]) {
|
|
2661
|
+
try {
|
|
2662
|
+
const data = JSON.parse(execFileSync(candidate, ["info", "--format", "{{json .}}"], { encoding: "utf8", windowsHide: true, timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }));
|
|
2663
|
+
writeCliMessage(cliM(candidate === "docker" && (data.HTTPProxy || data.HTTPSProxy) ? "cli_download_engine_proxy_configured" : candidate === "podman" && !data.host?.serviceIsRemote ? "cli_download_engine_proxy_local" : "cli_download_engine_proxy_hint", { params: { runtime: candidate } }));
|
|
2664
|
+
return;
|
|
2665
|
+
} catch {
|
|
2666
|
+
}
|
|
2667
|
+
}
|
|
2668
|
+
writeCliMessage(cliM("cli_download_engine_proxy_hint", { params: { runtime } }));
|
|
2669
|
+
}
|
|
2670
|
+
function validateDownloadDockerfile(file, downloads) {
|
|
2671
|
+
const content = readFileSync(file, "utf8");
|
|
2672
|
+
if (downloads.imageSource.type !== "official" && !/^ARG HAI_NODE_IMAGE=/m.test(content) || downloads.npmSource.type !== "official" && !/^ARG HAI_NPM_REGISTRY[=\s]/m.test(content)) {
|
|
2673
|
+
throw new Error(cliM("cli_download_template_required", { params: { path: file } }));
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
function createWindowsBuildOutput() {
|
|
2677
|
+
const decoder = new StringDecoder("utf8");
|
|
2678
|
+
let previousCarriageReturn = false;
|
|
2679
|
+
const normalize = (value) => {
|
|
2680
|
+
const result = value.replace(/\n/g, (newline, offset) => (offset === 0 ? previousCarriageReturn : value[offset - 1] === "\r") ? newline : "\r\n");
|
|
2681
|
+
if (value.length)
|
|
2682
|
+
previousCarriageReturn = value.endsWith("\r");
|
|
2683
|
+
return result;
|
|
2684
|
+
};
|
|
2685
|
+
return new Transform({
|
|
2686
|
+
transform(chunk, _encoding, callback) {
|
|
2687
|
+
callback(null, normalize(decoder.write(chunk)));
|
|
2688
|
+
},
|
|
2689
|
+
flush(callback) {
|
|
2690
|
+
callback(null, normalize(decoder.end()));
|
|
2691
|
+
}
|
|
2692
|
+
});
|
|
2693
|
+
}
|
|
2694
|
+
async function forwardWindowsBuildOutput(source, destination) {
|
|
2695
|
+
const forwarding = new Writable({
|
|
2696
|
+
write(chunk, encoding, callback) {
|
|
2697
|
+
destination.write(chunk, encoding, callback);
|
|
2698
|
+
}
|
|
2699
|
+
});
|
|
2700
|
+
await pipeline(source, createWindowsBuildOutput(), forwarding);
|
|
2701
|
+
}
|
|
2495
2702
|
|
|
2496
2703
|
// src/commands/cli-build.ts
|
|
2497
2704
|
async function run(command, args, cwd, quiet = false, identity, compileEnvironment) {
|
|
2498
2705
|
await new Promise((resolve7, reject) => {
|
|
2499
|
-
const env = Object.fromEntries(Object.entries(
|
|
2706
|
+
const env = Object.fromEntries(Object.entries(process5.env).filter(([key]) => !/^(?:HAI_|PUBLIC_|VITE_)/.test(key)));
|
|
2500
2707
|
Object.assign(env, compileEnvironment);
|
|
2501
2708
|
if (identity) {
|
|
2502
2709
|
env.HAI_BUILD_ID = identity.buildId;
|
|
2503
2710
|
env.HAI_BUILD_COMMIT = identity.commit;
|
|
2504
2711
|
}
|
|
2505
2712
|
env.NODE_ENV = "production";
|
|
2713
|
+
if (process5.platform === "win32") {
|
|
2714
|
+
env.npm_config_reporter = "append-only";
|
|
2715
|
+
env.pnpm_config_reporter = "append-only";
|
|
2716
|
+
}
|
|
2506
2717
|
delete env.CAPACITOR_SERVER_URL;
|
|
2507
2718
|
if (env.CI === "1" || env.CI === "0")
|
|
2508
2719
|
env.CI = env.CI === "1" ? "true" : "false";
|
|
2509
|
-
const
|
|
2720
|
+
const windowsOutput = !quiet && process5.platform === "win32";
|
|
2721
|
+
const child = spawn(command, args, { cwd, env, windowsHide: true, stdio: quiet ? "ignore" : windowsOutput ? ["inherit", "pipe", "pipe"] : "inherit", shell: false });
|
|
2722
|
+
let output = Promise.resolve();
|
|
2723
|
+
if (windowsOutput && child.stdout && child.stderr) {
|
|
2724
|
+
output = Promise.all([
|
|
2725
|
+
forwardWindowsBuildOutput(child.stdout, process5.stdout),
|
|
2726
|
+
forwardWindowsBuildOutput(child.stderr, process5.stderr)
|
|
2727
|
+
]).then(() => void 0);
|
|
2728
|
+
void output.catch(() => child.kill());
|
|
2729
|
+
}
|
|
2510
2730
|
child.once("error", reject);
|
|
2511
|
-
child.once(
|
|
2731
|
+
child.once(windowsOutput && child.stdout && child.stderr ? "close" : "exit", (code) => {
|
|
2732
|
+
void output.then(() => code === 0 ? resolve7() : reject(new Error(cliM("cli_build_failed", { params: { command, code: String(code) } }))), reject);
|
|
2733
|
+
});
|
|
2512
2734
|
});
|
|
2513
2735
|
}
|
|
2514
2736
|
async function pnpm(args, cwd, identity, compileEnvironment) {
|
|
2515
|
-
const entry =
|
|
2737
|
+
const entry = process5.env.npm_execpath;
|
|
2516
2738
|
if (entry && /(?:^|[/\\])pnpm(?:-native)?(?:\.exe|\.[cm]?js)?$/i.test(entry))
|
|
2517
|
-
return /\.[cm]?js$/i.test(entry) ? run(
|
|
2518
|
-
if (
|
|
2519
|
-
const directories = (
|
|
2739
|
+
return /\.[cm]?js$/i.test(entry) ? run(process5.execPath, [entry, ...args], cwd, false, identity, compileEnvironment) : run(entry, args, cwd, false, identity, compileEnvironment);
|
|
2740
|
+
if (process5.platform === "win32") {
|
|
2741
|
+
const directories = (process5.env.PATH ?? "").split(";");
|
|
2520
2742
|
for (const directory of directories) {
|
|
2521
2743
|
const executable = join(directory, "pnpm.exe");
|
|
2522
2744
|
if (existsSync(executable))
|
|
@@ -2524,7 +2746,7 @@ async function pnpm(args, cwd, identity, compileEnvironment) {
|
|
|
2524
2746
|
for (const relative4 of ["node_modules/pnpm/bin/pnpm.cjs", "pnpm.cjs"]) {
|
|
2525
2747
|
const candidate = join(directory, relative4);
|
|
2526
2748
|
if (existsSync(candidate))
|
|
2527
|
-
return run(
|
|
2749
|
+
return run(process5.execPath, [candidate, ...args], cwd, false, identity, compileEnvironment);
|
|
2528
2750
|
}
|
|
2529
2751
|
}
|
|
2530
2752
|
throw new Error(cliM("cli_build_use_pnpm"));
|
|
@@ -2532,8 +2754,8 @@ async function pnpm(args, cwd, identity, compileEnvironment) {
|
|
|
2532
2754
|
return run("pnpm", args, cwd, false, identity, compileEnvironment);
|
|
2533
2755
|
}
|
|
2534
2756
|
function staticCompileEnvironment(target) {
|
|
2535
|
-
const flag =
|
|
2536
|
-
const base =
|
|
2757
|
+
const flag = process5.env.HAI_BUILD_STATIC;
|
|
2758
|
+
const base = process5.env.PUBLIC_BASE_PATH;
|
|
2537
2759
|
if (flag !== void 0 && flag !== "" && flag !== "0" && flag !== "1")
|
|
2538
2760
|
throw new Error(cliM("cli_build_static_flag"));
|
|
2539
2761
|
if (base && (!/^\/[\w.-]+(?:\/[\w.-]+)*$/.test(base) || base.split("/").some((segment) => segment === "." || segment === "..")))
|
|
@@ -2560,7 +2782,7 @@ function sourceCommit(cwd) {
|
|
|
2560
2782
|
}
|
|
2561
2783
|
}
|
|
2562
2784
|
async function buildCommand(options) {
|
|
2563
|
-
const directory = resolve(options.cwd ??
|
|
2785
|
+
const directory = resolve(options.cwd ?? process5.cwd());
|
|
2564
2786
|
const target = options.target ?? "compile";
|
|
2565
2787
|
const concurrency = Number(options.concurrency ?? 2);
|
|
2566
2788
|
if (![1, 2].includes(concurrency))
|
|
@@ -2569,7 +2791,7 @@ async function buildCommand(options) {
|
|
|
2569
2791
|
if (!["compile", "image", "desktop", "app"].includes(target))
|
|
2570
2792
|
throw new Error(cliM("cli_build_target_invalid"));
|
|
2571
2793
|
const compileEnvironment = staticCompileEnvironment(target);
|
|
2572
|
-
if (target !== "image" && (options.images !== void 0 || options.concurrency !== void 0 || options.runtime !== void 0 || options.network !== void 0 || options.sqlitePrebuildMirror !== void 0 || options.httpProxy === false) || !["desktop", "app"].includes(target) && (options.platform !== void 0 || options.arch !== void 0) || target === "app" && options.arch !== void 0) {
|
|
2794
|
+
if (target !== "image" && (options.images !== void 0 || options.concurrency !== void 0 || options.runtime !== void 0 || options.network !== void 0 || options.sqlitePrebuildMirror !== void 0 || options.httpProxy === false || options.imageSource !== void 0 || options.imageMirrors !== void 0 || options.npmSource !== void 0 || options.npmRegistry !== void 0 || options.proxyMode !== void 0 || options.proxyUrl !== void 0 || options.proxyBypass !== void 0) || !["desktop", "app"].includes(target) && (options.platform !== void 0 || options.arch !== void 0) || target === "app" && options.arch !== void 0) {
|
|
2573
2795
|
throw new Error(cliM("cli_build_options_invalid"));
|
|
2574
2796
|
}
|
|
2575
2797
|
if (target === "compile") {
|
|
@@ -2592,9 +2814,9 @@ async function buildCommand(options) {
|
|
|
2592
2814
|
}
|
|
2593
2815
|
if (target === "desktop") {
|
|
2594
2816
|
const platforms = { win32: "windows", linux: "linux", darwin: "macos" };
|
|
2595
|
-
const host = platforms[
|
|
2817
|
+
const host = platforms[process5.platform];
|
|
2596
2818
|
const platform = options.platform ?? host;
|
|
2597
|
-
const arch = options.arch ??
|
|
2819
|
+
const arch = options.arch ?? process5.arch;
|
|
2598
2820
|
if (!platform || platform !== host || !["x64", "arm64"].includes(arch))
|
|
2599
2821
|
throw new Error(cliM("cli_build_native_host"));
|
|
2600
2822
|
if (!config.desktop?.length)
|
|
@@ -2624,6 +2846,8 @@ async function buildCommand(options) {
|
|
|
2624
2846
|
if (!existsSync(resolve(cwd, image.dockerfile)))
|
|
2625
2847
|
throw new Error(cliM("cli_build_dockerfile_missing", { params: { path: image.dockerfile } }));
|
|
2626
2848
|
}
|
|
2849
|
+
const downloads = await resolveBuildDownloads(cwd, options);
|
|
2850
|
+
for (const image of images) validateDownloadDockerfile(resolve(cwd, image.dockerfile), downloads);
|
|
2627
2851
|
const candidates = options.runtime && options.runtime !== "auto" ? [options.runtime] : ["podman", "docker"];
|
|
2628
2852
|
if (candidates.some((runtime2) => !["podman", "docker"].includes(runtime2)))
|
|
2629
2853
|
throw new Error(cliM("cli_build_runtime_missing"));
|
|
@@ -2638,6 +2862,7 @@ async function buildCommand(options) {
|
|
|
2638
2862
|
}
|
|
2639
2863
|
if (!runtime)
|
|
2640
2864
|
throw new Error(cliM("cli_build_runtime_missing"));
|
|
2865
|
+
await preflightDownloadProxy(runtime, downloads.proxy);
|
|
2641
2866
|
if (options.sqlitePrebuildMirror) {
|
|
2642
2867
|
const url = new URL(options.sqlitePrebuildMirror);
|
|
2643
2868
|
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.search || url.hash)
|
|
@@ -2667,8 +2892,8 @@ async function buildCommand(options) {
|
|
|
2667
2892
|
const context = resolve(cwd, image.context ?? ".");
|
|
2668
2893
|
const imageRef = `localhost/hai-${projectName}-${image.name}:${buildId.toLowerCase().replaceAll("+", "_")}`;
|
|
2669
2894
|
const args = ["build", "-f", resolve(cwd, image.dockerfile), "-t", imageRef];
|
|
2670
|
-
const testRun =
|
|
2671
|
-
const testLedger =
|
|
2895
|
+
const testRun = process5.env.HAI_TEST_IMAGE_RUN;
|
|
2896
|
+
const testLedger = process5.env.HAI_TEST_IMAGE_LEDGER;
|
|
2672
2897
|
if (testLedger && /^[a-f0-9-]{36}$/.test(testRun ?? "")) {
|
|
2673
2898
|
const label = `org.h-ai.test.image-run=${testRun}`;
|
|
2674
2899
|
args.push("--label", label);
|
|
@@ -2678,19 +2903,19 @@ async function buildCommand(options) {
|
|
|
2678
2903
|
`);
|
|
2679
2904
|
}
|
|
2680
2905
|
args.push("--build-arg", `HAI_BUILD_ID=${buildId}`, "--build-arg", `HAI_BUILD_COMMIT=${commit}`);
|
|
2906
|
+
const dockerfile = readFileSync(resolve(cwd, image.dockerfile), "utf8");
|
|
2907
|
+
for (const match of dockerfile.matchAll(/^ARG (HAI_(?:NODE|NGINX)_IMAGE)=(\S+)\s*$/gm))
|
|
2908
|
+
args.push("--build-arg", `${match[1]}=${resolveImageReference(match[2], downloads.imageSource)}`);
|
|
2909
|
+
args.push("--build-arg", `HAI_NPM_REGISTRY=${downloads.npmRegistry}`, ...buildProxyArguments(downloads.proxy, runtime, options.network));
|
|
2910
|
+
if (runtime === "docker" && process5.platform === "linux" && options.network !== "host")
|
|
2911
|
+
args.push("--add-host", "host.docker.internal:host-gateway");
|
|
2681
2912
|
if (options.network !== void 0)
|
|
2682
2913
|
args.push("--network", options.network);
|
|
2683
2914
|
const ignore = `${resolve(cwd, image.dockerfile)}.dockerignore`;
|
|
2684
2915
|
if (runtime === "podman" && existsSync(ignore))
|
|
2685
2916
|
args.push("--ignorefile", ignore);
|
|
2686
2917
|
if (runtime === "podman") {
|
|
2687
|
-
args.push("--format", "docker", "--jobs", "1", ...
|
|
2688
|
-
if (options.httpProxy !== false) {
|
|
2689
|
-
for (const key of ["HTTP_PROXY", "HTTPS_PROXY", "FTP_PROXY", "NO_PROXY", "http_proxy", "https_proxy", "ftp_proxy", "no_proxy"]) {
|
|
2690
|
-
if (process4.env[key])
|
|
2691
|
-
args.push("--build-arg", `${key}=${process4.env[key]}`);
|
|
2692
|
-
}
|
|
2693
|
-
}
|
|
2918
|
+
args.push("--format", "docker", "--jobs", "1", ...downloads.proxy.mode === "none" ? ["--http-proxy=false"] : []);
|
|
2694
2919
|
}
|
|
2695
2920
|
if (options.sqlitePrebuildMirror)
|
|
2696
2921
|
args.push("--build-arg", `SQLITE_PREBUILD_MIRROR=${options.sqlitePrebuildMirror}`);
|
|
@@ -2772,7 +2997,7 @@ function prepareDependencyInputs(cwd) {
|
|
|
2772
2997
|
async function deploySecretsCommand(directory, options) {
|
|
2773
2998
|
if (!options.import || !["docker", "podman"].includes(options.runtime ?? "docker"))
|
|
2774
2999
|
throw new Error(cliM("cli_deploy_secrets_options"));
|
|
2775
|
-
const cwd = resolve(options.cwd ??
|
|
3000
|
+
const cwd = resolve(options.cwd ?? process5.cwd());
|
|
2776
3001
|
const local = createRequire(resolve(cwd, "package.json"));
|
|
2777
3002
|
let module;
|
|
2778
3003
|
try {
|
|
@@ -2788,237 +3013,12 @@ ${JSON.stringify({ phase: context?.phase, state: context?.state })}`);
|
|
|
2788
3013
|
}
|
|
2789
3014
|
writeCliMessage(JSON.stringify(result.data, null, 2));
|
|
2790
3015
|
}
|
|
2791
|
-
|
|
2792
|
-
// ../reldb/dist/chunk-SDS2ZT3V.js
|
|
2793
|
-
external_exports.enum(["sqlite", "postgresql", "mysql"]);
|
|
2794
|
-
var ReldbOperationLogConfigSchema = external_exports.object({
|
|
2795
|
-
read: external_exports.boolean().default(false),
|
|
2796
|
-
write: external_exports.boolean().default(false),
|
|
2797
|
-
/** 安全数量摘要的最大字符数;0 表示省略摘要,永不记录 SQL 原文或参数值。 */
|
|
2798
|
-
maxLength: external_exports.number().int().min(0).default(1e3),
|
|
2799
|
-
level: external_exports.enum(["info", "debug", "trace"]).default("debug")
|
|
2800
|
-
});
|
|
2801
|
-
var OperationLogConfigFieldSchema = {
|
|
2802
|
-
operationLog: ReldbOperationLogConfigSchema.optional()
|
|
2803
|
-
};
|
|
2804
|
-
var PoolConfigSchema = external_exports.object({
|
|
2805
|
-
/** PostgreSQL 已建立连接的最小保留数(默认 1,不主动预建) */
|
|
2806
|
-
min: external_exports.number().int().min(0).default(1),
|
|
2807
|
-
/** 最大连接数(默认 10) */
|
|
2808
|
-
max: external_exports.number().int().min(1).default(10),
|
|
2809
|
-
/** PostgreSQL 空闲连接超时,毫秒(默认 30000;0 禁用) */
|
|
2810
|
-
idleTimeout: external_exports.number().int().min(0).default(3e4),
|
|
2811
|
-
/** 获取连接超时,毫秒(默认10000);PostgreSQL >=0,0禁用;MySQL排队+建连总期限为1–2147483647 */
|
|
2812
|
-
acquireTimeout: external_exports.number().int().min(0).default(1e4)
|
|
2813
|
-
});
|
|
2814
|
-
var MysqlPoolConfigSchema = external_exports.object({
|
|
2815
|
-
/** 最大连接数(默认 10) */
|
|
2816
|
-
max: external_exports.number().int().min(1).default(10),
|
|
2817
|
-
/** 获取连接超时,毫秒(默认10000);PostgreSQL >=0,0禁用;MySQL排队+建连总期限为1–2147483647 */
|
|
2818
|
-
acquireTimeout: external_exports.number().int().min(1).max(2147483647).default(1e4),
|
|
2819
|
-
/** MySQL 等待队列最大请求数(默认 1000;正整数,不支持无限队列) */
|
|
2820
|
-
queueLimit: external_exports.number().int().min(1).default(1e3)
|
|
2821
|
-
}).strict();
|
|
2822
|
-
var SslConfigSchema = external_exports.union([
|
|
2823
|
-
external_exports.boolean(),
|
|
2824
|
-
external_exports.enum(["require", "prefer", "allow", "disable"]),
|
|
2825
|
-
external_exports.record(external_exports.string(), external_exports.unknown())
|
|
2826
|
-
]);
|
|
2827
|
-
var MysqlSslConfigSchema = external_exports.union([
|
|
2828
|
-
external_exports.literal(false),
|
|
2829
|
-
external_exports.object({
|
|
2830
|
-
/** MySQL 是否校验证书链(默认 true);false 明确放弃服务端认证 */
|
|
2831
|
-
rejectUnauthorized: external_exports.boolean().default(true),
|
|
2832
|
-
/** MySQL 是否验证 DNS 主机身份(默认 true);仅证书链验证开启时有效 */
|
|
2833
|
-
verifyIdentity: external_exports.boolean().default(true),
|
|
2834
|
-
/** MySQL 信任的 CA,PEM 内容;省略时使用 Node 信任库 */
|
|
2835
|
-
ca: external_exports.string().min(1).optional(),
|
|
2836
|
-
/** MySQL 客户端证书,PEM 内容;必须同时提供 key */
|
|
2837
|
-
cert: external_exports.string().min(1).optional(),
|
|
2838
|
-
/** MySQL 客户端私钥,PEM 内容;必须同时提供 cert */
|
|
2839
|
-
key: external_exports.string().min(1).optional()
|
|
2840
|
-
}).strict().refine((ssl) => Boolean(ssl.cert) === Boolean(ssl.key), { path: ["key"] })
|
|
2841
|
-
]);
|
|
2842
|
-
var SqliteOptionsSchema = external_exports.object({
|
|
2843
|
-
/** 是否启用 WAL 模式(默认 true),可提高并发读写性能 */
|
|
2844
|
-
walMode: external_exports.boolean().default(true),
|
|
2845
|
-
/** 是否只读模式(默认 false) */
|
|
2846
|
-
readonly: external_exports.boolean().default(false),
|
|
2847
|
-
/**
|
|
2848
|
-
* 执行方式(默认 sync)。
|
|
2849
|
-
*
|
|
2850
|
-
* - `sync`:主线程直接执行 better-sqlite3(同步阻塞主线程事件循环)。
|
|
2851
|
-
* - `worker`:在专用 worker 线程持有唯一连接执行,把阻塞移出主线程。
|
|
2852
|
-
* 注意 WAL 只改善数据库锁并发,无法避免 better-sqlite3 同步调用占用调用线程。
|
|
2853
|
-
*/
|
|
2854
|
-
executor: external_exports.enum(["sync", "worker"]).default("sync"),
|
|
2855
|
-
/** worker 执行方式下等待连接打开的超时(毫秒,默认 10000) */
|
|
2856
|
-
workerConnectTimeoutMs: external_exports.number().int().positive().default(1e4)
|
|
2857
|
-
});
|
|
2858
|
-
var MysqlOptionsSchema = external_exports.object({
|
|
2859
|
-
/** 字符集(默认 utf8mb4),推荐使用 utf8mb4 支持完整 Unicode */
|
|
2860
|
-
charset: external_exports.string().default("utf8mb4")
|
|
2861
|
-
}).strict();
|
|
2862
|
-
var NetworkConfigSchema = external_exports.object({
|
|
2863
|
-
/**
|
|
2864
|
-
* 连接字符串(可选)
|
|
2865
|
-
* 如果提供 url,将优先使用,忽略 host/port 等字段
|
|
2866
|
-
*/
|
|
2867
|
-
url: external_exports.string().optional(),
|
|
2868
|
-
/** 数据库主机地址(默认 localhost) */
|
|
2869
|
-
host: external_exports.string().default("localhost"),
|
|
2870
|
-
/**
|
|
2871
|
-
* 数据库端口
|
|
2872
|
-
* - PostgreSQL 默认 5432
|
|
2873
|
-
* - MySQL 默认 3306
|
|
2874
|
-
*/
|
|
2875
|
-
port: external_exports.number().int().min(1).max(65535).optional(),
|
|
2876
|
-
/** 数据库名称 */
|
|
2877
|
-
database: external_exports.string(),
|
|
2878
|
-
/** 数据库用户名 */
|
|
2879
|
-
user: external_exports.string().optional(),
|
|
2880
|
-
/** 数据库密码 */
|
|
2881
|
-
password: external_exports.string().optional(),
|
|
2882
|
-
/** SSL/TLS 连接配置 */
|
|
2883
|
-
ssl: SslConfigSchema.optional(),
|
|
2884
|
-
/** 连接池配置 */
|
|
2885
|
-
pool: PoolConfigSchema.optional()
|
|
2886
|
-
});
|
|
2887
|
-
var SqliteConfigSchema = external_exports.object({
|
|
2888
|
-
type: external_exports.literal("sqlite"),
|
|
2889
|
-
/** 数据库文件路径(如 './data.db')或 ':memory:'(内存数据库) */
|
|
2890
|
-
database: external_exports.string(),
|
|
2891
|
-
/** SQLite 特定选项 */
|
|
2892
|
-
sqlite: SqliteOptionsSchema.optional(),
|
|
2893
|
-
...OperationLogConfigFieldSchema
|
|
2894
|
-
});
|
|
2895
|
-
var PostgresqlConfigSchema = NetworkConfigSchema.extend({
|
|
2896
|
-
type: external_exports.literal("postgresql"),
|
|
2897
|
-
...OperationLogConfigFieldSchema
|
|
2898
|
-
});
|
|
2899
|
-
var MysqlConfigSchema = NetworkConfigSchema.extend({
|
|
2900
|
-
type: external_exports.literal("mysql"),
|
|
2901
|
-
/** 网络数据库URL;MySQL空串表示使用分字段,非空仅mysql://且拒绝query/fragment,优先于host/port/database/user/password */
|
|
2902
|
-
url: external_exports.union([external_exports.literal("").transform(() => void 0), external_exports.url({ protocol: /^mysql$/ }).refine((value) => !value.includes("?") && !value.includes("#"))]).optional(),
|
|
2903
|
-
/** 数据库:SQLite文件路径或:memory:;PostgreSQL必填名称;MySQL无URL时必填,URL模式从URL读取 */
|
|
2904
|
-
database: external_exports.string().min(1).optional(),
|
|
2905
|
-
/** TLS:PostgreSQL使用其模式;MySQL仅false或严格对象,空对象默认校验证书链和DNS身份 */
|
|
2906
|
-
ssl: MysqlSslConfigSchema.optional(),
|
|
2907
|
-
/** 连接池配置:PostgreSQL支持min/idleTimeout;MySQL仅max/acquireTimeout/queueLimit,拒绝其他字段 */
|
|
2908
|
-
pool: MysqlPoolConfigSchema.optional(),
|
|
2909
|
-
/** MySQL 特定选项 */
|
|
2910
|
-
mysql: MysqlOptionsSchema.optional(),
|
|
2911
|
-
...OperationLogConfigFieldSchema
|
|
2912
|
-
}).refine((config) => Boolean(config.url) || Boolean(config.database), { path: ["database"] });
|
|
2913
|
-
var ReldbConfigSchema = external_exports.discriminatedUnion("type", [
|
|
2914
|
-
SqliteConfigSchema,
|
|
2915
|
-
PostgresqlConfigSchema,
|
|
2916
|
-
MysqlConfigSchema
|
|
2917
|
-
]);
|
|
2918
|
-
var CLOUD_FIELDS = {
|
|
2919
|
-
"neon": ["apiKey"],
|
|
2920
|
-
"upstash": ["email", "apiKey"],
|
|
2921
|
-
"cloudflare-r2": ["accountId", "apiToken", "accessKeyId", "secretAccessKey"],
|
|
2922
|
-
"resend": ["apiKey", "from"],
|
|
2923
|
-
"aliyun": ["accessKeyId", "accessKeySecret", "signName"]
|
|
2924
|
-
};
|
|
2925
|
-
function targetConfig(requirement, environment) {
|
|
2926
|
-
const result = {};
|
|
2927
|
-
const parent = environment.targetValues[requirement.envPrefix];
|
|
2928
|
-
if (parent) {
|
|
2929
|
-
try {
|
|
2930
|
-
Object.assign(result, JSON.parse(parent));
|
|
2931
|
-
} catch {
|
|
2932
|
-
return {};
|
|
2933
|
-
}
|
|
2934
|
-
}
|
|
2935
|
-
for (const [key, value] of Object.entries(environment.targetValues)) {
|
|
2936
|
-
if (key.startsWith(`${requirement.envPrefix}_`))
|
|
2937
|
-
result[key.slice(requirement.envPrefix.length + 1).toLowerCase()] = value;
|
|
2938
|
-
}
|
|
2939
|
-
return result;
|
|
2940
|
-
}
|
|
2941
|
-
function canKeepMiddleware(requirement, backend, environment) {
|
|
2942
|
-
const target = targetConfig(requirement, environment);
|
|
2943
|
-
if (requirement.service === "ldap" && backend.backend === "disabled")
|
|
2944
|
-
return environment.targetValues.HAI_IAM_LOGIN_LDAP === "false";
|
|
2945
|
-
if (requirement.service === "ldap") {
|
|
2946
|
-
if (!Object.keys(target).length)
|
|
2947
|
-
return false;
|
|
2948
|
-
} else if (target.type !== backend.backend) {
|
|
2949
|
-
return false;
|
|
2950
|
-
}
|
|
2951
|
-
return backend.fields.filter((field) => field.required && !field.secret).every((field) => {
|
|
2952
|
-
if ((target.url || requirement.config.url && Object.keys(target).length) && ["host", "port"].includes(field.name))
|
|
2953
|
-
return true;
|
|
2954
|
-
return target[field.name] !== void 0 && target[field.name] !== "" || target[field.name.toLowerCase()] !== void 0 && target[field.name.toLowerCase()] !== "";
|
|
2955
|
-
}) && backend.fields.filter((field) => field.required && field.secret).every((field) => Boolean(requirement.config[field.name] || environment.values[`${requirement.envPrefix}_${field.name.toUpperCase()}`]));
|
|
2956
|
-
}
|
|
2957
3016
|
async function ask(question) {
|
|
2958
3017
|
const answer = await prompts({ ...question, name: "value" });
|
|
2959
3018
|
if (answer.value === void 0)
|
|
2960
3019
|
throw new Error(cliM("cli_deploy_cancelled"));
|
|
2961
3020
|
return answer.value;
|
|
2962
3021
|
}
|
|
2963
|
-
function validateField(value, field, backend) {
|
|
2964
|
-
if (value === "")
|
|
2965
|
-
return field.required ? cliM("cli_deploy_required") : true;
|
|
2966
|
-
if (field.kind === "port")
|
|
2967
|
-
return /^\d+$/.test(value) && Number(value) >= 1 && Number(value) <= 65535 || cliM("cli_deploy_invalid_value");
|
|
2968
|
-
if (field.kind === "number")
|
|
2969
|
-
return /^\d+$/.test(value) && Number(value) >= (field.minimum ?? 0) && Number(value) <= (field.maximum ?? Number.MAX_SAFE_INTEGER) || cliM("cli_deploy_invalid_value");
|
|
2970
|
-
if (field.kind === "boolean")
|
|
2971
|
-
return ["true", "false"].includes(value) || cliM("cli_deploy_invalid_value");
|
|
2972
|
-
if (field.kind === "url") {
|
|
2973
|
-
try {
|
|
2974
|
-
return Boolean(new URL(value).protocol);
|
|
2975
|
-
} catch {
|
|
2976
|
-
return cliM("cli_deploy_invalid_value");
|
|
2977
|
-
}
|
|
2978
|
-
}
|
|
2979
|
-
if (field.name === "ssl") {
|
|
2980
|
-
const parsed2 = parseDocument(value);
|
|
2981
|
-
const schema = backend === "mysql" ? MysqlSslConfigSchema : SslConfigSchema;
|
|
2982
|
-
return parsed2.errors.length === 0 && schema.safeParse(parsed2.toJS()).success || cliM("cli_deploy_invalid_value");
|
|
2983
|
-
}
|
|
2984
|
-
if (field.name === "headers") {
|
|
2985
|
-
try {
|
|
2986
|
-
const headers = JSON.parse(value);
|
|
2987
|
-
return headers !== null && typeof headers === "object" && !Array.isArray(headers) && Object.values(headers).every((item) => typeof item === "string") || cliM("cli_deploy_invalid_value");
|
|
2988
|
-
} catch {
|
|
2989
|
-
return cliM("cli_deploy_invalid_value");
|
|
2990
|
-
}
|
|
2991
|
-
}
|
|
2992
|
-
if (field.name === "method")
|
|
2993
|
-
return ["POST", "PUT"].includes(value) || cliM("cli_deploy_invalid_value");
|
|
2994
|
-
return true;
|
|
2995
|
-
}
|
|
2996
|
-
function ensureConfigNode(appDir, requirement, backend) {
|
|
2997
|
-
if (requirement.service === "ldap" && backend === "disabled")
|
|
2998
|
-
return;
|
|
2999
|
-
const directory = join(appDir, "config");
|
|
3000
|
-
mkdirSync(directory, { recursive: true });
|
|
3001
|
-
const path10 = join(directory, `_${requirement.configName}.yml`);
|
|
3002
|
-
const document = parseDocument(existsSync(path10) ? readFileSync(path10, "utf8") : "{}\n");
|
|
3003
|
-
if (document.errors.length)
|
|
3004
|
-
throw new Error(cliM("cli_deploy_invalid_value"));
|
|
3005
|
-
if (requirement.configPath.length && !document.hasIn(requirement.configPath))
|
|
3006
|
-
document.setIn(requirement.configPath, document.createNode(requirement.configName === "reach" ? { name: requirement.config.name ?? requirement.service, type: backend } : {}));
|
|
3007
|
-
if (requirement.service === "ldap") {
|
|
3008
|
-
if (!document.hasIn(["login"]))
|
|
3009
|
-
document.set("login", document.createNode({}));
|
|
3010
|
-
if (!document.hasIn(["login", "ldap"]))
|
|
3011
|
-
document.setIn(["login", "ldap"], `\${HAI_IAM_LOGIN_LDAP:false}`);
|
|
3012
|
-
}
|
|
3013
|
-
const content = document.toString();
|
|
3014
|
-
if (!existsSync(path10) || readFileSync(path10, "utf8") !== content)
|
|
3015
|
-
writeFileSync(path10, content);
|
|
3016
|
-
}
|
|
3017
|
-
function connectionEnv(requirement, backend, config) {
|
|
3018
|
-
if (requirement.service === "ldap")
|
|
3019
|
-
return backend === "disabled" ? { HAI_IAM_LOGIN_LDAP: "false" } : { HAI_IAM_LOGIN_LDAP: "true", [requirement.envPrefix]: JSON.stringify(config) };
|
|
3020
|
-
return { [requirement.envPrefix]: JSON.stringify({ ...config, type: backend }) };
|
|
3021
|
-
}
|
|
3022
3022
|
async function configureDeployMiddleware(module, scan, environment, config, yes = false) {
|
|
3023
3023
|
const modes = {};
|
|
3024
3024
|
const services = {};
|
|
@@ -3030,7 +3030,7 @@ async function configureDeployMiddleware(module, scan, environment, config, yes
|
|
|
3030
3030
|
if (!current)
|
|
3031
3031
|
throw new Error(cliM("cli_deploy_cloud_unsupported", { params: { backend: requirement.backend } }));
|
|
3032
3032
|
writeCliMessage(cliM("cli_deploy_middleware", { params: { service: requirement.service, backend: current.label, purpose: module.describeMiddlewareBackend(current), source: requirement.source } }));
|
|
3033
|
-
const canKeep = canKeepMiddleware(requirement, current, environment);
|
|
3033
|
+
const canKeep = module.canKeepMiddleware(requirement, current, environment);
|
|
3034
3034
|
const mode = yes ? canKeep ? "keep" : "default" : await ask({
|
|
3035
3035
|
type: "select",
|
|
3036
3036
|
name: "value",
|
|
@@ -3055,22 +3055,23 @@ async function configureDeployMiddleware(module, scan, environment, config, yes
|
|
|
3055
3055
|
throw new Error(cliM("cli_deploy_invalid_value"));
|
|
3056
3056
|
requirement.backend = backendName;
|
|
3057
3057
|
const updates = {};
|
|
3058
|
-
|
|
3058
|
+
let configuration;
|
|
3059
|
+
for (const option of mode === "default" && provider?.type === "docker-ssh" ? backend.containerOptions ?? [] : []) {
|
|
3059
3060
|
const container = config.container && typeof config.container === "object" ? config.container : {};
|
|
3060
|
-
const
|
|
3061
|
-
const
|
|
3062
|
-
if (!
|
|
3061
|
+
const currentValue = String(container[option.field] ?? option.defaultValue);
|
|
3062
|
+
const selected = yes ? currentValue : String(await ask({ type: "select", name: "value", message: module.describeMiddlewareBackend(option), initial: Math.max(0, option.choices.findIndex((item) => item.value === currentValue)), choices: option.choices.map((item) => ({ title: item.label, value: item.value })) }));
|
|
3063
|
+
if (!option.choices.some((item) => item.value === selected))
|
|
3063
3064
|
throw new Error(cliM("cli_deploy_invalid_value"));
|
|
3064
|
-
config.container = { ...container,
|
|
3065
|
-
updates.
|
|
3065
|
+
config.container = { ...container, [option.field]: selected };
|
|
3066
|
+
updates[option.variable] = selected;
|
|
3066
3067
|
const deploymentFile = projectConfigPath(scan.appDir ?? environment.envDir);
|
|
3067
3068
|
const project = readProjectConfig(deploymentFile);
|
|
3068
3069
|
project.deploy ??= {};
|
|
3069
3070
|
if (project.deploy.container != null && (typeof project.deploy.container !== "object" || Array.isArray(project.deploy.container)))
|
|
3070
3071
|
throw new Error(cliM("cli_deploy_config_node", { params: { path: deploymentFile, field: "deploy.container" } }));
|
|
3071
3072
|
project.deploy.container ??= {};
|
|
3072
|
-
if (!(
|
|
3073
|
-
project.deploy.container.
|
|
3073
|
+
if (!(option.field in project.deploy.container)) {
|
|
3074
|
+
project.deploy.container[option.field] = `\${${option.variable}:${option.defaultValue}}`;
|
|
3074
3075
|
writeFileSync(deploymentFile, `${JSON.stringify(project, null, 2)}
|
|
3075
3076
|
`);
|
|
3076
3077
|
}
|
|
@@ -3081,7 +3082,7 @@ async function configureDeployMiddleware(module, scan, environment, config, yes
|
|
|
3081
3082
|
const prior = existingServices[requirement.service];
|
|
3082
3083
|
const priorConfig = prior && typeof prior === "object" ? prior : {};
|
|
3083
3084
|
const cloud = { provisioner: backend.provisioner };
|
|
3084
|
-
for (const name of
|
|
3085
|
+
for (const name of backend.cloudFields ?? []) {
|
|
3085
3086
|
const key = `HAI_DEPLOY_SERVICES_${requirement.service.toUpperCase()}_${name.toUpperCase()}`;
|
|
3086
3087
|
const initial = String(priorConfig[name] ?? environment.values[key] ?? "");
|
|
3087
3088
|
const label = `${backend.label} \u2014 ${cliM(`cli_deploy_cloud_input_${name}`)}`;
|
|
@@ -3093,32 +3094,25 @@ async function configureDeployMiddleware(module, scan, environment, config, yes
|
|
|
3093
3094
|
}
|
|
3094
3095
|
services[requirement.service] = cloud;
|
|
3095
3096
|
} else {
|
|
3096
|
-
if (mode === "default" &&
|
|
3097
|
+
if (mode === "default" && backend.containerSupported === false)
|
|
3097
3098
|
throw new Error(cliM("cli_deploy_cloud_unsupported", { params: { backend: backend.label } }));
|
|
3098
|
-
const connection = backendName === current.backend ? { ...requirement.config } : requirement.
|
|
3099
|
+
const connection = backendName === current.backend ? { ...requirement.config } : requirement.config.name === void 0 ? {} : { name: requirement.config.name };
|
|
3099
3100
|
for (const field of backend.fields) {
|
|
3100
3101
|
const previous2 = backendName === current.backend ? requirement.config[field.name] : void 0;
|
|
3101
3102
|
const initial = previous2 === void 0 ? field.defaultValue ?? "" : typeof previous2 === "object" ? JSON.stringify(previous2) : String(previous2);
|
|
3102
3103
|
const variable = `${requirement.envPrefix}_${field.name.toUpperCase()}`;
|
|
3103
3104
|
const info = moduleEnvironmentVariables(requirement.configName).find((item) => item.name === variable);
|
|
3104
|
-
const value = mode === "custom" && !yes ? String(await ask({ type: field.secret ? "password" : "text", name: "value", message: cliM("cli_deploy_field", { params: { description: info?.description ?? field.name, constraint: info?.constraint ?? field.kind ?? "string" } }), initial, validate: (input) =>
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
} else {
|
|
3105
|
+
const value = mode === "custom" && !yes ? String(await ask({ type: field.secret ? "password" : "text", name: "value", message: cliM("cli_deploy_field", { params: { description: info?.description ?? field.name, constraint: info?.constraint ?? field.kind ?? "string" } }), initial, validate: (input) => module.validateMiddlewareField({ value: String(input), field, backend: backendName }) || cliM("cli_deploy_invalid_value") })) : initial;
|
|
3106
|
+
const parsed2 = module.parseMiddlewareField({ value, field, backend: backendName, managed: mode === "default" });
|
|
3107
|
+
if (!parsed2.success)
|
|
3108
|
+
throw new Error(parsed2.error.message);
|
|
3109
|
+
if (parsed2.data === void 0)
|
|
3110
3110
|
delete connection[field.name];
|
|
3111
|
-
|
|
3111
|
+
else connection[field.name] = parsed2.data;
|
|
3112
3112
|
}
|
|
3113
|
-
|
|
3114
|
-
const validated = ReldbConfigSchema.safeParse({ ...connection, type: backendName });
|
|
3115
|
-
if (!validated.success)
|
|
3116
|
-
throw new Error(cliM("cli_deploy_config_invalid", { params: { path: join(scan.appDir ?? ".", "config", "_db.yml"), fields: validated.error.issues.map((issue) => issue.path.join(".")).join(", ") } }));
|
|
3117
|
-
}
|
|
3118
|
-
Object.assign(updates, connectionEnv(requirement, backendName, connection));
|
|
3113
|
+
configuration = connection;
|
|
3119
3114
|
}
|
|
3120
|
-
|
|
3121
|
-
const saved = module.saveDeploymentEnvironment(environment, updates);
|
|
3115
|
+
const saved = module.saveMiddlewareEnvironment(environment, { appDir: scan.appDir ?? ".", requirement, backend: backendName, configuration, updates });
|
|
3122
3116
|
if (!saved.success)
|
|
3123
3117
|
throw new Error(saved.error.message);
|
|
3124
3118
|
writeCliMessage(cliM("cli_deploy_saved", { params: { service: requirement.service } }));
|
|
@@ -3222,7 +3216,7 @@ async function configureDeployTarget(module, config, environment, nonInteractive
|
|
|
3222
3216
|
const validated = module.ProviderConfigSchema.safeParse(provider);
|
|
3223
3217
|
if (!validated.success)
|
|
3224
3218
|
throw new Error(cliM("cli_deploy_invalid_value"));
|
|
3225
|
-
const saved = module.saveDeploymentEnvironment(environment, { HAI_DEPLOY_PROVIDER:
|
|
3219
|
+
const saved = module.saveDeploymentEnvironment(environment, { HAI_DEPLOY_PROVIDER: validated.data }, { private: true });
|
|
3226
3220
|
if (!saved.success)
|
|
3227
3221
|
throw new Error(saved.error.message);
|
|
3228
3222
|
config.provider = validated.data;
|
|
@@ -3273,7 +3267,7 @@ async function configureDeployHttps(module, config, environment, nonInteractive,
|
|
|
3273
3267
|
const parsed2 = module.ProviderConfigSchema.safeParse({ ...provider, expose: { ...expose, ...https?.type === "letsencrypt" ? { hostPort: 80 } : {}, https } });
|
|
3274
3268
|
if (!parsed2.success)
|
|
3275
3269
|
throw new Error(cliM("cli_deploy_invalid_value"));
|
|
3276
|
-
const saved = module.saveDeploymentEnvironment(environment, { HAI_DEPLOY_PROVIDER:
|
|
3270
|
+
const saved = module.saveDeploymentEnvironment(environment, { HAI_DEPLOY_PROVIDER: parsed2.data }, { private: true });
|
|
3277
3271
|
if (!saved.success)
|
|
3278
3272
|
throw new Error(saved.error.message);
|
|
3279
3273
|
config.provider = parsed2.data;
|
|
@@ -3281,11 +3275,11 @@ async function configureDeployHttps(module, config, environment, nonInteractive,
|
|
|
3281
3275
|
}
|
|
3282
3276
|
async function deployCommand(options) {
|
|
3283
3277
|
const spinner = ora();
|
|
3284
|
-
const cwd = options.cwd ??
|
|
3278
|
+
const cwd = options.cwd ?? process5.cwd();
|
|
3285
3279
|
let appDir = resolve(cwd, options.appDir ?? ".");
|
|
3286
3280
|
let closeDeploy = null;
|
|
3287
3281
|
let restoreProjectLogger;
|
|
3288
|
-
const originalEnv = { ...
|
|
3282
|
+
const originalEnv = { ...process5.env };
|
|
3289
3283
|
const previousLogLevel = core.logger.getLevel();
|
|
3290
3284
|
core.logger.setLevel("fatal");
|
|
3291
3285
|
try {
|
|
@@ -3295,21 +3289,21 @@ async function deployCommand(options) {
|
|
|
3295
3289
|
throw new Error(cliM("cli_build_runtime_missing"));
|
|
3296
3290
|
if (options.artifactDir && options.build)
|
|
3297
3291
|
throw new Error(cliM("cli_deploy_build_artifact_conflict"));
|
|
3298
|
-
if (!options.build && (options.concurrency !== void 0 || options.network !== void 0 || options.sqlitePrebuildMirror !== void 0 || options.
|
|
3292
|
+
if (!options.build && (options.concurrency !== void 0 || options.network !== void 0 || options.sqlitePrebuildMirror !== void 0 || options.npmSource !== void 0 || options.npmRegistry !== void 0))
|
|
3299
3293
|
throw new Error(cliM("cli_deploy_build_options_required"));
|
|
3300
3294
|
let selectedServices = options.services?.split(",").map((name) => name.trim());
|
|
3301
3295
|
if (selectedServices && (!selectedServices.length || selectedServices.some((name) => !/^[a-z][a-z0-9-]*$/.test(name)) || new Set(selectedServices).size !== selectedServices.length))
|
|
3302
3296
|
throw new Error(cliM("cli_build_selection_invalid"));
|
|
3303
3297
|
let environmentName = options.env;
|
|
3304
3298
|
if (!environmentName) {
|
|
3305
|
-
if (!
|
|
3299
|
+
if (!process5.stdin.isTTY)
|
|
3306
3300
|
throw new Error(cliM("cli_deploy_environment_hint"));
|
|
3307
3301
|
const answer = await prompts({ type: "text", name: "environment", message: cliM("cli_deploy_environment"), initial: "prod" });
|
|
3308
3302
|
environmentName = answer.environment;
|
|
3309
3303
|
if (!environmentName)
|
|
3310
3304
|
throw new Error(cliM("cli_deploy_cancelled"));
|
|
3311
3305
|
}
|
|
3312
|
-
if (!options.plan && !options.yes && !
|
|
3306
|
+
if (!options.plan && !options.yes && !process5.stdin.isTTY)
|
|
3313
3307
|
throw new Error(cliM("cli_deploy_environment_hint"));
|
|
3314
3308
|
let deployModule;
|
|
3315
3309
|
try {
|
|
@@ -3328,7 +3322,7 @@ async function deployCommand(options) {
|
|
|
3328
3322
|
localModule = localRequire.resolve("@h-ai/deploy");
|
|
3329
3323
|
} catch {
|
|
3330
3324
|
}
|
|
3331
|
-
deployModule = localModule ? await import(pathToFileURL(localModule).href) : await import('./src-
|
|
3325
|
+
deployModule = localModule ? await import(pathToFileURL(localModule).href) : await import('./src-CX5IJGYM.js');
|
|
3332
3326
|
} catch {
|
|
3333
3327
|
writeCliError(chalk.red(cliM("cli_deploy_module_missing")));
|
|
3334
3328
|
writeCliMessage(chalk.cyan(" pnpm add -D @h-ai/deploy"));
|
|
@@ -3356,9 +3350,9 @@ async function deployCommand(options) {
|
|
|
3356
3350
|
if (!environment.success)
|
|
3357
3351
|
throw new Error(environment.error.message);
|
|
3358
3352
|
if (options.plan) {
|
|
3359
|
-
if (options.build || options.bundleOnly || options.output)
|
|
3353
|
+
if (options.build || options.bundleOnly || options.output || options.imageSource !== void 0 || options.imageMirrors !== void 0 || options.npmSource !== void 0 || options.npmRegistry !== void 0 || options.proxyMode !== void 0 || options.proxyUrl !== void 0 || options.proxyBypass !== void 0 || options.httpProxy === false)
|
|
3360
3354
|
throw new Error(cliM("cli_deploy_plan_options"));
|
|
3361
|
-
const loaded = deployModule.loadDeploymentConfig("deploy", buildFile, { ...
|
|
3355
|
+
const loaded = deployModule.loadDeploymentConfig("deploy", buildFile, { ...process5.env, ...environment.data.values });
|
|
3362
3356
|
if (!loaded.success)
|
|
3363
3357
|
throw new Error(loaded.error.message);
|
|
3364
3358
|
const validated = deployModule.DeployConfigSchema.safeParse(loaded.data);
|
|
@@ -3370,7 +3364,7 @@ async function deployCommand(options) {
|
|
|
3370
3364
|
writeCliMessage(JSON.stringify(plan.data, null, 2));
|
|
3371
3365
|
return;
|
|
3372
3366
|
}
|
|
3373
|
-
Object.assign(
|
|
3367
|
+
Object.assign(process5.env, environment.data.values);
|
|
3374
3368
|
spinner.start(cliM("cli_deploy_load_credentials"));
|
|
3375
3369
|
const credResult = deploy.credentials.load();
|
|
3376
3370
|
if (!credResult.success) {
|
|
@@ -3384,7 +3378,7 @@ async function deployCommand(options) {
|
|
|
3384
3378
|
writeCliMessage(chalk.cyan(cliM("cli_deploy_config_hint")));
|
|
3385
3379
|
throw new Error(cliM("cli_deploy_config_missing", { params: { path: configPath } }));
|
|
3386
3380
|
}
|
|
3387
|
-
const loadedConfig = deployModule.loadDeploymentConfig("deploy", configPath,
|
|
3381
|
+
const loadedConfig = deployModule.loadDeploymentConfig("deploy", configPath, process5.env);
|
|
3388
3382
|
if (!loadedConfig.success)
|
|
3389
3383
|
throw new Error(loadedConfig.error.message);
|
|
3390
3384
|
const deployConfig = loadedConfig.data;
|
|
@@ -3429,13 +3423,16 @@ async function deployCommand(options) {
|
|
|
3429
3423
|
}
|
|
3430
3424
|
}
|
|
3431
3425
|
spinner.succeed(cliM("cli_deploy_scanned", { params: { name: scan.appName, sveltekit: String(scan.isSvelteKit), services: scan.requiredServices.join(", ") || cliM("cli_deploy_none") } }));
|
|
3426
|
+
const downloads = configObject(deployConfig.provider).type === "docker-ssh" ? await resolveBuildDownloads(buildRoot, options) : void 0;
|
|
3427
|
+
let builtImages = false;
|
|
3432
3428
|
if (options.build) {
|
|
3433
3429
|
if (!existsSync(buildFile))
|
|
3434
3430
|
throw new Error(cliM("cli_build_images_missing"));
|
|
3435
3431
|
const imageNames2 = selectedServices?.filter((name) => ["serv", "web"].includes(name));
|
|
3436
3432
|
if (!selectedServices || imageNames2?.length) {
|
|
3437
3433
|
writeCliMessage(cliM("cli_deploy_build_started"));
|
|
3438
|
-
|
|
3434
|
+
builtImages = true;
|
|
3435
|
+
await buildCommand({ ...options, cwd: buildRoot, target: "image", images: imageNames2?.join(","), yes: true, imageSource: downloads?.imageSource.type, imageMirrors: downloads?.imageSource.registries ? Object.entries(downloads.imageSource.registries).map(([key, value]) => `${key}=${value}`).join(",") : void 0, npmSource: downloads?.npmSource.type, npmRegistry: downloads?.npmSource.registry, proxyMode: downloads?.proxy.mode, proxyUrl: downloads?.proxy.url, proxyBypass: downloads?.proxy.bypass });
|
|
3439
3436
|
}
|
|
3440
3437
|
}
|
|
3441
3438
|
if (selectedServices)
|
|
@@ -3460,15 +3457,15 @@ async function deployCommand(options) {
|
|
|
3460
3457
|
if (options.bundleOnly)
|
|
3461
3458
|
await configureDeployTarget(deployModule, deployConfig, environment.data, options.yes, true);
|
|
3462
3459
|
await configureDeployHttps(deployModule, deployConfig, environment.data, options.yes, selectedServices !== void 0);
|
|
3463
|
-
for (const key of Object.keys(
|
|
3460
|
+
for (const key of Object.keys(process5.env)) {
|
|
3464
3461
|
if (originalEnv[key] === void 0)
|
|
3465
|
-
delete
|
|
3462
|
+
delete process5.env[key];
|
|
3466
3463
|
}
|
|
3467
|
-
Object.assign(
|
|
3464
|
+
Object.assign(process5.env, originalEnv);
|
|
3468
3465
|
const refreshed = deployModule.loadDeploymentEnvironment({ environment: environment.data.environment, envDir: environment.data.envDir });
|
|
3469
3466
|
if (!refreshed.success)
|
|
3470
3467
|
throw new Error(refreshed.error.message);
|
|
3471
|
-
Object.assign(
|
|
3468
|
+
Object.assign(process5.env, refreshed.data.values);
|
|
3472
3469
|
spinner.start(cliM("cli_deploy_initializing"));
|
|
3473
3470
|
const validatedConfig = deployModule.DeployConfigSchema.safeParse(deployConfig);
|
|
3474
3471
|
if (!validatedConfig.success)
|
|
@@ -3480,7 +3477,11 @@ async function deployCommand(options) {
|
|
|
3480
3477
|
closeDeploy = () => deploy.close();
|
|
3481
3478
|
spinner.succeed(cliM("cli_deploy_initialized"));
|
|
3482
3479
|
spinner.start(cliM("cli_deploy_deploying"));
|
|
3480
|
+
if (downloads && !builtImages && (!selectedServices || selectedServices.some((name) => !["serv", "web"].includes(name))))
|
|
3481
|
+
await preflightDownloadProxy(options.runtime ?? "auto", downloads.proxy);
|
|
3483
3482
|
const deployResult = await deploy.deployApp(appDir, {
|
|
3483
|
+
imageSource: downloads?.imageSource,
|
|
3484
|
+
proxy: downloads?.proxy,
|
|
3484
3485
|
selectedServices,
|
|
3485
3486
|
runtime: options.runtime,
|
|
3486
3487
|
onProgress: (stage) => writeCliMessage(cliM(`cli_deploy_stage_${stage}`)),
|
|
@@ -3542,14 +3543,14 @@ async function deployCommand(options) {
|
|
|
3542
3543
|
await closeDeploy();
|
|
3543
3544
|
} catch (error) {
|
|
3544
3545
|
writeCliError("Failed to close deploy module", error);
|
|
3545
|
-
|
|
3546
|
+
process5.exitCode = 1;
|
|
3546
3547
|
}
|
|
3547
3548
|
}
|
|
3548
|
-
for (const key of Object.keys(
|
|
3549
|
+
for (const key of Object.keys(process5.env)) {
|
|
3549
3550
|
if (originalEnv[key] === void 0)
|
|
3550
|
-
delete
|
|
3551
|
+
delete process5.env[key];
|
|
3551
3552
|
}
|
|
3552
|
-
Object.assign(
|
|
3553
|
+
Object.assign(process5.env, originalEnv);
|
|
3553
3554
|
core.logger.setLevel(previousLogLevel);
|
|
3554
3555
|
restoreProjectLogger?.();
|
|
3555
3556
|
}
|
|
@@ -4383,7 +4384,7 @@ async function startFeedbackViewer(bundle, options = {}) {
|
|
|
4383
4384
|
async function feedbackCommand(action, bundlePath, options = {}) {
|
|
4384
4385
|
if (!["inspect", "summary", "evidence", "view"].includes(action))
|
|
4385
4386
|
throw new Error(cliM("cli_feedback_invalidAction"));
|
|
4386
|
-
const filePath = path2.resolve(options.cwd ??
|
|
4387
|
+
const filePath = path2.resolve(options.cwd ?? process5.cwd(), bundlePath);
|
|
4387
4388
|
const metadata = await stat(filePath);
|
|
4388
4389
|
if (!metadata.isFile() || metadata.size > 64 * 1024 * 1024)
|
|
4389
4390
|
throw new Error(cliM("cli_feedback_invalidBundle"));
|
|
@@ -4417,12 +4418,12 @@ async function feedbackCommand(action, bundlePath, options = {}) {
|
|
|
4417
4418
|
writeCliMessage(cliM("cli_feedback_viewerStarted", { params: { url: viewer.url } }));
|
|
4418
4419
|
await new Promise((resolve7, reject) => {
|
|
4419
4420
|
const stop = () => {
|
|
4420
|
-
|
|
4421
|
-
|
|
4421
|
+
process5.off("SIGINT", stop);
|
|
4422
|
+
process5.off("SIGTERM", stop);
|
|
4422
4423
|
viewer.close().then(resolve7, reject);
|
|
4423
4424
|
};
|
|
4424
|
-
|
|
4425
|
-
|
|
4425
|
+
process5.once("SIGINT", stop);
|
|
4426
|
+
process5.once("SIGTERM", stop);
|
|
4426
4427
|
});
|
|
4427
4428
|
}
|
|
4428
4429
|
function appendAt(source, marker, entry) {
|
|
@@ -5042,7 +5043,7 @@ async function initProject(options) {
|
|
|
5042
5043
|
const { project, existing, missing } = result;
|
|
5043
5044
|
spinner.succeed(cliM("cli_initDetected", { params: { name: chalk.cyan(project.name) } }));
|
|
5044
5045
|
if (project.isHaiProject) {
|
|
5045
|
-
const { generateProjectAiSupport, resolveSkillNamesForPackages } = await import('./cli-skill-templates-
|
|
5046
|
+
const { generateProjectAiSupport, resolveSkillNamesForPackages } = await import('./cli-skill-templates-S2YH642Z.js');
|
|
5046
5047
|
const generatedFiles = await generateProjectAiSupport(cwd, resolveSkillNamesForPackages(project.haiPackages), {
|
|
5047
5048
|
overwriteSkills: false,
|
|
5048
5049
|
overwriteBridgeFiles: false
|
|
@@ -5120,7 +5121,7 @@ async function initProject(options) {
|
|
|
5120
5121
|
throw error;
|
|
5121
5122
|
}
|
|
5122
5123
|
}
|
|
5123
|
-
function
|
|
5124
|
+
function object2(value) {
|
|
5124
5125
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
5125
5126
|
}
|
|
5126
5127
|
function declaresValueExport(source, name) {
|
|
@@ -5153,9 +5154,9 @@ async function inspectFrameworkUpgrade(directory, version) {
|
|
|
5153
5154
|
throw new Error(cliM("cli_upgrade_exact_version"));
|
|
5154
5155
|
const root = realpathSync(resolve(directory));
|
|
5155
5156
|
const workspaceFile = join(root, "pnpm-workspace.yaml");
|
|
5156
|
-
const workspace = existsSync(workspaceFile) ?
|
|
5157
|
-
const rootManifest =
|
|
5158
|
-
const patterns = Array.isArray(workspace.packages) ? workspace.packages : Array.isArray(rootManifest.workspaces) ? rootManifest.workspaces : Array.isArray(
|
|
5157
|
+
const workspace = existsSync(workspaceFile) ? object2(parse(readFileSync(workspaceFile, "utf8"))) : {};
|
|
5158
|
+
const rootManifest = object2(JSON.parse(readFileSync(join(root, "package.json"), "utf8")));
|
|
5159
|
+
const patterns = Array.isArray(workspace.packages) ? workspace.packages : Array.isArray(rootManifest.workspaces) ? rootManifest.workspaces : Array.isArray(object2(rootManifest.workspaces).packages) ? object2(rootManifest.workspaces).packages : [];
|
|
5159
5160
|
const directories = /* @__PURE__ */ new Set([root]);
|
|
5160
5161
|
const safePatterns = patterns.filter((pattern) => typeof pattern === "string" && !isAbsolute(pattern.replace(/^!/, "")) && !pattern.split(/[\\/]/).includes(".."));
|
|
5161
5162
|
const exclude = ["**/node_modules/**", ...safePatterns.filter((pattern) => pattern.startsWith("!")).map((pattern) => `${pattern.slice(1)}/package.json`)];
|
|
@@ -5163,29 +5164,29 @@ async function inspectFrameworkUpgrade(directory, version) {
|
|
|
5163
5164
|
for await (const manifest of glob(`${pattern}/package.json`, { cwd: root, exclude })) {
|
|
5164
5165
|
const location = realpathSync(dirname(join(root, manifest)));
|
|
5165
5166
|
const fromRoot = relative(root, location);
|
|
5166
|
-
if (!isAbsolute(fromRoot) && fromRoot !== ".." && !fromRoot.startsWith(`..${
|
|
5167
|
+
if (!isAbsolute(fromRoot) && fromRoot !== ".." && !fromRoot.startsWith(`..${process5.platform === "win32" ? "\\" : "/"}`))
|
|
5167
5168
|
directories.add(location);
|
|
5168
5169
|
}
|
|
5169
5170
|
}
|
|
5170
5171
|
const packages = /* @__PURE__ */ new Set(["@h-ai/cli", "@h-ai/deploy"]);
|
|
5171
5172
|
const drift = [];
|
|
5172
|
-
const catalog =
|
|
5173
|
+
const catalog = object2(workspace.catalog);
|
|
5173
5174
|
const lockPath = join(root, "pnpm-lock.yaml");
|
|
5174
5175
|
const lock = existsSync(lockPath) ? parseAllDocuments(readFileSync(lockPath, "utf8")).reduce((all, document) => {
|
|
5175
5176
|
if (document.errors.length)
|
|
5176
5177
|
throw new Error(cliM("cli_upgrade_lock_invalid"));
|
|
5177
|
-
const part =
|
|
5178
|
-
return { ...all, ...part, importers: { ...
|
|
5178
|
+
const part = object2(document.toJS());
|
|
5179
|
+
return { ...all, ...part, importers: { ...object2(all.importers), ...object2(part.importers) } };
|
|
5179
5180
|
}, {}) : {};
|
|
5180
5181
|
for (const location of directories) {
|
|
5181
|
-
const manifest =
|
|
5182
|
-
const dependencies = { ...
|
|
5183
|
-
const importer =
|
|
5182
|
+
const manifest = object2(JSON.parse(readFileSync(join(location, "package.json"), "utf8")));
|
|
5183
|
+
const dependencies = { ...object2(manifest.dependencies), ...object2(manifest.devDependencies), ...object2(manifest.optionalDependencies) };
|
|
5184
|
+
const importer = object2(object2(lock.importers)[relative(root, location).replaceAll("\\", "/") || "."]);
|
|
5184
5185
|
for (const [name, specifier] of Object.entries(dependencies)) {
|
|
5185
5186
|
if (!/^@h-ai\/[\w-]+$/.test(name) || typeof specifier !== "string")
|
|
5186
5187
|
continue;
|
|
5187
5188
|
packages.add(name);
|
|
5188
|
-
const declared = specifier.startsWith("catalog:") ? String(
|
|
5189
|
+
const declared = specifier.startsWith("catalog:") ? String(object2(specifier === "catalog:" ? catalog : object2(workspace.catalogs)[specifier.slice(8)])[name] ?? "") : specifier;
|
|
5189
5190
|
const issues = [];
|
|
5190
5191
|
if (declared !== version && !declared.startsWith("workspace:"))
|
|
5191
5192
|
issues.push("declared-version-drift");
|
|
@@ -5193,7 +5194,7 @@ async function inspectFrameworkUpgrade(directory, version) {
|
|
|
5193
5194
|
try {
|
|
5194
5195
|
const path10 = findPackageJSON(name, pathToFileURL(join(location, "package.json")));
|
|
5195
5196
|
if (path10) {
|
|
5196
|
-
const candidate =
|
|
5197
|
+
const candidate = object2(JSON.parse(readFileSync(path10, "utf8")));
|
|
5197
5198
|
if (candidate.name === name && typeof candidate.version === "string")
|
|
5198
5199
|
installed = candidate.version;
|
|
5199
5200
|
}
|
|
@@ -5201,13 +5202,13 @@ async function inspectFrameworkUpgrade(directory, version) {
|
|
|
5201
5202
|
}
|
|
5202
5203
|
if (installed !== version)
|
|
5203
5204
|
issues.push(installed ? "installed-version-drift" : "not-installed");
|
|
5204
|
-
const locked =
|
|
5205
|
+
const locked = object2(object2(importer.dependencies)[name] ?? object2(importer.devDependencies)[name] ?? object2(importer.optionalDependencies)[name]);
|
|
5205
5206
|
if (typeof locked.version !== "string" || !locked.version.startsWith("link:") && locked.version.split("(")[0] !== version)
|
|
5206
5207
|
issues.push("lock-version-drift");
|
|
5207
5208
|
drift.push({ package: name, source: relative(root, join(location, "package.json")).replaceAll("\\", "/"), declared, installed, issues });
|
|
5208
5209
|
}
|
|
5209
5210
|
}
|
|
5210
|
-
const registry = new URL(
|
|
5211
|
+
const registry = new URL(process5.env.npm_config_registry ?? "https://registry.npmjs.org/");
|
|
5211
5212
|
if (registry.username || registry.password || registry.protocol !== "https:")
|
|
5212
5213
|
throw new Error(cliM("cli_upgrade_registry"));
|
|
5213
5214
|
const releases = [];
|
|
@@ -5222,11 +5223,11 @@ async function inspectFrameworkUpgrade(directory, version) {
|
|
|
5222
5223
|
const response = await fetch(new URL(`${encodeURIComponent(name)}/${encodeURIComponent(version)}`, registry), { signal: AbortSignal.timeout(2e4) });
|
|
5223
5224
|
if (!response.ok)
|
|
5224
5225
|
throw new Error("Release missing");
|
|
5225
|
-
const metadata =
|
|
5226
|
-
const dist =
|
|
5226
|
+
const metadata = object2(await response.json());
|
|
5227
|
+
const dist = object2(metadata.dist);
|
|
5227
5228
|
if (metadata.version !== version || typeof dist.tarball !== "string" || typeof dist.integrity !== "string")
|
|
5228
5229
|
throw new Error("Invalid metadata");
|
|
5229
|
-
for (const dependency of Object.keys(
|
|
5230
|
+
for (const dependency of Object.keys(object2(metadata.dependencies))) {
|
|
5230
5231
|
if (/^@h-ai\/[\w-]+$/.test(dependency) && !packages.has(dependency)) {
|
|
5231
5232
|
packages.add(dependency);
|
|
5232
5233
|
pending.push(dependency);
|
|
@@ -5250,7 +5251,7 @@ async function inspectFrameworkUpgrade(directory, version) {
|
|
|
5250
5251
|
throw new Error("Integrity mismatch");
|
|
5251
5252
|
const files = tarFiles(bytes);
|
|
5252
5253
|
const manifest = files.get("package/package.json");
|
|
5253
|
-
if (!manifest ||
|
|
5254
|
+
if (!manifest || object2(JSON.parse(new TextDecoder().decode(manifest))).version !== version || !files.has("package/dist/index.js"))
|
|
5254
5255
|
throw new Error("Incomplete artifact");
|
|
5255
5256
|
const migration = { "@h-ai/iam": "migrateIam", "@h-ai/reach": "migrateReach", "@h-ai/scheduler": "migrateScheduler", "@h-ai/audit": "migrateAudit" }[name];
|
|
5256
5257
|
if (migration && declaresValueExport(new TextDecoder().decode(files.get("package/dist/index.d.ts")), migration) && declaresValueExport(new TextDecoder().decode(files.get("package/dist/index.js")), migration))
|
|
@@ -5277,13 +5278,13 @@ async function inspectFrameworkUpgrade(directory, version) {
|
|
|
5277
5278
|
dirtyFiles = execFileSync("git", ["status", "--porcelain", "--", "."], { cwd: root, encoding: "utf8", windowsHide: true, stdio: "pipe" }).trim().split("\n").filter(Boolean);
|
|
5278
5279
|
} catch {
|
|
5279
5280
|
}
|
|
5280
|
-
return { version, releaseComplete: releases.every((item) => item.available), modified: false, releases, drift, skills, dirtyFiles, customizations: { overrides: [.../* @__PURE__ */ new Set([...Object.keys(
|
|
5281
|
+
return { version, releaseComplete: releases.every((item) => item.available), modified: false, releases, drift, skills, dirtyFiles, customizations: { overrides: [.../* @__PURE__ */ new Set([...Object.keys(object2(workspace.overrides)), ...Object.keys(object2(rootManifest.overrides)), ...Object.keys(object2(object2(rootManifest.pnpm).overrides))])], patches: [.../* @__PURE__ */ new Set([...Object.keys(object2(workspace.patchedDependencies)), ...Object.keys(object2(object2(rootManifest.pnpm).patchedDependencies))])] }, migration: { preflight: migrationPreflight, inspectModuleReadmes: true, exclusiveAccess: true, backup: ["database", "shared-session-cache"], rollback: "restore-compatible-database-and-binaries", sessions: "legacy-credential-sessions-require-login" } };
|
|
5281
5282
|
}
|
|
5282
5283
|
async function upgradeCommand(version, options = {}) {
|
|
5283
|
-
const report = await inspectFrameworkUpgrade(options.cwd ??
|
|
5284
|
+
const report = await inspectFrameworkUpgrade(options.cwd ?? process5.cwd(), version);
|
|
5284
5285
|
writeCliMessage(JSON.stringify(report, null, 2));
|
|
5285
5286
|
if (!report.releaseComplete)
|
|
5286
|
-
|
|
5287
|
+
process5.exitCode = 1;
|
|
5287
5288
|
}
|
|
5288
5289
|
|
|
5289
5290
|
// src/cli-main.ts
|
|
@@ -5308,7 +5309,7 @@ cli.command("create [name]", cliM("cli_help_create")).option("--type <type>", cl
|
|
|
5308
5309
|
cwd: options.cwd
|
|
5309
5310
|
});
|
|
5310
5311
|
} catch {
|
|
5311
|
-
|
|
5312
|
+
process5.exitCode = 1;
|
|
5312
5313
|
}
|
|
5313
5314
|
});
|
|
5314
5315
|
cli.command("add [module]", cliM("cli_help_add")).option("--no-install", cliM("cli_help_noInstall")).action(async (module, options) => {
|
|
@@ -5320,7 +5321,7 @@ cli.command("add [module]", cliM("cli_help_add")).option("--no-install", cliM("c
|
|
|
5320
5321
|
cwd: options.cwd
|
|
5321
5322
|
});
|
|
5322
5323
|
} catch {
|
|
5323
|
-
|
|
5324
|
+
process5.exit(1);
|
|
5324
5325
|
}
|
|
5325
5326
|
});
|
|
5326
5327
|
cli.command("init", cliM("cli_help_init")).option("-f, --force", cliM("cli_help_forceConfig")).action(async (options) => {
|
|
@@ -5331,7 +5332,7 @@ cli.command("init", cliM("cli_help_init")).option("-f, --force", cliM("cli_help_
|
|
|
5331
5332
|
cwd: options.cwd
|
|
5332
5333
|
});
|
|
5333
5334
|
} catch {
|
|
5334
|
-
|
|
5335
|
+
process5.exit(1);
|
|
5335
5336
|
}
|
|
5336
5337
|
});
|
|
5337
5338
|
cli.command("generate [type] [name]", cliM("cli_help_generate")).option("-w, --workspace <name>", cliM("cli_help_workspace")).alias("g").option("-o, --output <path>", cliM("cli_help_output")).option("-f, --force", cliM("cli_help_force")).action(async (type, name, options) => {
|
|
@@ -5346,15 +5347,15 @@ cli.command("generate [type] [name]", cliM("cli_help_generate")).option("-w, --w
|
|
|
5346
5347
|
cwd: options.cwd
|
|
5347
5348
|
});
|
|
5348
5349
|
} catch {
|
|
5349
|
-
|
|
5350
|
+
process5.exit(1);
|
|
5350
5351
|
}
|
|
5351
5352
|
});
|
|
5352
|
-
cli.command("build", cliM("cli_help_build")).option("--target <target>", cliM("cli_help_target")).option("--images <names>", cliM("cli_help_images")).option("--concurrency <count>", cliM("cli_help_buildConcurrency")).option("--runtime <runtime>", cliM("cli_help_buildRuntime")).option("--network <network>", cliM("cli_help_buildNetwork")).option("--platform <platform>", cliM("cli_help_platform")).option("--arch <arch>", cliM("cli_help_arch")).option("--sqlite-prebuild-mirror <url>", cliM("cli_help_sqliteMirror")).option("--no-http-proxy", cliM("cli_help_noHttpProxy")).action(async (options) => {
|
|
5353
|
+
cli.command("build", cliM("cli_help_build")).option("--target <target>", cliM("cli_help_target")).option("--images <names>", cliM("cli_help_images")).option("--concurrency <count>", cliM("cli_help_buildConcurrency")).option("--runtime <runtime>", cliM("cli_help_buildRuntime")).option("--network <network>", cliM("cli_help_buildNetwork")).option("--platform <platform>", cliM("cli_help_platform")).option("--arch <arch>", cliM("cli_help_arch")).option("--sqlite-prebuild-mirror <url>", cliM("cli_help_sqliteMirror")).option("--no-http-proxy", cliM("cli_help_noHttpProxy")).option("-y, --yes", cliM("cli_help_deployYes")).option("--image-source <source>", cliM("cli_help_imageSource")).option("--image-mirrors <mappings>", cliM("cli_help_imageMirrors")).option("--npm-source <source>", cliM("cli_help_npmSource")).option("--npm-registry <url>", cliM("cli_help_npmRegistry")).option("--proxy-mode <mode>", cliM("cli_help_proxyMode")).option("--proxy-url <url>", cliM("cli_help_proxyUrl")).option("--proxy-bypass <hosts>", cliM("cli_help_proxyBypass")).action(async (options) => {
|
|
5353
5354
|
try {
|
|
5354
5355
|
await buildCommand(options);
|
|
5355
5356
|
} catch (error) {
|
|
5356
5357
|
writeCliMessage(error instanceof Error ? error.message : String(error));
|
|
5357
|
-
|
|
5358
|
+
process5.exitCode = 1;
|
|
5358
5359
|
}
|
|
5359
5360
|
});
|
|
5360
5361
|
cli.command("upgrade <version>", cliM("cli_help_upgrade")).action(async (version, options) => {
|
|
@@ -5362,10 +5363,10 @@ cli.command("upgrade <version>", cliM("cli_help_upgrade")).action(async (version
|
|
|
5362
5363
|
await upgradeCommand(version, options);
|
|
5363
5364
|
} catch (error) {
|
|
5364
5365
|
writeCliMessage(error instanceof Error ? error.message : String(error));
|
|
5365
|
-
|
|
5366
|
+
process5.exitCode = 1;
|
|
5366
5367
|
}
|
|
5367
5368
|
});
|
|
5368
|
-
cli.command("deploy [appDir]", cliM("cli_help_deploy")).option("--plan", cliM("cli_help_deployPlan")).option("--inspect-remote", cliM("cli_help_inspectRemote")).option("--env <environment>", cliM("cli_help_environment")).option("--env-dir <path>", cliM("cli_help_envDir")).option("-y, --yes", cliM("cli_help_deployYes")).option("--skip-middleware", cliM("cli_help_skipMiddleware")).option("--artifact-dir <path>", cliM("cli_help_artifactDir")).option("--services <names>", cliM("cli_help_services")).option("--build", cliM("cli_help_deployBuild")).option("--concurrency <count>", cliM("cli_help_buildConcurrency")).option("--network <network>", cliM("cli_help_deployNetwork")).option("--sqlite-prebuild-mirror <url>", cliM("cli_help_deploySqliteMirror")).option("--no-http-proxy", cliM("cli_help_deployNoProxy")).option("--runtime <runtime>", cliM("cli_help_deployRuntime")).option("--bundle-only", cliM("cli_help_bundleOnly")).option("--output <path>", cliM("cli_help_bundleOutput")).action(async (appDir, options) => {
|
|
5369
|
+
cli.command("deploy [appDir]", cliM("cli_help_deploy")).option("--plan", cliM("cli_help_deployPlan")).option("--inspect-remote", cliM("cli_help_inspectRemote")).option("--env <environment>", cliM("cli_help_environment")).option("--env-dir <path>", cliM("cli_help_envDir")).option("-y, --yes", cliM("cli_help_deployYes")).option("--skip-middleware", cliM("cli_help_skipMiddleware")).option("--artifact-dir <path>", cliM("cli_help_artifactDir")).option("--services <names>", cliM("cli_help_services")).option("--build", cliM("cli_help_deployBuild")).option("--concurrency <count>", cliM("cli_help_buildConcurrency")).option("--network <network>", cliM("cli_help_deployNetwork")).option("--sqlite-prebuild-mirror <url>", cliM("cli_help_deploySqliteMirror")).option("--no-http-proxy", cliM("cli_help_deployNoProxy")).option("--image-source <source>", cliM("cli_help_imageSource")).option("--image-mirrors <mappings>", cliM("cli_help_imageMirrors")).option("--npm-source <source>", cliM("cli_help_npmSource")).option("--npm-registry <url>", cliM("cli_help_npmRegistry")).option("--proxy-mode <mode>", cliM("cli_help_proxyMode")).option("--proxy-url <url>", cliM("cli_help_proxyUrl")).option("--proxy-bypass <hosts>", cliM("cli_help_proxyBypass")).option("--runtime <runtime>", cliM("cli_help_deployRuntime")).option("--bundle-only", cliM("cli_help_bundleOnly")).option("--output <path>", cliM("cli_help_bundleOutput")).action(async (appDir, options) => {
|
|
5369
5370
|
try {
|
|
5370
5371
|
await deployCommand({
|
|
5371
5372
|
appDir,
|
|
@@ -5382,6 +5383,13 @@ cli.command("deploy [appDir]", cliM("cli_help_deploy")).option("--plan", cliM("c
|
|
|
5382
5383
|
network: options.network,
|
|
5383
5384
|
sqlitePrebuildMirror: options.sqlitePrebuildMirror,
|
|
5384
5385
|
httpProxy: options.httpProxy,
|
|
5386
|
+
imageSource: options.imageSource,
|
|
5387
|
+
imageMirrors: options.imageMirrors,
|
|
5388
|
+
npmSource: options.npmSource,
|
|
5389
|
+
npmRegistry: options.npmRegistry,
|
|
5390
|
+
proxyMode: options.proxyMode,
|
|
5391
|
+
proxyUrl: options.proxyUrl,
|
|
5392
|
+
proxyBypass: options.proxyBypass,
|
|
5385
5393
|
runtime: options.runtime,
|
|
5386
5394
|
bundleOnly: options.bundleOnly,
|
|
5387
5395
|
output: options.output,
|
|
@@ -5389,7 +5397,7 @@ cli.command("deploy [appDir]", cliM("cli_help_deploy")).option("--plan", cliM("c
|
|
|
5389
5397
|
cwd: options.cwd
|
|
5390
5398
|
});
|
|
5391
5399
|
} catch {
|
|
5392
|
-
|
|
5400
|
+
process5.exitCode = 1;
|
|
5393
5401
|
}
|
|
5394
5402
|
});
|
|
5395
5403
|
cli.command("deploy-secrets <directory>", cliM("cli_help_deploySecrets")).option("--import <file>", cliM("cli_help_secretImport")).option("--apply", cliM("cli_help_secretApply")).option("--runtime <runtime>", cliM("cli_help_deployRuntime")).action(async (directory, options) => {
|
|
@@ -5397,7 +5405,7 @@ cli.command("deploy-secrets <directory>", cliM("cli_help_deploySecrets")).option
|
|
|
5397
5405
|
await deploySecretsCommand(directory, options);
|
|
5398
5406
|
} catch (error) {
|
|
5399
5407
|
writeCliMessage(error instanceof Error ? error.message : String(error));
|
|
5400
|
-
|
|
5408
|
+
process5.exitCode = 1;
|
|
5401
5409
|
}
|
|
5402
5410
|
});
|
|
5403
5411
|
cli.command("feedback <action> <bundle>", cliM("cli_help_feedback")).option("--page <number>", cliM("cli_feedback_page")).option("--page-size <number>", cliM("cli_feedback_pageSize")).option("--kind <kind>", cliM("cli_feedback_kind")).option("--request-id <id>", cliM("cli_feedback_requestId")).option("--error-id <id>", cliM("cli_feedback_errorId")).option("--from <timestamp>", cliM("cli_feedback_from")).option("--to <timestamp>", cliM("cli_feedback_to")).option("--port <number>", cliM("cli_feedback_port")).action(async (action, bundle, options) => {
|
|
@@ -5416,7 +5424,7 @@ cli.command("feedback <action> <bundle>", cliM("cli_help_feedback")).option("--p
|
|
|
5416
5424
|
});
|
|
5417
5425
|
} catch (error) {
|
|
5418
5426
|
writeCliMessage(error instanceof Error ? error.message : String(error));
|
|
5419
|
-
|
|
5427
|
+
process5.exitCode = 1;
|
|
5420
5428
|
}
|
|
5421
5429
|
});
|
|
5422
5430
|
cli.command("g:page <name>", cliM("cli_help_generatePage")).option("-w, --workspace <name>", cliM("cli_help_workspace")).action(async (name, options) => {
|