@h-ai/cli 1.0.0-beta.4 → 1.0.0-beta.6
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 +21 -7
- package/README.ja.md +21 -7
- package/README.md +21 -7
- package/dist/{chunk-K6RWTTHD.js → chunk-4XVCGFBA.js} +6143 -667
- package/dist/chunk-4XVCGFBA.js.map +1 -0
- package/dist/{chunk-SWEU7KUE.js → chunk-7DNIMG2H.js} +92 -17
- package/dist/chunk-7DNIMG2H.js.map +1 -0
- package/dist/{chunk-YVNNMC4H.js → chunk-STWZQ3IP.js} +59 -3
- package/dist/chunk-STWZQ3IP.js.map +1 -0
- package/dist/cli-config-templates-YGPVNRX5.js +5 -0
- package/dist/{cli-config-templates-LUJGDQNW.js.map → cli-config-templates-YGPVNRX5.js.map} +1 -1
- package/dist/{cli-skill-templates-VV2XWYON.js → cli-skill-templates-S2YH642Z.js} +3 -3
- package/dist/{cli-skill-templates-VV2XWYON.js.map → cli-skill-templates-S2YH642Z.js.map} +1 -1
- package/dist/index.js +362 -359
- package/dist/index.js.map +1 -1
- package/dist/metafile-esm.json +1 -1
- package/dist/src-NXCCU6GO.js +5 -0
- package/dist/src-NXCCU6GO.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 +4 -4
- 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 +3 -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/guide.md +1 -1
- package/templates/skills/hai-app-create/development.md +8 -7
- package/templates/skills/hai-build/SKILL.md +4 -1
- package/templates/skills/hai-build/paths.md +2 -0
- package/templates/skills/hai-build/reference.md +15 -1
- 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 +13 -3
- package/templates/skills/hai-deploy/middleware.md +9 -9
- package/templates/skills/hai-iam/reference.md +2 -2
- package/templates/skills/hai-serv/SKILL.md +1 -0
- package/templates/skills/hai-serv/reference.md +1 -1
- package/dist/chunk-K6RWTTHD.js.map +0 -1
- package/dist/chunk-SWEU7KUE.js.map +0 -1
- package/dist/chunk-YVNNMC4H.js.map +0 -1
- package/dist/cli-config-templates-LUJGDQNW.js +0 -5
- package/dist/src-IR5AU43K.js +0 -5
- package/dist/src-IR5AU43K.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-STWZQ3IP.js';
|
|
3
|
+
import { cliM } from './chunk-7DNIMG2H.js';
|
|
4
|
+
import { normalizeProjectName, resolveImageReference, resolveDownloadProxy } from './chunk-4XVCGFBA.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());
|
|
@@ -828,6 +832,7 @@ async function generateFromTemplates(projectPath, context) {
|
|
|
828
832
|
}
|
|
829
833
|
await renderDynamicFiles(root, projectPath, context);
|
|
830
834
|
await fse.copy(path2.join(root, "shared", "run-e2e.mjs"), path2.join(projectPath, "scripts", "run-e2e.mjs"));
|
|
835
|
+
await fse.copy(path2.join(root, "shared", "run-node.mjs"), path2.join(projectPath, "scripts", "run-node.mjs"));
|
|
831
836
|
await fse.copy(path2.join(root, "shared", "e2e-env.ts"), path2.join(projectPath, "scripts", "e2e-env.ts"));
|
|
832
837
|
await fse.copy(path2.join(root, "shared", "build-metadata.ts"), path2.join(projectPath, "scripts", "build-metadata.ts"));
|
|
833
838
|
await fse.copy(path2.join(root, "shared", "public-base-path.mjs"), path2.join(projectPath, "scripts", "public-base-path.mjs"));
|
|
@@ -1266,7 +1271,7 @@ async function createProject(options) {
|
|
|
1266
1271
|
});
|
|
1267
1272
|
await generateFromTemplates(projectPath, context);
|
|
1268
1273
|
{
|
|
1269
|
-
const { generateConfigFile: generateConfigFile2, generateEnvExample, generateProductionEnvironment: generateProductionEnvironment2 } = await import('./cli-config-templates-
|
|
1274
|
+
const { generateConfigFile: generateConfigFile2, generateEnvExample, generateProductionEnvironment: generateProductionEnvironment2 } = await import('./cli-config-templates-YGPVNRX5.js');
|
|
1270
1275
|
const configs = resolvedOptions.moduleConfigs;
|
|
1271
1276
|
const isApiWorkspace = resolvedOptions.appType === "api";
|
|
1272
1277
|
const isFullstack = resolvedOptions.appType === "fullstack";
|
|
@@ -1333,13 +1338,14 @@ ${runtimeExample.split("\n").map((line) => line && !line.startsWith("#") ? `# ${
|
|
|
1333
1338
|
${sharedVariables.join("\n")}
|
|
1334
1339
|
`);
|
|
1335
1340
|
for (const [mode, environment] of [["dev", "development"], ["test", "test"], ["prod", "production"]]) {
|
|
1336
|
-
let
|
|
1341
|
+
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";
|
|
1342
|
+
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
1343
|
HAI_CORE_ENV=${environment}
|
|
1338
1344
|
HAI_CORE_LOGGING_LEVEL=${mode === "test" ? "warn" : "debug"}
|
|
1339
1345
|
`;
|
|
1340
1346
|
if (isFullstack) {
|
|
1341
1347
|
for (const name of ["HAI_ADMIN_DEFAULT_PASSWORD", "HAI_AUDIT_ADMIN_PASSWORD", "HAI_CONFIG_ADMIN_PASSWORD", "HAI_BUSINESS_OPERATOR_PASSWORD"])
|
|
1342
|
-
|
|
1348
|
+
privateValues += `
|
|
1343
1349
|
${name}=Aa1!${randomBytes(24).toString("base64url")}
|
|
1344
1350
|
`;
|
|
1345
1351
|
}
|
|
@@ -1348,15 +1354,16 @@ ${name}=Aa1!${randomBytes(24).toString("base64url")}
|
|
|
1348
1354
|
key.generateKeys();
|
|
1349
1355
|
const id = `${mode}-${randomBytes(6).toString("hex")}`;
|
|
1350
1356
|
const ring = { activeKeyId: id, keys: { [id]: { publicKey: key.getPublicKey("hex"), privateKey: key.getPrivateKey("hex").padStart(64, "0") } } };
|
|
1351
|
-
|
|
1357
|
+
privateValues += `
|
|
1352
1358
|
HAI_CRYPTO_TRANSPORT_SERVERKEYRING='${JSON.stringify(ring)}'
|
|
1353
1359
|
`;
|
|
1354
1360
|
}
|
|
1355
1361
|
await writeFile(path2.join(envDirectory, `.env.${mode}`), values);
|
|
1362
|
+
await fse.writeFile(path2.join(envDirectory, `.env.${mode}.local`), privateValues, { mode: 384 });
|
|
1356
1363
|
}
|
|
1357
|
-
await fse.writeFile(path2.join(envDirectory, ".env.local"), "# \u672C\u673A\u79C1\u6709\u8986\u76D6\uFF0C\u4E0D\u63D0\u4EA4 Git\uFF1B\u521D\u59CB\
|
|
1364
|
+
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
1365
|
}
|
|
1359
|
-
const { generateSkillFiles } = await import('./cli-skill-templates-
|
|
1366
|
+
const { generateSkillFiles } = await import('./cli-skill-templates-S2YH642Z.js');
|
|
1360
1367
|
await generateSkillFiles(
|
|
1361
1368
|
projectPath,
|
|
1362
1369
|
resolvedOptions.features,
|
|
@@ -1403,7 +1410,7 @@ async function resolveOptions(options) {
|
|
|
1403
1410
|
writeCliMessage("");
|
|
1404
1411
|
const onCancel = () => {
|
|
1405
1412
|
writeCliMessage(chalk.red(cliM("cli_cancelledLine")));
|
|
1406
|
-
|
|
1413
|
+
process5.exit(1);
|
|
1407
1414
|
};
|
|
1408
1415
|
let projectName = options.name;
|
|
1409
1416
|
if (!projectName && useDefaults) {
|
|
@@ -1607,7 +1614,7 @@ async function promptModuleConfigs(features, projectName) {
|
|
|
1607
1614
|
const configs = {};
|
|
1608
1615
|
const onCancel = () => {
|
|
1609
1616
|
writeCliMessage(chalk.red(cliM("cli_cancelledLine")));
|
|
1610
|
-
|
|
1617
|
+
process5.exit(1);
|
|
1611
1618
|
};
|
|
1612
1619
|
writeCliMessage("");
|
|
1613
1620
|
writeCliMessage(chalk.bold(cliM("cli_createModuleConfig")));
|
|
@@ -1848,7 +1855,7 @@ function generateAiDevelopmentReadme() {
|
|
|
1848
1855
|
function generateEnvironmentReadme() {
|
|
1849
1856
|
return `### \u5206\u73AF\u5883\u914D\u7F6E
|
|
1850
1857
|
|
|
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
|
|
1858
|
+
\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
|
|
1852
1859
|
|
|
1853
1860
|
\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\u3002AI \u81EA\u52A8\u8865\u5168 db+vecdb \u4F9D\u8D56\uFF0C\u5E76\u5728\u4E8C\u8005\u5C31\u7EEA\u540E\u521D\u59CB\u5316\uFF0C\u5931\u8D25\u9006\u5E8F\u6E05\u7406\u3002
|
|
1854
1861
|
|
|
@@ -1873,6 +1880,7 @@ function generateBuildDeploymentReadme(pm, appDir) {
|
|
|
1873
1880
|
|
|
1874
1881
|
\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
1882
|
\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
|
|
1883
|
+
\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
1884
|
\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
1885
|
\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
1886
|
|
|
@@ -1896,7 +1904,7 @@ ${pm} exec hai deploy ${appDir} --env prod --services web
|
|
|
1896
1904
|
\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
1905
|
\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
1906
|
\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\
|
|
1907
|
+
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
1908
|
\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
1909
|
\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
1910
|
`;
|
|
@@ -2079,7 +2087,7 @@ Web/App/Desktop \u5171\u4EAB AppShell \u7684 header/footer\u3002\u65B0\u589E\u98
|
|
|
2079
2087
|
|
|
2080
2088
|
${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
2089
|
|
|
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\
|
|
2090
|
+
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
2091
|
|
|
2084
2092
|
\`_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
2093
|
|
|
@@ -2087,7 +2095,7 @@ CLI \u5728\u6839\u76EE\u5F55 .env.dev\u3001.env.test\u3001.env.prod \u4E2D\u4E3A
|
|
|
2087
2095
|
|
|
2088
2096
|
\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
2097
|
|
|
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
|
|
2098
|
+
\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
2099
|
|
|
2092
2100
|
\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
2101
|
|
|
@@ -2332,7 +2340,7 @@ async function addModule(options) {
|
|
|
2332
2340
|
writeCliMessage(cliM("cli_addAvailableModules", { params: { modules: Object.keys(MODULE_MAP).join(", ") } }));
|
|
2333
2341
|
return;
|
|
2334
2342
|
}
|
|
2335
|
-
const { generateProjectAiSupport, resolveSkillNamesForPackages } = await import('./cli-skill-templates-
|
|
2343
|
+
const { generateProjectAiSupport, resolveSkillNamesForPackages } = await import('./cli-skill-templates-S2YH642Z.js');
|
|
2336
2344
|
if (moduleDef.packages.every((p) => project.haiPackages.includes(p))) {
|
|
2337
2345
|
if (moduleName === "deploy")
|
|
2338
2346
|
await ensureDeployConfig(cwd);
|
|
@@ -2454,7 +2462,7 @@ ${production.join("\n")}`);
|
|
|
2454
2462
|
}
|
|
2455
2463
|
}
|
|
2456
2464
|
async function buildMobileApp(root, directories, platform, run2) {
|
|
2457
|
-
if (!directories.length || platform === "ios" &&
|
|
2465
|
+
if (!directories.length || platform === "ios" && process5.platform !== "darwin")
|
|
2458
2466
|
throw new Error(cliM("cli_build_app_platform"));
|
|
2459
2467
|
const outputs = [];
|
|
2460
2468
|
for (const item of directories) {
|
|
@@ -2492,31 +2500,240 @@ async function buildMobileApp(root, directories, platform, run2) {
|
|
|
2492
2500
|
}
|
|
2493
2501
|
return outputs;
|
|
2494
2502
|
}
|
|
2503
|
+
function object(value) {
|
|
2504
|
+
if (value === void 0)
|
|
2505
|
+
return {};
|
|
2506
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
2507
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2508
|
+
return value;
|
|
2509
|
+
}
|
|
2510
|
+
function registryUrl(value) {
|
|
2511
|
+
try {
|
|
2512
|
+
if (typeof value !== "string")
|
|
2513
|
+
throw new Error("Missing registry");
|
|
2514
|
+
const url = new URL(value);
|
|
2515
|
+
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.search || url.hash)
|
|
2516
|
+
throw new Error("Invalid registry");
|
|
2517
|
+
return url.toString().replace(/\/$/, "");
|
|
2518
|
+
} catch {
|
|
2519
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
async function resolveBuildDownloads(directory, options) {
|
|
2523
|
+
const path10 = projectConfigPath(directory);
|
|
2524
|
+
const project = readProjectConfig(path10);
|
|
2525
|
+
const build = object(project.build);
|
|
2526
|
+
const sources = object(build.sources);
|
|
2527
|
+
const savedImage = object(sources.image);
|
|
2528
|
+
const savedNpm = object(sources.npm);
|
|
2529
|
+
const savedProxy = object(build.proxy);
|
|
2530
|
+
const interactive = !!process5.stdin.isTTY && !options.yes;
|
|
2531
|
+
const choose = async (message, values) => {
|
|
2532
|
+
const answer = await prompts({ type: "select", name: "value", message, choices: values.map((value) => ({ title: cliM(`cli_download_${value}`), value })) });
|
|
2533
|
+
if (typeof answer.value !== "string")
|
|
2534
|
+
throw new Error(cliM("cli_deploy_cancelled"));
|
|
2535
|
+
return answer.value;
|
|
2536
|
+
};
|
|
2537
|
+
const mirrorEntries = options.imageMirrors?.split(",").map((entry) => {
|
|
2538
|
+
const separator = entry.indexOf("=");
|
|
2539
|
+
if (separator <= 0 || separator === entry.length - 1)
|
|
2540
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2541
|
+
return [entry.slice(0, separator).trim(), entry.slice(separator + 1).trim()];
|
|
2542
|
+
});
|
|
2543
|
+
if (mirrorEntries && new Set(mirrorEntries.map(([key]) => key)).size !== mirrorEntries.length)
|
|
2544
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2545
|
+
let imageType = options.imageSource ?? (mirrorEntries ? "custom" : savedImage.type);
|
|
2546
|
+
let npmType = options.npmSource ?? (options.npmRegistry ? "custom" : savedNpm.type);
|
|
2547
|
+
const saveImage = imageType === void 0 && interactive;
|
|
2548
|
+
const saveNpm = npmType === void 0 && interactive;
|
|
2549
|
+
if (saveImage)
|
|
2550
|
+
imageType = await choose(cliM("cli_download_choose_image"), ["official", "cn", "custom"]);
|
|
2551
|
+
if (saveNpm)
|
|
2552
|
+
npmType = await choose(cliM("cli_download_choose_npm"), ["official", "cn", "custom"]);
|
|
2553
|
+
imageType ??= "official";
|
|
2554
|
+
npmType ??= "official";
|
|
2555
|
+
if (typeof imageType !== "string" || !["official", "cn", "custom"].includes(imageType) || typeof npmType !== "string" || !["official", "cn", "custom"].includes(npmType))
|
|
2556
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2557
|
+
let registries = mirrorEntries ? Object.fromEntries(mirrorEntries) : savedImage.registries;
|
|
2558
|
+
if (imageType === "custom" && !registries && interactive) {
|
|
2559
|
+
const answer = await prompts({ type: "text", name: "value", message: cliM("cli_download_image_mirrors") });
|
|
2560
|
+
if (typeof answer.value !== "string" || !answer.value.trim())
|
|
2561
|
+
throw new Error(cliM("cli_deploy_cancelled"));
|
|
2562
|
+
registries = Object.fromEntries(answer.value.split(",").map((entry) => {
|
|
2563
|
+
const index = entry.indexOf("=");
|
|
2564
|
+
if (index <= 0)
|
|
2565
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2566
|
+
return [entry.slice(0, index).trim(), entry.slice(index + 1).trim()];
|
|
2567
|
+
}));
|
|
2568
|
+
}
|
|
2569
|
+
const mappings = registries === void 0 ? void 0 : object(registries);
|
|
2570
|
+
if (mappings && Object.entries(mappings).some(([key, value]) => !/^[\w.-]+(?::\d+)?$/.test(key) || typeof value !== "string"))
|
|
2571
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2572
|
+
const imageSource = { type: imageType, ...imageType === "custom" ? { registries: mappings } : {} };
|
|
2573
|
+
if (mirrorEntries && imageType !== "custom")
|
|
2574
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2575
|
+
if (imageType === "custom") {
|
|
2576
|
+
if (!mappings || !Object.keys(mappings).length)
|
|
2577
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2578
|
+
for (const key of Object.keys(mappings)) resolveImageReference(`${key}/hai-source-check:1`, imageSource);
|
|
2579
|
+
}
|
|
2580
|
+
let customRegistry = options.npmRegistry ?? savedNpm.registry;
|
|
2581
|
+
if (npmType === "custom" && !customRegistry && interactive) {
|
|
2582
|
+
const answer = await prompts({ type: "text", name: "value", message: cliM("cli_download_npm_registry") });
|
|
2583
|
+
if (typeof answer.value !== "string" || !answer.value.trim())
|
|
2584
|
+
throw new Error(cliM("cli_deploy_cancelled"));
|
|
2585
|
+
customRegistry = answer.value;
|
|
2586
|
+
}
|
|
2587
|
+
if (options.npmRegistry && npmType !== "custom")
|
|
2588
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2589
|
+
const npmRegistry = npmType === "cn" ? "https://registry.npmmirror.com" : npmType === "official" ? "https://registry.npmjs.org" : registryUrl(customRegistry);
|
|
2590
|
+
const npmSource = { type: npmType, ...npmType === "custom" ? { registry: npmRegistry } : {} };
|
|
2591
|
+
let proxyMode = options.proxyMode ?? (options.proxyUrl ? "custom" : savedProxy.mode);
|
|
2592
|
+
const saveProxy = proxyMode === void 0 && interactive && options.httpProxy !== false;
|
|
2593
|
+
if (saveProxy)
|
|
2594
|
+
proxyMode = await choose(cliM("cli_download_choose_proxy"), ["inherit", "system", "custom", "none"]);
|
|
2595
|
+
proxyMode ??= "inherit";
|
|
2596
|
+
if (options.proxyUrl !== void 0 && proxyMode !== "custom")
|
|
2597
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2598
|
+
if (typeof proxyMode !== "string" || !["inherit", "system", "custom", "none"].includes(proxyMode))
|
|
2599
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2600
|
+
if (options.httpProxy === false && (options.proxyUrl !== void 0 || options.proxyMode !== void 0 && options.proxyMode !== "none"))
|
|
2601
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2602
|
+
let proxyUrl = options.proxyUrl ?? savedProxy.url;
|
|
2603
|
+
if (proxyMode === "custom" && !proxyUrl && interactive) {
|
|
2604
|
+
const answer = await prompts({ type: "text", name: "value", message: cliM("cli_download_proxy_url") });
|
|
2605
|
+
if (typeof answer.value !== "string" || !answer.value.trim())
|
|
2606
|
+
throw new Error(cliM("cli_deploy_cancelled"));
|
|
2607
|
+
proxyUrl = answer.value;
|
|
2608
|
+
}
|
|
2609
|
+
const bypass = options.proxyBypass ?? savedProxy.bypass;
|
|
2610
|
+
if (proxyUrl !== void 0 && typeof proxyUrl !== "string" || bypass !== void 0 && typeof bypass !== "string")
|
|
2611
|
+
throw new Error(cliM("cli_download_invalid"));
|
|
2612
|
+
const proxy = { mode: options.httpProxy === false ? "none" : proxyMode, ...proxyMode === "custom" && options.httpProxy !== false ? { url: proxyUrl } : {}, ...bypass !== void 0 ? { bypass } : {} };
|
|
2613
|
+
resolveDownloadProxy(proxy);
|
|
2614
|
+
if (saveImage || saveNpm || saveProxy) {
|
|
2615
|
+
project.build = { ...build, sources: { ...sources, ...saveImage ? { image: imageSource } : {}, ...saveNpm ? { npm: npmSource } : {} }, ...saveProxy ? { proxy } : {} };
|
|
2616
|
+
writeFileSync(path10, `${JSON.stringify(project, null, 2)}
|
|
2617
|
+
`);
|
|
2618
|
+
}
|
|
2619
|
+
return { imageSource, npmRegistry, npmSource, proxy };
|
|
2620
|
+
}
|
|
2621
|
+
function buildProxyArguments(proxy, runtime, network) {
|
|
2622
|
+
const environment = resolveDownloadProxy(proxy);
|
|
2623
|
+
for (const key of ["HTTP_PROXY", "HTTPS_PROXY", "http_proxy", "https_proxy", "ALL_PROXY", "all_proxy"]) {
|
|
2624
|
+
if (!environment[key])
|
|
2625
|
+
continue;
|
|
2626
|
+
const url = new URL(environment[key]);
|
|
2627
|
+
if (network !== "host" && (runtime === "docker" || network !== void 0) && ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname)) {
|
|
2628
|
+
url.hostname = runtime === "podman" ? "host.containers.internal" : "host.docker.internal";
|
|
2629
|
+
environment[key] = url.toString().replace(/\/$/, "");
|
|
2630
|
+
}
|
|
2631
|
+
}
|
|
2632
|
+
return Object.entries(environment).flatMap(([key, value]) => ["--build-arg", `${key}=${value}`]);
|
|
2633
|
+
}
|
|
2634
|
+
async function preflightDownloadProxy(runtime, proxy) {
|
|
2635
|
+
const environment = resolveDownloadProxy(proxy);
|
|
2636
|
+
for (const value of new Set([environment.HTTP_PROXY, environment.HTTPS_PROXY].filter(Boolean))) {
|
|
2637
|
+
const url = new URL(value);
|
|
2638
|
+
await new Promise((resolve7, reject) => {
|
|
2639
|
+
const socket = connect({ host: url.hostname.replace(/^\[|\]$/g, ""), port: Number(url.port || (url.protocol === "https:" ? 443 : 80)) });
|
|
2640
|
+
socket.setTimeout(3e3);
|
|
2641
|
+
socket.once("connect", () => {
|
|
2642
|
+
socket.destroy();
|
|
2643
|
+
resolve7();
|
|
2644
|
+
});
|
|
2645
|
+
const fail = () => {
|
|
2646
|
+
socket.destroy();
|
|
2647
|
+
reject(new Error(cliM("cli_download_proxy_unreachable")));
|
|
2648
|
+
};
|
|
2649
|
+
socket.once("error", fail);
|
|
2650
|
+
socket.once("timeout", fail);
|
|
2651
|
+
});
|
|
2652
|
+
}
|
|
2653
|
+
if (!environment.HTTP_PROXY && !environment.HTTPS_PROXY)
|
|
2654
|
+
return;
|
|
2655
|
+
for (const candidate of runtime === "auto" ? ["podman", "docker"] : [runtime]) {
|
|
2656
|
+
try {
|
|
2657
|
+
const data = JSON.parse(execFileSync(candidate, ["info", "--format", "{{json .}}"], { encoding: "utf8", windowsHide: true, timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }));
|
|
2658
|
+
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 } }));
|
|
2659
|
+
return;
|
|
2660
|
+
} catch {
|
|
2661
|
+
}
|
|
2662
|
+
}
|
|
2663
|
+
writeCliMessage(cliM("cli_download_engine_proxy_hint", { params: { runtime } }));
|
|
2664
|
+
}
|
|
2665
|
+
function validateDownloadDockerfile(file, downloads) {
|
|
2666
|
+
const content = readFileSync(file, "utf8");
|
|
2667
|
+
if (downloads.imageSource.type !== "official" && !/^ARG HAI_NODE_IMAGE=/m.test(content) || downloads.npmSource.type !== "official" && !/^ARG HAI_NPM_REGISTRY[=\s]/m.test(content)) {
|
|
2668
|
+
throw new Error(cliM("cli_download_template_required", { params: { path: file } }));
|
|
2669
|
+
}
|
|
2670
|
+
}
|
|
2671
|
+
function createWindowsBuildOutput() {
|
|
2672
|
+
const decoder = new StringDecoder("utf8");
|
|
2673
|
+
let previousCarriageReturn = false;
|
|
2674
|
+
const normalize = (value) => {
|
|
2675
|
+
const result = value.replace(/\n/g, (newline, offset) => (offset === 0 ? previousCarriageReturn : value[offset - 1] === "\r") ? newline : "\r\n");
|
|
2676
|
+
if (value.length)
|
|
2677
|
+
previousCarriageReturn = value.endsWith("\r");
|
|
2678
|
+
return result;
|
|
2679
|
+
};
|
|
2680
|
+
return new Transform({
|
|
2681
|
+
transform(chunk, _encoding, callback) {
|
|
2682
|
+
callback(null, normalize(decoder.write(chunk)));
|
|
2683
|
+
},
|
|
2684
|
+
flush(callback) {
|
|
2685
|
+
callback(null, normalize(decoder.end()));
|
|
2686
|
+
}
|
|
2687
|
+
});
|
|
2688
|
+
}
|
|
2689
|
+
async function forwardWindowsBuildOutput(source, destination) {
|
|
2690
|
+
const forwarding = new Writable({
|
|
2691
|
+
write(chunk, encoding, callback) {
|
|
2692
|
+
destination.write(chunk, encoding, callback);
|
|
2693
|
+
}
|
|
2694
|
+
});
|
|
2695
|
+
await pipeline(source, createWindowsBuildOutput(), forwarding);
|
|
2696
|
+
}
|
|
2495
2697
|
|
|
2496
2698
|
// src/commands/cli-build.ts
|
|
2497
2699
|
async function run(command, args, cwd, quiet = false, identity, compileEnvironment) {
|
|
2498
2700
|
await new Promise((resolve7, reject) => {
|
|
2499
|
-
const env = Object.fromEntries(Object.entries(
|
|
2701
|
+
const env = Object.fromEntries(Object.entries(process5.env).filter(([key]) => !/^(?:HAI_|PUBLIC_|VITE_)/.test(key)));
|
|
2500
2702
|
Object.assign(env, compileEnvironment);
|
|
2501
2703
|
if (identity) {
|
|
2502
2704
|
env.HAI_BUILD_ID = identity.buildId;
|
|
2503
2705
|
env.HAI_BUILD_COMMIT = identity.commit;
|
|
2504
2706
|
}
|
|
2505
2707
|
env.NODE_ENV = "production";
|
|
2708
|
+
if (process5.platform === "win32") {
|
|
2709
|
+
env.npm_config_reporter = "append-only";
|
|
2710
|
+
env.pnpm_config_reporter = "append-only";
|
|
2711
|
+
}
|
|
2506
2712
|
delete env.CAPACITOR_SERVER_URL;
|
|
2507
2713
|
if (env.CI === "1" || env.CI === "0")
|
|
2508
2714
|
env.CI = env.CI === "1" ? "true" : "false";
|
|
2509
|
-
const
|
|
2715
|
+
const windowsOutput = !quiet && process5.platform === "win32";
|
|
2716
|
+
const child = spawn(command, args, { cwd, env, windowsHide: true, stdio: quiet ? "ignore" : windowsOutput ? ["inherit", "pipe", "pipe"] : "inherit", shell: false });
|
|
2717
|
+
let output = Promise.resolve();
|
|
2718
|
+
if (windowsOutput && child.stdout && child.stderr) {
|
|
2719
|
+
output = Promise.all([
|
|
2720
|
+
forwardWindowsBuildOutput(child.stdout, process5.stdout),
|
|
2721
|
+
forwardWindowsBuildOutput(child.stderr, process5.stderr)
|
|
2722
|
+
]).then(() => void 0);
|
|
2723
|
+
void output.catch(() => child.kill());
|
|
2724
|
+
}
|
|
2510
2725
|
child.once("error", reject);
|
|
2511
|
-
child.once(
|
|
2726
|
+
child.once(windowsOutput && child.stdout && child.stderr ? "close" : "exit", (code) => {
|
|
2727
|
+
void output.then(() => code === 0 ? resolve7() : reject(new Error(cliM("cli_build_failed", { params: { command, code: String(code) } }))), reject);
|
|
2728
|
+
});
|
|
2512
2729
|
});
|
|
2513
2730
|
}
|
|
2514
2731
|
async function pnpm(args, cwd, identity, compileEnvironment) {
|
|
2515
|
-
const entry =
|
|
2732
|
+
const entry = process5.env.npm_execpath;
|
|
2516
2733
|
if (entry && /(?:^|[/\\])pnpm(?:-native)?(?:\.exe|\.[cm]?js)?$/i.test(entry))
|
|
2517
|
-
return /\.[cm]?js$/i.test(entry) ? run(
|
|
2518
|
-
if (
|
|
2519
|
-
const directories = (
|
|
2734
|
+
return /\.[cm]?js$/i.test(entry) ? run(process5.execPath, [entry, ...args], cwd, false, identity, compileEnvironment) : run(entry, args, cwd, false, identity, compileEnvironment);
|
|
2735
|
+
if (process5.platform === "win32") {
|
|
2736
|
+
const directories = (process5.env.PATH ?? "").split(";");
|
|
2520
2737
|
for (const directory of directories) {
|
|
2521
2738
|
const executable = join(directory, "pnpm.exe");
|
|
2522
2739
|
if (existsSync(executable))
|
|
@@ -2524,7 +2741,7 @@ async function pnpm(args, cwd, identity, compileEnvironment) {
|
|
|
2524
2741
|
for (const relative4 of ["node_modules/pnpm/bin/pnpm.cjs", "pnpm.cjs"]) {
|
|
2525
2742
|
const candidate = join(directory, relative4);
|
|
2526
2743
|
if (existsSync(candidate))
|
|
2527
|
-
return run(
|
|
2744
|
+
return run(process5.execPath, [candidate, ...args], cwd, false, identity, compileEnvironment);
|
|
2528
2745
|
}
|
|
2529
2746
|
}
|
|
2530
2747
|
throw new Error(cliM("cli_build_use_pnpm"));
|
|
@@ -2532,8 +2749,8 @@ async function pnpm(args, cwd, identity, compileEnvironment) {
|
|
|
2532
2749
|
return run("pnpm", args, cwd, false, identity, compileEnvironment);
|
|
2533
2750
|
}
|
|
2534
2751
|
function staticCompileEnvironment(target) {
|
|
2535
|
-
const flag =
|
|
2536
|
-
const base =
|
|
2752
|
+
const flag = process5.env.HAI_BUILD_STATIC;
|
|
2753
|
+
const base = process5.env.PUBLIC_BASE_PATH;
|
|
2537
2754
|
if (flag !== void 0 && flag !== "" && flag !== "0" && flag !== "1")
|
|
2538
2755
|
throw new Error(cliM("cli_build_static_flag"));
|
|
2539
2756
|
if (base && (!/^\/[\w.-]+(?:\/[\w.-]+)*$/.test(base) || base.split("/").some((segment) => segment === "." || segment === "..")))
|
|
@@ -2560,7 +2777,7 @@ function sourceCommit(cwd) {
|
|
|
2560
2777
|
}
|
|
2561
2778
|
}
|
|
2562
2779
|
async function buildCommand(options) {
|
|
2563
|
-
const directory = resolve(options.cwd ??
|
|
2780
|
+
const directory = resolve(options.cwd ?? process5.cwd());
|
|
2564
2781
|
const target = options.target ?? "compile";
|
|
2565
2782
|
const concurrency = Number(options.concurrency ?? 2);
|
|
2566
2783
|
if (![1, 2].includes(concurrency))
|
|
@@ -2569,7 +2786,7 @@ async function buildCommand(options) {
|
|
|
2569
2786
|
if (!["compile", "image", "desktop", "app"].includes(target))
|
|
2570
2787
|
throw new Error(cliM("cli_build_target_invalid"));
|
|
2571
2788
|
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) {
|
|
2789
|
+
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
2790
|
throw new Error(cliM("cli_build_options_invalid"));
|
|
2574
2791
|
}
|
|
2575
2792
|
if (target === "compile") {
|
|
@@ -2592,9 +2809,9 @@ async function buildCommand(options) {
|
|
|
2592
2809
|
}
|
|
2593
2810
|
if (target === "desktop") {
|
|
2594
2811
|
const platforms = { win32: "windows", linux: "linux", darwin: "macos" };
|
|
2595
|
-
const host = platforms[
|
|
2812
|
+
const host = platforms[process5.platform];
|
|
2596
2813
|
const platform = options.platform ?? host;
|
|
2597
|
-
const arch = options.arch ??
|
|
2814
|
+
const arch = options.arch ?? process5.arch;
|
|
2598
2815
|
if (!platform || platform !== host || !["x64", "arm64"].includes(arch))
|
|
2599
2816
|
throw new Error(cliM("cli_build_native_host"));
|
|
2600
2817
|
if (!config.desktop?.length)
|
|
@@ -2624,6 +2841,8 @@ async function buildCommand(options) {
|
|
|
2624
2841
|
if (!existsSync(resolve(cwd, image.dockerfile)))
|
|
2625
2842
|
throw new Error(cliM("cli_build_dockerfile_missing", { params: { path: image.dockerfile } }));
|
|
2626
2843
|
}
|
|
2844
|
+
const downloads = await resolveBuildDownloads(cwd, options);
|
|
2845
|
+
for (const image of images) validateDownloadDockerfile(resolve(cwd, image.dockerfile), downloads);
|
|
2627
2846
|
const candidates = options.runtime && options.runtime !== "auto" ? [options.runtime] : ["podman", "docker"];
|
|
2628
2847
|
if (candidates.some((runtime2) => !["podman", "docker"].includes(runtime2)))
|
|
2629
2848
|
throw new Error(cliM("cli_build_runtime_missing"));
|
|
@@ -2638,6 +2857,7 @@ async function buildCommand(options) {
|
|
|
2638
2857
|
}
|
|
2639
2858
|
if (!runtime)
|
|
2640
2859
|
throw new Error(cliM("cli_build_runtime_missing"));
|
|
2860
|
+
await preflightDownloadProxy(runtime, downloads.proxy);
|
|
2641
2861
|
if (options.sqlitePrebuildMirror) {
|
|
2642
2862
|
const url = new URL(options.sqlitePrebuildMirror);
|
|
2643
2863
|
if (!["http:", "https:"].includes(url.protocol) || url.username || url.password || url.search || url.hash)
|
|
@@ -2667,8 +2887,8 @@ async function buildCommand(options) {
|
|
|
2667
2887
|
const context = resolve(cwd, image.context ?? ".");
|
|
2668
2888
|
const imageRef = `localhost/hai-${projectName}-${image.name}:${buildId.toLowerCase().replaceAll("+", "_")}`;
|
|
2669
2889
|
const args = ["build", "-f", resolve(cwd, image.dockerfile), "-t", imageRef];
|
|
2670
|
-
const testRun =
|
|
2671
|
-
const testLedger =
|
|
2890
|
+
const testRun = process5.env.HAI_TEST_IMAGE_RUN;
|
|
2891
|
+
const testLedger = process5.env.HAI_TEST_IMAGE_LEDGER;
|
|
2672
2892
|
if (testLedger && /^[a-f0-9-]{36}$/.test(testRun ?? "")) {
|
|
2673
2893
|
const label = `org.h-ai.test.image-run=${testRun}`;
|
|
2674
2894
|
args.push("--label", label);
|
|
@@ -2678,19 +2898,19 @@ async function buildCommand(options) {
|
|
|
2678
2898
|
`);
|
|
2679
2899
|
}
|
|
2680
2900
|
args.push("--build-arg", `HAI_BUILD_ID=${buildId}`, "--build-arg", `HAI_BUILD_COMMIT=${commit}`);
|
|
2901
|
+
const dockerfile = readFileSync(resolve(cwd, image.dockerfile), "utf8");
|
|
2902
|
+
for (const match of dockerfile.matchAll(/^ARG (HAI_(?:NODE|NGINX)_IMAGE)=(\S+)\s*$/gm))
|
|
2903
|
+
args.push("--build-arg", `${match[1]}=${resolveImageReference(match[2], downloads.imageSource)}`);
|
|
2904
|
+
args.push("--build-arg", `HAI_NPM_REGISTRY=${downloads.npmRegistry}`, ...buildProxyArguments(downloads.proxy, runtime, options.network));
|
|
2905
|
+
if (runtime === "docker" && process5.platform === "linux" && options.network !== "host")
|
|
2906
|
+
args.push("--add-host", "host.docker.internal:host-gateway");
|
|
2681
2907
|
if (options.network !== void 0)
|
|
2682
2908
|
args.push("--network", options.network);
|
|
2683
2909
|
const ignore = `${resolve(cwd, image.dockerfile)}.dockerignore`;
|
|
2684
2910
|
if (runtime === "podman" && existsSync(ignore))
|
|
2685
2911
|
args.push("--ignorefile", ignore);
|
|
2686
2912
|
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
|
-
}
|
|
2913
|
+
args.push("--format", "docker", "--jobs", "1", ...downloads.proxy.mode === "none" ? ["--http-proxy=false"] : []);
|
|
2694
2914
|
}
|
|
2695
2915
|
if (options.sqlitePrebuildMirror)
|
|
2696
2916
|
args.push("--build-arg", `SQLITE_PREBUILD_MIRROR=${options.sqlitePrebuildMirror}`);
|
|
@@ -2772,7 +2992,7 @@ function prepareDependencyInputs(cwd) {
|
|
|
2772
2992
|
async function deploySecretsCommand(directory, options) {
|
|
2773
2993
|
if (!options.import || !["docker", "podman"].includes(options.runtime ?? "docker"))
|
|
2774
2994
|
throw new Error(cliM("cli_deploy_secrets_options"));
|
|
2775
|
-
const cwd = resolve(options.cwd ??
|
|
2995
|
+
const cwd = resolve(options.cwd ?? process5.cwd());
|
|
2776
2996
|
const local = createRequire(resolve(cwd, "package.json"));
|
|
2777
2997
|
let module;
|
|
2778
2998
|
try {
|
|
@@ -2788,237 +3008,12 @@ ${JSON.stringify({ phase: context?.phase, state: context?.state })}`);
|
|
|
2788
3008
|
}
|
|
2789
3009
|
writeCliMessage(JSON.stringify(result.data, null, 2));
|
|
2790
3010
|
}
|
|
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
3011
|
async function ask(question) {
|
|
2958
3012
|
const answer = await prompts({ ...question, name: "value" });
|
|
2959
3013
|
if (answer.value === void 0)
|
|
2960
3014
|
throw new Error(cliM("cli_deploy_cancelled"));
|
|
2961
3015
|
return answer.value;
|
|
2962
3016
|
}
|
|
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
3017
|
async function configureDeployMiddleware(module, scan, environment, config, yes = false) {
|
|
3023
3018
|
const modes = {};
|
|
3024
3019
|
const services = {};
|
|
@@ -3030,7 +3025,7 @@ async function configureDeployMiddleware(module, scan, environment, config, yes
|
|
|
3030
3025
|
if (!current)
|
|
3031
3026
|
throw new Error(cliM("cli_deploy_cloud_unsupported", { params: { backend: requirement.backend } }));
|
|
3032
3027
|
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);
|
|
3028
|
+
const canKeep = module.canKeepMiddleware(requirement, current, environment);
|
|
3034
3029
|
const mode = yes ? canKeep ? "keep" : "default" : await ask({
|
|
3035
3030
|
type: "select",
|
|
3036
3031
|
name: "value",
|
|
@@ -3055,22 +3050,23 @@ async function configureDeployMiddleware(module, scan, environment, config, yes
|
|
|
3055
3050
|
throw new Error(cliM("cli_deploy_invalid_value"));
|
|
3056
3051
|
requirement.backend = backendName;
|
|
3057
3052
|
const updates = {};
|
|
3058
|
-
|
|
3053
|
+
let configuration;
|
|
3054
|
+
for (const option of mode === "default" && provider?.type === "docker-ssh" ? backend.containerOptions ?? [] : []) {
|
|
3059
3055
|
const container = config.container && typeof config.container === "object" ? config.container : {};
|
|
3060
|
-
const
|
|
3061
|
-
const
|
|
3062
|
-
if (!
|
|
3056
|
+
const currentValue = String(container[option.field] ?? option.defaultValue);
|
|
3057
|
+
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 })) }));
|
|
3058
|
+
if (!option.choices.some((item) => item.value === selected))
|
|
3063
3059
|
throw new Error(cliM("cli_deploy_invalid_value"));
|
|
3064
|
-
config.container = { ...container,
|
|
3065
|
-
updates.
|
|
3060
|
+
config.container = { ...container, [option.field]: selected };
|
|
3061
|
+
updates[option.variable] = selected;
|
|
3066
3062
|
const deploymentFile = projectConfigPath(scan.appDir ?? environment.envDir);
|
|
3067
3063
|
const project = readProjectConfig(deploymentFile);
|
|
3068
3064
|
project.deploy ??= {};
|
|
3069
3065
|
if (project.deploy.container != null && (typeof project.deploy.container !== "object" || Array.isArray(project.deploy.container)))
|
|
3070
3066
|
throw new Error(cliM("cli_deploy_config_node", { params: { path: deploymentFile, field: "deploy.container" } }));
|
|
3071
3067
|
project.deploy.container ??= {};
|
|
3072
|
-
if (!(
|
|
3073
|
-
project.deploy.container.
|
|
3068
|
+
if (!(option.field in project.deploy.container)) {
|
|
3069
|
+
project.deploy.container[option.field] = `\${${option.variable}:${option.defaultValue}}`;
|
|
3074
3070
|
writeFileSync(deploymentFile, `${JSON.stringify(project, null, 2)}
|
|
3075
3071
|
`);
|
|
3076
3072
|
}
|
|
@@ -3081,7 +3077,7 @@ async function configureDeployMiddleware(module, scan, environment, config, yes
|
|
|
3081
3077
|
const prior = existingServices[requirement.service];
|
|
3082
3078
|
const priorConfig = prior && typeof prior === "object" ? prior : {};
|
|
3083
3079
|
const cloud = { provisioner: backend.provisioner };
|
|
3084
|
-
for (const name of
|
|
3080
|
+
for (const name of backend.cloudFields ?? []) {
|
|
3085
3081
|
const key = `HAI_DEPLOY_SERVICES_${requirement.service.toUpperCase()}_${name.toUpperCase()}`;
|
|
3086
3082
|
const initial = String(priorConfig[name] ?? environment.values[key] ?? "");
|
|
3087
3083
|
const label = `${backend.label} \u2014 ${cliM(`cli_deploy_cloud_input_${name}`)}`;
|
|
@@ -3093,32 +3089,25 @@ async function configureDeployMiddleware(module, scan, environment, config, yes
|
|
|
3093
3089
|
}
|
|
3094
3090
|
services[requirement.service] = cloud;
|
|
3095
3091
|
} else {
|
|
3096
|
-
if (mode === "default" &&
|
|
3092
|
+
if (mode === "default" && backend.containerSupported === false)
|
|
3097
3093
|
throw new Error(cliM("cli_deploy_cloud_unsupported", { params: { backend: backend.label } }));
|
|
3098
|
-
const connection = backendName === current.backend ? { ...requirement.config } : requirement.
|
|
3094
|
+
const connection = backendName === current.backend ? { ...requirement.config } : requirement.config.name === void 0 ? {} : { name: requirement.config.name };
|
|
3099
3095
|
for (const field of backend.fields) {
|
|
3100
3096
|
const previous2 = backendName === current.backend ? requirement.config[field.name] : void 0;
|
|
3101
3097
|
const initial = previous2 === void 0 ? field.defaultValue ?? "" : typeof previous2 === "object" ? JSON.stringify(previous2) : String(previous2);
|
|
3102
3098
|
const variable = `${requirement.envPrefix}_${field.name.toUpperCase()}`;
|
|
3103
3099
|
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 {
|
|
3100
|
+
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;
|
|
3101
|
+
const parsed2 = module.parseMiddlewareField({ value, field, backend: backendName, managed: mode === "default" });
|
|
3102
|
+
if (!parsed2.success)
|
|
3103
|
+
throw new Error(parsed2.error.message);
|
|
3104
|
+
if (parsed2.data === void 0)
|
|
3110
3105
|
delete connection[field.name];
|
|
3111
|
-
|
|
3106
|
+
else connection[field.name] = parsed2.data;
|
|
3112
3107
|
}
|
|
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));
|
|
3108
|
+
configuration = connection;
|
|
3119
3109
|
}
|
|
3120
|
-
|
|
3121
|
-
const saved = module.saveDeploymentEnvironment(environment, updates);
|
|
3110
|
+
const saved = module.saveMiddlewareEnvironment(environment, { appDir: scan.appDir ?? ".", requirement, backend: backendName, configuration, updates });
|
|
3122
3111
|
if (!saved.success)
|
|
3123
3112
|
throw new Error(saved.error.message);
|
|
3124
3113
|
writeCliMessage(cliM("cli_deploy_saved", { params: { service: requirement.service } }));
|
|
@@ -3222,7 +3211,7 @@ async function configureDeployTarget(module, config, environment, nonInteractive
|
|
|
3222
3211
|
const validated = module.ProviderConfigSchema.safeParse(provider);
|
|
3223
3212
|
if (!validated.success)
|
|
3224
3213
|
throw new Error(cliM("cli_deploy_invalid_value"));
|
|
3225
|
-
const saved = module.saveDeploymentEnvironment(environment, { HAI_DEPLOY_PROVIDER:
|
|
3214
|
+
const saved = module.saveDeploymentEnvironment(environment, { HAI_DEPLOY_PROVIDER: validated.data }, { private: true });
|
|
3226
3215
|
if (!saved.success)
|
|
3227
3216
|
throw new Error(saved.error.message);
|
|
3228
3217
|
config.provider = validated.data;
|
|
@@ -3273,7 +3262,7 @@ async function configureDeployHttps(module, config, environment, nonInteractive,
|
|
|
3273
3262
|
const parsed2 = module.ProviderConfigSchema.safeParse({ ...provider, expose: { ...expose, ...https?.type === "letsencrypt" ? { hostPort: 80 } : {}, https } });
|
|
3274
3263
|
if (!parsed2.success)
|
|
3275
3264
|
throw new Error(cliM("cli_deploy_invalid_value"));
|
|
3276
|
-
const saved = module.saveDeploymentEnvironment(environment, { HAI_DEPLOY_PROVIDER:
|
|
3265
|
+
const saved = module.saveDeploymentEnvironment(environment, { HAI_DEPLOY_PROVIDER: parsed2.data }, { private: true });
|
|
3277
3266
|
if (!saved.success)
|
|
3278
3267
|
throw new Error(saved.error.message);
|
|
3279
3268
|
config.provider = parsed2.data;
|
|
@@ -3281,11 +3270,11 @@ async function configureDeployHttps(module, config, environment, nonInteractive,
|
|
|
3281
3270
|
}
|
|
3282
3271
|
async function deployCommand(options) {
|
|
3283
3272
|
const spinner = ora();
|
|
3284
|
-
const cwd = options.cwd ??
|
|
3273
|
+
const cwd = options.cwd ?? process5.cwd();
|
|
3285
3274
|
let appDir = resolve(cwd, options.appDir ?? ".");
|
|
3286
3275
|
let closeDeploy = null;
|
|
3287
3276
|
let restoreProjectLogger;
|
|
3288
|
-
const originalEnv = { ...
|
|
3277
|
+
const originalEnv = { ...process5.env };
|
|
3289
3278
|
const previousLogLevel = core.logger.getLevel();
|
|
3290
3279
|
core.logger.setLevel("fatal");
|
|
3291
3280
|
try {
|
|
@@ -3295,21 +3284,21 @@ async function deployCommand(options) {
|
|
|
3295
3284
|
throw new Error(cliM("cli_build_runtime_missing"));
|
|
3296
3285
|
if (options.artifactDir && options.build)
|
|
3297
3286
|
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.
|
|
3287
|
+
if (!options.build && (options.concurrency !== void 0 || options.network !== void 0 || options.sqlitePrebuildMirror !== void 0 || options.npmSource !== void 0 || options.npmRegistry !== void 0))
|
|
3299
3288
|
throw new Error(cliM("cli_deploy_build_options_required"));
|
|
3300
3289
|
let selectedServices = options.services?.split(",").map((name) => name.trim());
|
|
3301
3290
|
if (selectedServices && (!selectedServices.length || selectedServices.some((name) => !/^[a-z][a-z0-9-]*$/.test(name)) || new Set(selectedServices).size !== selectedServices.length))
|
|
3302
3291
|
throw new Error(cliM("cli_build_selection_invalid"));
|
|
3303
3292
|
let environmentName = options.env;
|
|
3304
3293
|
if (!environmentName) {
|
|
3305
|
-
if (!
|
|
3294
|
+
if (!process5.stdin.isTTY)
|
|
3306
3295
|
throw new Error(cliM("cli_deploy_environment_hint"));
|
|
3307
3296
|
const answer = await prompts({ type: "text", name: "environment", message: cliM("cli_deploy_environment"), initial: "prod" });
|
|
3308
3297
|
environmentName = answer.environment;
|
|
3309
3298
|
if (!environmentName)
|
|
3310
3299
|
throw new Error(cliM("cli_deploy_cancelled"));
|
|
3311
3300
|
}
|
|
3312
|
-
if (!options.plan && !options.yes && !
|
|
3301
|
+
if (!options.plan && !options.yes && !process5.stdin.isTTY)
|
|
3313
3302
|
throw new Error(cliM("cli_deploy_environment_hint"));
|
|
3314
3303
|
let deployModule;
|
|
3315
3304
|
try {
|
|
@@ -3328,7 +3317,7 @@ async function deployCommand(options) {
|
|
|
3328
3317
|
localModule = localRequire.resolve("@h-ai/deploy");
|
|
3329
3318
|
} catch {
|
|
3330
3319
|
}
|
|
3331
|
-
deployModule = localModule ? await import(pathToFileURL(localModule).href) : await import('./src-
|
|
3320
|
+
deployModule = localModule ? await import(pathToFileURL(localModule).href) : await import('./src-NXCCU6GO.js');
|
|
3332
3321
|
} catch {
|
|
3333
3322
|
writeCliError(chalk.red(cliM("cli_deploy_module_missing")));
|
|
3334
3323
|
writeCliMessage(chalk.cyan(" pnpm add -D @h-ai/deploy"));
|
|
@@ -3356,9 +3345,9 @@ async function deployCommand(options) {
|
|
|
3356
3345
|
if (!environment.success)
|
|
3357
3346
|
throw new Error(environment.error.message);
|
|
3358
3347
|
if (options.plan) {
|
|
3359
|
-
if (options.build || options.bundleOnly || options.output)
|
|
3348
|
+
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
3349
|
throw new Error(cliM("cli_deploy_plan_options"));
|
|
3361
|
-
const loaded = deployModule.loadDeploymentConfig("deploy", buildFile, { ...
|
|
3350
|
+
const loaded = deployModule.loadDeploymentConfig("deploy", buildFile, { ...process5.env, ...environment.data.values });
|
|
3362
3351
|
if (!loaded.success)
|
|
3363
3352
|
throw new Error(loaded.error.message);
|
|
3364
3353
|
const validated = deployModule.DeployConfigSchema.safeParse(loaded.data);
|
|
@@ -3370,7 +3359,7 @@ async function deployCommand(options) {
|
|
|
3370
3359
|
writeCliMessage(JSON.stringify(plan.data, null, 2));
|
|
3371
3360
|
return;
|
|
3372
3361
|
}
|
|
3373
|
-
Object.assign(
|
|
3362
|
+
Object.assign(process5.env, environment.data.values);
|
|
3374
3363
|
spinner.start(cliM("cli_deploy_load_credentials"));
|
|
3375
3364
|
const credResult = deploy.credentials.load();
|
|
3376
3365
|
if (!credResult.success) {
|
|
@@ -3384,7 +3373,7 @@ async function deployCommand(options) {
|
|
|
3384
3373
|
writeCliMessage(chalk.cyan(cliM("cli_deploy_config_hint")));
|
|
3385
3374
|
throw new Error(cliM("cli_deploy_config_missing", { params: { path: configPath } }));
|
|
3386
3375
|
}
|
|
3387
|
-
const loadedConfig = deployModule.loadDeploymentConfig("deploy", configPath,
|
|
3376
|
+
const loadedConfig = deployModule.loadDeploymentConfig("deploy", configPath, process5.env);
|
|
3388
3377
|
if (!loadedConfig.success)
|
|
3389
3378
|
throw new Error(loadedConfig.error.message);
|
|
3390
3379
|
const deployConfig = loadedConfig.data;
|
|
@@ -3429,13 +3418,16 @@ async function deployCommand(options) {
|
|
|
3429
3418
|
}
|
|
3430
3419
|
}
|
|
3431
3420
|
spinner.succeed(cliM("cli_deploy_scanned", { params: { name: scan.appName, sveltekit: String(scan.isSvelteKit), services: scan.requiredServices.join(", ") || cliM("cli_deploy_none") } }));
|
|
3421
|
+
const downloads = configObject(deployConfig.provider).type === "docker-ssh" ? await resolveBuildDownloads(buildRoot, options) : void 0;
|
|
3422
|
+
let builtImages = false;
|
|
3432
3423
|
if (options.build) {
|
|
3433
3424
|
if (!existsSync(buildFile))
|
|
3434
3425
|
throw new Error(cliM("cli_build_images_missing"));
|
|
3435
3426
|
const imageNames2 = selectedServices?.filter((name) => ["serv", "web"].includes(name));
|
|
3436
3427
|
if (!selectedServices || imageNames2?.length) {
|
|
3437
3428
|
writeCliMessage(cliM("cli_deploy_build_started"));
|
|
3438
|
-
|
|
3429
|
+
builtImages = true;
|
|
3430
|
+
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
3431
|
}
|
|
3440
3432
|
}
|
|
3441
3433
|
if (selectedServices)
|
|
@@ -3460,15 +3452,15 @@ async function deployCommand(options) {
|
|
|
3460
3452
|
if (options.bundleOnly)
|
|
3461
3453
|
await configureDeployTarget(deployModule, deployConfig, environment.data, options.yes, true);
|
|
3462
3454
|
await configureDeployHttps(deployModule, deployConfig, environment.data, options.yes, selectedServices !== void 0);
|
|
3463
|
-
for (const key of Object.keys(
|
|
3455
|
+
for (const key of Object.keys(process5.env)) {
|
|
3464
3456
|
if (originalEnv[key] === void 0)
|
|
3465
|
-
delete
|
|
3457
|
+
delete process5.env[key];
|
|
3466
3458
|
}
|
|
3467
|
-
Object.assign(
|
|
3459
|
+
Object.assign(process5.env, originalEnv);
|
|
3468
3460
|
const refreshed = deployModule.loadDeploymentEnvironment({ environment: environment.data.environment, envDir: environment.data.envDir });
|
|
3469
3461
|
if (!refreshed.success)
|
|
3470
3462
|
throw new Error(refreshed.error.message);
|
|
3471
|
-
Object.assign(
|
|
3463
|
+
Object.assign(process5.env, refreshed.data.values);
|
|
3472
3464
|
spinner.start(cliM("cli_deploy_initializing"));
|
|
3473
3465
|
const validatedConfig = deployModule.DeployConfigSchema.safeParse(deployConfig);
|
|
3474
3466
|
if (!validatedConfig.success)
|
|
@@ -3480,7 +3472,11 @@ async function deployCommand(options) {
|
|
|
3480
3472
|
closeDeploy = () => deploy.close();
|
|
3481
3473
|
spinner.succeed(cliM("cli_deploy_initialized"));
|
|
3482
3474
|
spinner.start(cliM("cli_deploy_deploying"));
|
|
3475
|
+
if (downloads && !builtImages && (!selectedServices || selectedServices.some((name) => !["serv", "web"].includes(name))))
|
|
3476
|
+
await preflightDownloadProxy(options.runtime ?? "auto", downloads.proxy);
|
|
3483
3477
|
const deployResult = await deploy.deployApp(appDir, {
|
|
3478
|
+
imageSource: downloads?.imageSource,
|
|
3479
|
+
proxy: downloads?.proxy,
|
|
3484
3480
|
selectedServices,
|
|
3485
3481
|
runtime: options.runtime,
|
|
3486
3482
|
onProgress: (stage) => writeCliMessage(cliM(`cli_deploy_stage_${stage}`)),
|
|
@@ -3542,14 +3538,14 @@ async function deployCommand(options) {
|
|
|
3542
3538
|
await closeDeploy();
|
|
3543
3539
|
} catch (error) {
|
|
3544
3540
|
writeCliError("Failed to close deploy module", error);
|
|
3545
|
-
|
|
3541
|
+
process5.exitCode = 1;
|
|
3546
3542
|
}
|
|
3547
3543
|
}
|
|
3548
|
-
for (const key of Object.keys(
|
|
3544
|
+
for (const key of Object.keys(process5.env)) {
|
|
3549
3545
|
if (originalEnv[key] === void 0)
|
|
3550
|
-
delete
|
|
3546
|
+
delete process5.env[key];
|
|
3551
3547
|
}
|
|
3552
|
-
Object.assign(
|
|
3548
|
+
Object.assign(process5.env, originalEnv);
|
|
3553
3549
|
core.logger.setLevel(previousLogLevel);
|
|
3554
3550
|
restoreProjectLogger?.();
|
|
3555
3551
|
}
|
|
@@ -4383,7 +4379,7 @@ async function startFeedbackViewer(bundle, options = {}) {
|
|
|
4383
4379
|
async function feedbackCommand(action, bundlePath, options = {}) {
|
|
4384
4380
|
if (!["inspect", "summary", "evidence", "view"].includes(action))
|
|
4385
4381
|
throw new Error(cliM("cli_feedback_invalidAction"));
|
|
4386
|
-
const filePath = path2.resolve(options.cwd ??
|
|
4382
|
+
const filePath = path2.resolve(options.cwd ?? process5.cwd(), bundlePath);
|
|
4387
4383
|
const metadata = await stat(filePath);
|
|
4388
4384
|
if (!metadata.isFile() || metadata.size > 64 * 1024 * 1024)
|
|
4389
4385
|
throw new Error(cliM("cli_feedback_invalidBundle"));
|
|
@@ -4417,12 +4413,12 @@ async function feedbackCommand(action, bundlePath, options = {}) {
|
|
|
4417
4413
|
writeCliMessage(cliM("cli_feedback_viewerStarted", { params: { url: viewer.url } }));
|
|
4418
4414
|
await new Promise((resolve7, reject) => {
|
|
4419
4415
|
const stop = () => {
|
|
4420
|
-
|
|
4421
|
-
|
|
4416
|
+
process5.off("SIGINT", stop);
|
|
4417
|
+
process5.off("SIGTERM", stop);
|
|
4422
4418
|
viewer.close().then(resolve7, reject);
|
|
4423
4419
|
};
|
|
4424
|
-
|
|
4425
|
-
|
|
4420
|
+
process5.once("SIGINT", stop);
|
|
4421
|
+
process5.once("SIGTERM", stop);
|
|
4426
4422
|
});
|
|
4427
4423
|
}
|
|
4428
4424
|
function appendAt(source, marker, entry) {
|
|
@@ -5042,7 +5038,7 @@ async function initProject(options) {
|
|
|
5042
5038
|
const { project, existing, missing } = result;
|
|
5043
5039
|
spinner.succeed(cliM("cli_initDetected", { params: { name: chalk.cyan(project.name) } }));
|
|
5044
5040
|
if (project.isHaiProject) {
|
|
5045
|
-
const { generateProjectAiSupport, resolveSkillNamesForPackages } = await import('./cli-skill-templates-
|
|
5041
|
+
const { generateProjectAiSupport, resolveSkillNamesForPackages } = await import('./cli-skill-templates-S2YH642Z.js');
|
|
5046
5042
|
const generatedFiles = await generateProjectAiSupport(cwd, resolveSkillNamesForPackages(project.haiPackages), {
|
|
5047
5043
|
overwriteSkills: false,
|
|
5048
5044
|
overwriteBridgeFiles: false
|
|
@@ -5120,7 +5116,7 @@ async function initProject(options) {
|
|
|
5120
5116
|
throw error;
|
|
5121
5117
|
}
|
|
5122
5118
|
}
|
|
5123
|
-
function
|
|
5119
|
+
function object2(value) {
|
|
5124
5120
|
return value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
5125
5121
|
}
|
|
5126
5122
|
function declaresValueExport(source, name) {
|
|
@@ -5153,9 +5149,9 @@ async function inspectFrameworkUpgrade(directory, version) {
|
|
|
5153
5149
|
throw new Error(cliM("cli_upgrade_exact_version"));
|
|
5154
5150
|
const root = realpathSync(resolve(directory));
|
|
5155
5151
|
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(
|
|
5152
|
+
const workspace = existsSync(workspaceFile) ? object2(parse(readFileSync(workspaceFile, "utf8"))) : {};
|
|
5153
|
+
const rootManifest = object2(JSON.parse(readFileSync(join(root, "package.json"), "utf8")));
|
|
5154
|
+
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
5155
|
const directories = /* @__PURE__ */ new Set([root]);
|
|
5160
5156
|
const safePatterns = patterns.filter((pattern) => typeof pattern === "string" && !isAbsolute(pattern.replace(/^!/, "")) && !pattern.split(/[\\/]/).includes(".."));
|
|
5161
5157
|
const exclude = ["**/node_modules/**", ...safePatterns.filter((pattern) => pattern.startsWith("!")).map((pattern) => `${pattern.slice(1)}/package.json`)];
|
|
@@ -5163,29 +5159,29 @@ async function inspectFrameworkUpgrade(directory, version) {
|
|
|
5163
5159
|
for await (const manifest of glob(`${pattern}/package.json`, { cwd: root, exclude })) {
|
|
5164
5160
|
const location = realpathSync(dirname(join(root, manifest)));
|
|
5165
5161
|
const fromRoot = relative(root, location);
|
|
5166
|
-
if (!isAbsolute(fromRoot) && fromRoot !== ".." && !fromRoot.startsWith(`..${
|
|
5162
|
+
if (!isAbsolute(fromRoot) && fromRoot !== ".." && !fromRoot.startsWith(`..${process5.platform === "win32" ? "\\" : "/"}`))
|
|
5167
5163
|
directories.add(location);
|
|
5168
5164
|
}
|
|
5169
5165
|
}
|
|
5170
5166
|
const packages = /* @__PURE__ */ new Set(["@h-ai/cli", "@h-ai/deploy"]);
|
|
5171
5167
|
const drift = [];
|
|
5172
|
-
const catalog =
|
|
5168
|
+
const catalog = object2(workspace.catalog);
|
|
5173
5169
|
const lockPath = join(root, "pnpm-lock.yaml");
|
|
5174
5170
|
const lock = existsSync(lockPath) ? parseAllDocuments(readFileSync(lockPath, "utf8")).reduce((all, document) => {
|
|
5175
5171
|
if (document.errors.length)
|
|
5176
5172
|
throw new Error(cliM("cli_upgrade_lock_invalid"));
|
|
5177
|
-
const part =
|
|
5178
|
-
return { ...all, ...part, importers: { ...
|
|
5173
|
+
const part = object2(document.toJS());
|
|
5174
|
+
return { ...all, ...part, importers: { ...object2(all.importers), ...object2(part.importers) } };
|
|
5179
5175
|
}, {}) : {};
|
|
5180
5176
|
for (const location of directories) {
|
|
5181
|
-
const manifest =
|
|
5182
|
-
const dependencies = { ...
|
|
5183
|
-
const importer =
|
|
5177
|
+
const manifest = object2(JSON.parse(readFileSync(join(location, "package.json"), "utf8")));
|
|
5178
|
+
const dependencies = { ...object2(manifest.dependencies), ...object2(manifest.devDependencies), ...object2(manifest.optionalDependencies) };
|
|
5179
|
+
const importer = object2(object2(lock.importers)[relative(root, location).replaceAll("\\", "/") || "."]);
|
|
5184
5180
|
for (const [name, specifier] of Object.entries(dependencies)) {
|
|
5185
5181
|
if (!/^@h-ai\/[\w-]+$/.test(name) || typeof specifier !== "string")
|
|
5186
5182
|
continue;
|
|
5187
5183
|
packages.add(name);
|
|
5188
|
-
const declared = specifier.startsWith("catalog:") ? String(
|
|
5184
|
+
const declared = specifier.startsWith("catalog:") ? String(object2(specifier === "catalog:" ? catalog : object2(workspace.catalogs)[specifier.slice(8)])[name] ?? "") : specifier;
|
|
5189
5185
|
const issues = [];
|
|
5190
5186
|
if (declared !== version && !declared.startsWith("workspace:"))
|
|
5191
5187
|
issues.push("declared-version-drift");
|
|
@@ -5193,7 +5189,7 @@ async function inspectFrameworkUpgrade(directory, version) {
|
|
|
5193
5189
|
try {
|
|
5194
5190
|
const path10 = findPackageJSON(name, pathToFileURL(join(location, "package.json")));
|
|
5195
5191
|
if (path10) {
|
|
5196
|
-
const candidate =
|
|
5192
|
+
const candidate = object2(JSON.parse(readFileSync(path10, "utf8")));
|
|
5197
5193
|
if (candidate.name === name && typeof candidate.version === "string")
|
|
5198
5194
|
installed = candidate.version;
|
|
5199
5195
|
}
|
|
@@ -5201,13 +5197,13 @@ async function inspectFrameworkUpgrade(directory, version) {
|
|
|
5201
5197
|
}
|
|
5202
5198
|
if (installed !== version)
|
|
5203
5199
|
issues.push(installed ? "installed-version-drift" : "not-installed");
|
|
5204
|
-
const locked =
|
|
5200
|
+
const locked = object2(object2(importer.dependencies)[name] ?? object2(importer.devDependencies)[name] ?? object2(importer.optionalDependencies)[name]);
|
|
5205
5201
|
if (typeof locked.version !== "string" || !locked.version.startsWith("link:") && locked.version.split("(")[0] !== version)
|
|
5206
5202
|
issues.push("lock-version-drift");
|
|
5207
5203
|
drift.push({ package: name, source: relative(root, join(location, "package.json")).replaceAll("\\", "/"), declared, installed, issues });
|
|
5208
5204
|
}
|
|
5209
5205
|
}
|
|
5210
|
-
const registry = new URL(
|
|
5206
|
+
const registry = new URL(process5.env.npm_config_registry ?? "https://registry.npmjs.org/");
|
|
5211
5207
|
if (registry.username || registry.password || registry.protocol !== "https:")
|
|
5212
5208
|
throw new Error(cliM("cli_upgrade_registry"));
|
|
5213
5209
|
const releases = [];
|
|
@@ -5222,11 +5218,11 @@ async function inspectFrameworkUpgrade(directory, version) {
|
|
|
5222
5218
|
const response = await fetch(new URL(`${encodeURIComponent(name)}/${encodeURIComponent(version)}`, registry), { signal: AbortSignal.timeout(2e4) });
|
|
5223
5219
|
if (!response.ok)
|
|
5224
5220
|
throw new Error("Release missing");
|
|
5225
|
-
const metadata =
|
|
5226
|
-
const dist =
|
|
5221
|
+
const metadata = object2(await response.json());
|
|
5222
|
+
const dist = object2(metadata.dist);
|
|
5227
5223
|
if (metadata.version !== version || typeof dist.tarball !== "string" || typeof dist.integrity !== "string")
|
|
5228
5224
|
throw new Error("Invalid metadata");
|
|
5229
|
-
for (const dependency of Object.keys(
|
|
5225
|
+
for (const dependency of Object.keys(object2(metadata.dependencies))) {
|
|
5230
5226
|
if (/^@h-ai\/[\w-]+$/.test(dependency) && !packages.has(dependency)) {
|
|
5231
5227
|
packages.add(dependency);
|
|
5232
5228
|
pending.push(dependency);
|
|
@@ -5250,7 +5246,7 @@ async function inspectFrameworkUpgrade(directory, version) {
|
|
|
5250
5246
|
throw new Error("Integrity mismatch");
|
|
5251
5247
|
const files = tarFiles(bytes);
|
|
5252
5248
|
const manifest = files.get("package/package.json");
|
|
5253
|
-
if (!manifest ||
|
|
5249
|
+
if (!manifest || object2(JSON.parse(new TextDecoder().decode(manifest))).version !== version || !files.has("package/dist/index.js"))
|
|
5254
5250
|
throw new Error("Incomplete artifact");
|
|
5255
5251
|
const migration = { "@h-ai/iam": "migrateIam", "@h-ai/reach": "migrateReach", "@h-ai/scheduler": "migrateScheduler", "@h-ai/audit": "migrateAudit" }[name];
|
|
5256
5252
|
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 +5273,13 @@ async function inspectFrameworkUpgrade(directory, version) {
|
|
|
5277
5273
|
dirtyFiles = execFileSync("git", ["status", "--porcelain", "--", "."], { cwd: root, encoding: "utf8", windowsHide: true, stdio: "pipe" }).trim().split("\n").filter(Boolean);
|
|
5278
5274
|
} catch {
|
|
5279
5275
|
}
|
|
5280
|
-
return { version, releaseComplete: releases.every((item) => item.available), modified: false, releases, drift, skills, dirtyFiles, customizations: { overrides: [.../* @__PURE__ */ new Set([...Object.keys(
|
|
5276
|
+
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
5277
|
}
|
|
5282
5278
|
async function upgradeCommand(version, options = {}) {
|
|
5283
|
-
const report = await inspectFrameworkUpgrade(options.cwd ??
|
|
5279
|
+
const report = await inspectFrameworkUpgrade(options.cwd ?? process5.cwd(), version);
|
|
5284
5280
|
writeCliMessage(JSON.stringify(report, null, 2));
|
|
5285
5281
|
if (!report.releaseComplete)
|
|
5286
|
-
|
|
5282
|
+
process5.exitCode = 1;
|
|
5287
5283
|
}
|
|
5288
5284
|
|
|
5289
5285
|
// src/cli-main.ts
|
|
@@ -5308,7 +5304,7 @@ cli.command("create [name]", cliM("cli_help_create")).option("--type <type>", cl
|
|
|
5308
5304
|
cwd: options.cwd
|
|
5309
5305
|
});
|
|
5310
5306
|
} catch {
|
|
5311
|
-
|
|
5307
|
+
process5.exitCode = 1;
|
|
5312
5308
|
}
|
|
5313
5309
|
});
|
|
5314
5310
|
cli.command("add [module]", cliM("cli_help_add")).option("--no-install", cliM("cli_help_noInstall")).action(async (module, options) => {
|
|
@@ -5320,7 +5316,7 @@ cli.command("add [module]", cliM("cli_help_add")).option("--no-install", cliM("c
|
|
|
5320
5316
|
cwd: options.cwd
|
|
5321
5317
|
});
|
|
5322
5318
|
} catch {
|
|
5323
|
-
|
|
5319
|
+
process5.exit(1);
|
|
5324
5320
|
}
|
|
5325
5321
|
});
|
|
5326
5322
|
cli.command("init", cliM("cli_help_init")).option("-f, --force", cliM("cli_help_forceConfig")).action(async (options) => {
|
|
@@ -5331,7 +5327,7 @@ cli.command("init", cliM("cli_help_init")).option("-f, --force", cliM("cli_help_
|
|
|
5331
5327
|
cwd: options.cwd
|
|
5332
5328
|
});
|
|
5333
5329
|
} catch {
|
|
5334
|
-
|
|
5330
|
+
process5.exit(1);
|
|
5335
5331
|
}
|
|
5336
5332
|
});
|
|
5337
5333
|
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 +5342,15 @@ cli.command("generate [type] [name]", cliM("cli_help_generate")).option("-w, --w
|
|
|
5346
5342
|
cwd: options.cwd
|
|
5347
5343
|
});
|
|
5348
5344
|
} catch {
|
|
5349
|
-
|
|
5345
|
+
process5.exit(1);
|
|
5350
5346
|
}
|
|
5351
5347
|
});
|
|
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) => {
|
|
5348
|
+
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
5349
|
try {
|
|
5354
5350
|
await buildCommand(options);
|
|
5355
5351
|
} catch (error) {
|
|
5356
5352
|
writeCliMessage(error instanceof Error ? error.message : String(error));
|
|
5357
|
-
|
|
5353
|
+
process5.exitCode = 1;
|
|
5358
5354
|
}
|
|
5359
5355
|
});
|
|
5360
5356
|
cli.command("upgrade <version>", cliM("cli_help_upgrade")).action(async (version, options) => {
|
|
@@ -5362,10 +5358,10 @@ cli.command("upgrade <version>", cliM("cli_help_upgrade")).action(async (version
|
|
|
5362
5358
|
await upgradeCommand(version, options);
|
|
5363
5359
|
} catch (error) {
|
|
5364
5360
|
writeCliMessage(error instanceof Error ? error.message : String(error));
|
|
5365
|
-
|
|
5361
|
+
process5.exitCode = 1;
|
|
5366
5362
|
}
|
|
5367
5363
|
});
|
|
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) => {
|
|
5364
|
+
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
5365
|
try {
|
|
5370
5366
|
await deployCommand({
|
|
5371
5367
|
appDir,
|
|
@@ -5382,6 +5378,13 @@ cli.command("deploy [appDir]", cliM("cli_help_deploy")).option("--plan", cliM("c
|
|
|
5382
5378
|
network: options.network,
|
|
5383
5379
|
sqlitePrebuildMirror: options.sqlitePrebuildMirror,
|
|
5384
5380
|
httpProxy: options.httpProxy,
|
|
5381
|
+
imageSource: options.imageSource,
|
|
5382
|
+
imageMirrors: options.imageMirrors,
|
|
5383
|
+
npmSource: options.npmSource,
|
|
5384
|
+
npmRegistry: options.npmRegistry,
|
|
5385
|
+
proxyMode: options.proxyMode,
|
|
5386
|
+
proxyUrl: options.proxyUrl,
|
|
5387
|
+
proxyBypass: options.proxyBypass,
|
|
5385
5388
|
runtime: options.runtime,
|
|
5386
5389
|
bundleOnly: options.bundleOnly,
|
|
5387
5390
|
output: options.output,
|
|
@@ -5389,7 +5392,7 @@ cli.command("deploy [appDir]", cliM("cli_help_deploy")).option("--plan", cliM("c
|
|
|
5389
5392
|
cwd: options.cwd
|
|
5390
5393
|
});
|
|
5391
5394
|
} catch {
|
|
5392
|
-
|
|
5395
|
+
process5.exitCode = 1;
|
|
5393
5396
|
}
|
|
5394
5397
|
});
|
|
5395
5398
|
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 +5400,7 @@ cli.command("deploy-secrets <directory>", cliM("cli_help_deploySecrets")).option
|
|
|
5397
5400
|
await deploySecretsCommand(directory, options);
|
|
5398
5401
|
} catch (error) {
|
|
5399
5402
|
writeCliMessage(error instanceof Error ? error.message : String(error));
|
|
5400
|
-
|
|
5403
|
+
process5.exitCode = 1;
|
|
5401
5404
|
}
|
|
5402
5405
|
});
|
|
5403
5406
|
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 +5419,7 @@ cli.command("feedback <action> <bundle>", cliM("cli_help_feedback")).option("--p
|
|
|
5416
5419
|
});
|
|
5417
5420
|
} catch (error) {
|
|
5418
5421
|
writeCliMessage(error instanceof Error ? error.message : String(error));
|
|
5419
|
-
|
|
5422
|
+
process5.exitCode = 1;
|
|
5420
5423
|
}
|
|
5421
5424
|
});
|
|
5422
5425
|
cli.command("g:page <name>", cliM("cli_help_generatePage")).option("-w, --workspace <name>", cliM("cli_help_workspace")).action(async (name, options) => {
|