@h-ai/cli 1.0.0-beta.16 → 1.0.0-beta.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ export { generateConfigFile, generateEnvExample, generateProductionEnvironment } from './chunk-7NVRYYHN.js';
3
+ import './chunk-ZSDEVXZ7.js';
4
+ //# sourceMappingURL=cli-config-templates-QG5HOYR5.js.map
5
+ //# sourceMappingURL=cli-config-templates-QG5HOYR5.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"cli-config-templates-MKVYSK3E.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"cli-config-templates-QG5HOYR5.js"}
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- export { generateModuleSkillFile, generateProjectAiSupport, generateSkillFiles, resolveCompatibleSkillNames, resolveSkillNamesForPackages } from './chunk-EWTIVFHN.js';
2
+ export { generateModuleSkillFile, generateProjectAiSupport, generateSkillFiles, resolveCompatibleSkillNames, resolveSkillNamesForPackages } from './chunk-6YZBC5MO.js';
3
3
  import './chunk-ZSDEVXZ7.js';
4
- //# sourceMappingURL=cli-skill-templates-M64VPXZ4.js.map
5
- //# sourceMappingURL=cli-skill-templates-M64VPXZ4.js.map
4
+ //# sourceMappingURL=cli-skill-templates-W4I6ZKYW.js.map
5
+ //# sourceMappingURL=cli-skill-templates-W4I6ZKYW.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"cli-skill-templates-M64VPXZ4.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"cli-skill-templates-W4I6ZKYW.js"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { generateConfigFile, runtimeEnvironmentVariables, renderEnvironment, generateProductionEnvironment, moduleEnvironmentVariables, documentConfig, parameterizeConfig } from './chunk-S2ZP7BHG.js';
3
- import { cliM } from './chunk-EWTIVFHN.js';
2
+ import { generateConfigFile, runtimeEnvironmentVariables, renderEnvironment, generateProductionEnvironment, moduleEnvironmentVariables, documentConfig, parameterizeConfig } from './chunk-7NVRYYHN.js';
3
+ import { cliM } from './chunk-6YZBC5MO.js';
4
4
  import { __commonJS, __export, __toESM } from './chunk-ZSDEVXZ7.js';
5
5
  import process14 from 'process';
6
6
  import { cac } from 'cac';
@@ -4133,7 +4133,7 @@ async function createProject(options) {
4133
4133
  });
4134
4134
  await generateFromTemplates(projectPath, context);
4135
4135
  {
4136
- const { generateConfigFile: generateConfigFile2, generateEnvExample, generateProductionEnvironment: generateProductionEnvironment2 } = await import('./cli-config-templates-MKVYSK3E.js');
4136
+ const { generateConfigFile: generateConfigFile2, generateEnvExample, generateProductionEnvironment: generateProductionEnvironment2 } = await import('./cli-config-templates-QG5HOYR5.js');
4137
4137
  const configs = resolvedOptions.moduleConfigs;
4138
4138
  const isApiWorkspace = resolvedOptions.appType === "api";
4139
4139
  const isFullstack = resolvedOptions.appType === "fullstack";
@@ -4218,7 +4218,7 @@ HAI_CRYPTO_TRANSPORT_SERVERKEYRING='${JSON.stringify(ring)}'
4218
4218
  }
4219
4219
  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 });
4220
4220
  }
4221
- const { generateSkillFiles } = await import('./cli-skill-templates-M64VPXZ4.js');
4221
+ const { generateSkillFiles } = await import('./cli-skill-templates-W4I6ZKYW.js');
4222
4222
  await generateSkillFiles(
4223
4223
  projectPath,
4224
4224
  resolvedOptions.features,
@@ -5199,7 +5199,7 @@ async function addModule(options) {
5199
5199
  }
5200
5200
  const selected = baseDefinition.configKey === "db" ? "db" : moduleName;
5201
5201
  const moduleDef = { ...baseDefinition, deps: resolveFeatureDependencies([selected]).filter((feature) => feature !== selected) };
5202
- const { generateProjectAiSupport, resolveSkillNamesForPackages } = await import('./cli-skill-templates-M64VPXZ4.js');
5202
+ const { generateProjectAiSupport, resolveSkillNamesForPackages } = await import('./cli-skill-templates-W4I6ZKYW.js');
5203
5203
  const allPackages = new Set(moduleDef.packages);
5204
5204
  for (const dep of moduleDef.deps) {
5205
5205
  for (const name of MODULE_MAP[dep]?.packages ?? [])
@@ -25004,6 +25004,13 @@ external_exports.object({
25004
25004
  appVersion: external_exports.string().max(80).regex(/^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-[0-9a-z-]+(?:\.[0-9a-z-]+)*)?(?:\+[0-9a-z-]+(?:\.[0-9a-z-]+)*)?$/i),
25005
25005
  /** 本次构建标识;同一应用版本允许重复构建。 */
25006
25006
  buildId: external_exports.string().max(128).regex(/^[a-z0-9][\w.+-]*$/i),
25007
+ /** 构建启动时观察到的 Git 来源;历史清单可以省略。 */
25008
+ source: external_exports.object({
25009
+ /** 工程 package.json 所在仓库的提交 SHA;无法确定时为 unknown。 */
25010
+ commit: external_exports.string().regex(/^(?:[a-f0-9]{40}|[a-f0-9]{64}|unknown)$/),
25011
+ /** 工程目录有未提交改动时为 true;无法检查时为 null。 */
25012
+ dirty: external_exports.boolean().nullable()
25013
+ }).optional(),
25007
25014
  /** 只包含所选镜像的构建不能用于首次安装。 */
25008
25015
  partial: external_exports.boolean().default(false),
25009
25016
  /** 是否包含浏览器端;仅构建 serv 时也保留完整工程的 Web 拓扑。 */
@@ -25024,6 +25031,8 @@ external_exports.object({
25024
25031
  imageRef: external_exports.string().regex(/^[a-z0-9][a-z0-9./:_-]*:[a-z0-9_][a-z0-9_.-]*$/).refine((value) => !value.endsWith(":latest")),
25025
25032
  /** tar 内容的 SHA-256,用于部署前校验。 */
25026
25033
  sha256: external_exports.string().regex(/^[a-f0-9]{64}$/),
25034
+ /** 引擎实际构建的镜像 OS/架构;历史清单可以省略。 */
25035
+ platform: external_exports.string().regex(/^[a-z0-9][a-z0-9_.-]*\/[a-z0-9][a-z0-9_.-]*$/).optional(),
25027
25036
  /** 容器内部监听端口;服务器公开端口由部署选择。 */
25028
25037
  containerPort: external_exports.number().int().min(1).max(65535).optional()
25029
25038
  })).min(1).max(2).refine((images) => new Set(images.map((image) => image.name)).size === images.length)
@@ -25143,12 +25152,15 @@ var en_US_default = {
25143
25152
  deploy_requestAccessInvalid: "Invalid request access policy ({field}). Check fields, IP addresses, timezones and time windows. For a file reference, use readable YAML no larger than 1 MiB. Fix the configuration and create a new bundle.",
25144
25153
  deploy_httpsPortsInvalid: "HTTP and HTTPS ports must differ; Let\u2019s Encrypt HTTP-01 requires host port 80.",
25145
25154
  deploy_httpsCertificateInvalid: "Invalid HTTPS certificate. Check readable PEM files, matching unencrypted private key, validity dates and domain, then repackage.",
25146
- deploy_bundleRuntime: "Runtime configuration and activation:\nSingle application file: {directory}/config/.env.runtime\nThis snapshot: {directory}/releases/{deploymentId}/config/.env.runtime\nThe directory is mounted read-only at /run/hai/config. Edit fields and restart the Node backend; atomic file replacement is visible. Fields override parent JSON in the same source, and managed connections share this file. Back up, edit, docker restart <container> (or Podman), then verify health and affected flows.\nWeb/middleware-only updates retain the file; partial backend updates retain managed connections, while full updates use new settings and existing server credentials. Recovery restores configuration before services.\nNative middleware/static Web environment, ports, mounts, Node startup options, Nginx routes/limits and HTTPS layout require deployment. Website base changes also require rebuilding. Copy permanent settings to the source environment.",
25155
+ deploy_bundleRuntime: "Configuration files and activation\nconfig/.env.runtime in the unpacked bundle is this release's input. It contains application configuration and may include bundled middleware candidates. Change the project environment and rebuild the bundle. apply.sh verifies the unpacked content.\n{directory}/config/.env.runtime is the active configuration. Serv and SvelteKit SSR read it from the read-only /run/hai/config mount on each start.\nThe active file uses literal dotenv syntax and is limited to 1 MiB. Missing, unreadable, oversized, or duplicate assignments fail before startup.\n{directory}/releases/{deploymentId}/config/.env.runtime records this release. Updates that only select Web or middleware copy the configuration active at the time. Inspect the root file for the active value and the matching release for a historical value.\nA full deployment uses the new bundle configuration and reuses stored managed credentials. A partial update of the primary application takes external connections and application settings from the new bundle and keeps existing managed connections. A partial update that excludes the primary application keeps the active configuration. Switching between bundled and external middleware requires a full deployment.\nFor a temporary Node backend fix, back up and edit the active file, run docker restart <container> or podman restart <container>, and verify health and the affected feature. Put lasting changes in the project environment so the next backend release carries them. An explicit HAI_* value in the container process takes precedence.\nRedeploy changes to static Web or native middleware environments, ports, mounts, Node options, Nginx routes or limits, and HTTPS assembly. A website base path change also requires a rebuild.\nRecovery restores the active application file before restarting previous services. The database maintenance procedure handles password and data changes already made inside the database.",
25156
+ deploy_refreshCookieSecureInvalid: "HAI_SERV_REFRESH_COOKIE_SECURE must be true, false, or empty. Check the selected environment and packaging process for this variable.",
25157
+ deploy_postgresPasswordConflict: "External PostgreSQL has different passwords in HAI_DB_URL (or HAI_DB.url) and HAI_DB_PASSWORD (or HAI_DB.password). Use a complete URL or separate connection fields.",
25158
+ deploy_bundleVariables: "Environment variables and troubleshooting (names only)\nTarget environment: {environment}. Packaging priority, highest first: packaging process, .env.{environment}.local, .env.local, .env.{environment}, .env, and application YAML defaults. --env-dir selects the source directory. A field overrides its parent JSON in the same source. Higher-priority parent JSON replaces older structured fields.\nNames in this bundle's config/.env.runtime (--plan lists source input names): {keys}\nHAI_SERV_REFRESH_COOKIE_SECURE is a standalone process flag. Only the same name overrides it. true enables Secure, false is for controlled intranet or VPN HTTP access, and empty or absent uses the Serv environment default (enabled in production). Set HAI_SERV_CORS_ORIGIN to the actual HTTP origin. Verify login and refresh after deployment.\nExample for controlled HTTP: set HAI_SERV_REFRESH_COOKIE_SECURE=false in .env.{environment}.local and configure the actual CORS origin. With a successful full deployment and a serv image artifact, run pnpm run deploy --env {environment} --bundle-only --yes --services serv from the project. Unpack on the server and run sh ./apply.sh.\nExternal PostgreSQL uses HAI_DB_URL (a complete connection string with required authentication) or HAI_DB_HOST, HAI_DB_PORT, HAI_DB_USER, HAI_DB_DATABASE, and HAI_DB_PASSWORD. A URL takes precedence. Update the effective form when changing credentials. After updating the database account and the source environment, deploy serv or a full bundle.\nHAI_CACHE_*, HAI_STORAGE_*, HAI_VECDB_*, and HAI_IAM_LDAP_* configure application connections. S3 uses separate endpoint and access credentials. External or cloud-provisioned services normally have no native container variables in this bundle.\nFor bundled PostgreSQL, DB_PASSWORD in managed-secrets.env supplies HAI_DB_URL for the application and POSTGRES_PASSWORD for the image. POSTGRES_PASSWORD initializes an empty data directory. Other bundled images may use MYSQL_*, RUSTFS_*, MINIO_*, or LDAP_*. Rotate existing-volume credentials in both the actual account and managed state. A container restart or recreation alone cannot rotate a database password.\nNODE_ENV selects the application environment. The delivery topology determines listen settings in HOST, PORT, and HAI_SERV_SERVER_*. NODE_OPTIONS and HAI_DEPLOY_PRIVATE_PROXY come from container assembly. HAI_DEPLOY_PROVIDER_SSH_PASSWORD is used by the uploader for SSH.\nProtect the archive, runtime configuration, credentials, private keys, and failure logs. When sharing with operators or AI, use variable names, sources, redacted errors, and the deployment ID.",
25147
25159
  deploy_bundleHttpOnly: "HTTPS: disabled. This bundle exposes HTTP port {port}, contains no certificate attachment and will not request a certificate on the server.",
25148
25160
  deploy_bundleHttps: "HTTPS: enabled, https://{domain}:{port}; mode {mode}.\nServer certificate: {certificates}/fullchain.pem; private key: {certificates}/privkey.pem. Mounted read-only at /etc/nginx/tls/.\nEdit expose.https in HAI_DEPLOY_PROVIDER in the packaging environment .env.{environment}.local, or the unshadowed hai.json.deploy.provider.expose.https. Enable/disable, mode, domain or port changes require a new full bundle; editing .env.runtime and restarting does not issue a certificate for a new domain.",
25149
25161
  deploy_bundleAcme: "Persistent Certbot state: {state}; current certificate entry: {state}/live/{domain}. Packaging does not contact the CA; issuance runs during server deployment, followed by automatic renewal. Public port 80 and root /.well-known/acme-challenge/ must remain reachable independently of the business context path.",
25150
25162
  deploy_bundleAccounts: "Initial account variables (names and sources only; passwords omitted):\n{sources}\nApplications with matching bootstrap logic use HAI_CONFIG_ADMIN_PASSWORD to create the config_admin configuration administrator. HAI_ADMIN_DEFAULT_PASSWORD, HAI_AUDIT_ADMIN_PASSWORD and HAI_BUSINESS_OPERATOR_PASSWORD belong to the other template roles.\nFullstack creation generates independent initial passwords per environment. Packaging reads the selected environment and process overrides; server deployment does not generate new application account passwords. Startup creates missing configured accounts; changing variables does not reset existing passwords or restore old roles. Custom applications without this bootstrap follow their own implementation.",
25151
- deploy_bundleDirectories: "Server directory guide (root {directory}):\nincoming/: uploaded archive and extraction; remove this upload after success, retain evidence after failure or unknown execution.\nconfig/.env.runtime: single editable application file; releases/{deploymentId}/config/.env.runtime is this snapshot.\nreleases/{deploymentId}/manifest.json: artifacts and nonsecret metadata for layout, dependencies, probes, image lists, managed bindings and backend declarations. No secrets.\nEach release has a complete .hai/compose.json snapshot; partial updates replace selected service definitions and retain the others. .hai/ also holds native environment, the loader, Nginx/TLS, policy, checksums and recovery evidence. Helpers are embedded in apply.sh.\nimages/ is imported without copying archives into releases; images live in the engine and business data in volumes. Back up root managed-secrets.env and persistent-backends with data volumes.\ncurrent updates only after health passes. Inspect result-{deploymentId}.json and steps-{deploymentId}.jsonl. Before removing older releases, check active mounts, the complete .hai/compose.json and recovery needs.",
25163
+ deploy_bundleDirectories: "File index (server paths use the actual deployment root, default {directory})\nDelivery README.txt gives an overview. deploy.sh and deploy.ps1 upload and apply over SSH. deploy-target.json selects the target, authentication, and directory. read-target.awk reads that file for scripts. deploy-local.sh unpacks and applies on the server.\nIn the archive, APPLY.txt describes manual deployment and configuration. apply.sh verifies, locks, imports, and starts services. manifest.json records artifacts, mode, selected services, and non-secret metadata. images/ carries OCI archives for import into the engine.\nThe archive's .hai/compose.json contains selected services. The installed copy is the complete merged snapshot. .hai/SHA256SUMS checks the original unpacked files. Server copies can change during configuration finalization and merge.\nCompose uses .hai/middleware-runtime.env for bundled containers. The file can be empty when no native settings are needed. Retained services may refer to an older release, so follow env_file in the effective Compose snapshot. apply.sh consumes .hai/managed-candidates.env for first-install candidates.\n.hai/runtime-env.mjs loads and finalizes the Node environment. Optional files include .hai/request-access.yml, .hai/web.conf, proxy scripts, and .hai/tls/ for access policies, reverse proxying, and HTTPS.\nServer incoming/ holds this upload and unpacked files. releases/ holds deployment and recovery records. Protect and back up managed-secrets.env, persistent-backends, and data volumes together. .deploy.lock coordinates deployment and credential operations.\ncurrent updates after server health checks pass. result-{deploymentId}.json records the outcome and recovery state, steps-{deploymentId}.jsonl records progress, and diagnostics-{deploymentId}.log contains private startup diagnostics on failure. Check active Compose references, mounts, and recovery needs before pruning old releases.",
25152
25164
  deploy_downloadInvalid: "Invalid download source or proxy configuration. URLs must not contain credentials or query parameters.",
25153
25165
  deploy_imageSourceMissing: "Custom image source has no mapping for registry: {registry}",
25154
25166
  deploy_proxySystemUnsupported: "Static system proxy is unavailable, or only PAC/auto-discovery is configured. Use inherit with environment variables or a custom HTTP(S) URL.",
@@ -25283,12 +25295,15 @@ var ja_JP_default = {
25283
25295
  deploy_requestAccessInvalid: "\u30EA\u30AF\u30A8\u30B9\u30C8\u30A2\u30AF\u30BB\u30B9\u8A2D\u5B9A\uFF08{field}\uFF09\u304C\u7121\u52B9\u3067\u3059\u3002\u30D5\u30A3\u30FC\u30EB\u30C9\u3001IP\u3001\u30BF\u30A4\u30E0\u30BE\u30FC\u30F3\u3001\u6642\u9593\u5E2F\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u30D5\u30A1\u30A4\u30EB\u306F\u8AAD\u307F\u53D6\u308A\u53EF\u80FD\u306A 1 MiB \u4EE5\u4E0B\u306E YAML \u3092\u6307\u5B9A\u3057\u3001\u4FEE\u6B63\u5F8C\u306B\u518D\u30D1\u30C3\u30B1\u30FC\u30B8\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
25284
25296
  deploy_httpsPortsInvalid: "HTTP \u3068 HTTPS \u306E\u30DD\u30FC\u30C8\u306F\u7570\u306A\u308B\u5FC5\u8981\u304C\u3042\u308A\u307E\u3059\u3002Let\u2019s Encrypt HTTP-01 \u306B\u306F\u30DB\u30B9\u30C8\u306E\u30DD\u30FC\u30C8 80 \u304C\u5FC5\u8981\u3067\u3059\u3002",
25285
25297
  deploy_httpsCertificateInvalid: "HTTPS \u8A3C\u660E\u66F8\u304C\u7121\u52B9\u3067\u3059\u3002PEM \u30D5\u30A1\u30A4\u30EB\u3001\u6697\u53F7\u5316\u3055\u308C\u3066\u3044\u306A\u3044\u79D8\u5BC6\u9375\u3068\u306E\u4E00\u81F4\u3001\u6709\u52B9\u671F\u9593\u3001\u30C9\u30E1\u30A4\u30F3\u3092\u78BA\u8A8D\u3057\u3001\u518D\u4F5C\u6210\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
25286
- deploy_bundleRuntime: "\u5B9F\u884C\u8A2D\u5B9A\u3068\u53CD\u6620\uFF1A\n\u552F\u4E00\u306E\u30A2\u30D7\u30EA\u8A2D\u5B9A\uFF1A{directory}/config/.env.runtime\n\u4ECA\u56DE\u306E\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\uFF1A{directory}/releases/{deploymentId}/config/.env.runtime\n\u8A2D\u5B9A\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u30FC\u3092 /run/hai/config \u306B\u8AAD\u307F\u53D6\u308A\u5C02\u7528\u3067\u30DE\u30A6\u30F3\u30C8\u3057\u307E\u3059\u3002\u500B\u5225\u5909\u6570\u3092\u7DE8\u96C6\u3057\u3066 Node \u30D0\u30C3\u30AF\u30A8\u30F3\u30C9\u3092\u518D\u8D77\u52D5\u3059\u308B\u3068\u53CD\u6620\u3055\u308C\u3001\u30A2\u30C8\u30DF\u30C3\u30AF\u7F6E\u63DB\u3082\u8AAD\u307F\u53D6\u308C\u307E\u3059\u3002\u540C\u4E00\u30BD\u30FC\u30B9\u3067\u306F\u7D30\u9805\u304C\u89AA JSON \u3088\u308A\u512A\u5148\u3055\u308C\u3001\u7BA1\u7406\u63A5\u7D9A\u3082\u540C\u3058\u30D5\u30A1\u30A4\u30EB\u3067\u3059\u3002\u7DE8\u96C6\u524D\u306B\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u3057\u3001docker restart <\u30B3\u30F3\u30C6\u30CA\u30FC\u540D>\uFF08Podman \u3082\u540C\u69D8\uFF09\u5F8C\u306B\u30D8\u30EB\u30B9\u3068\u696D\u52D9\u3092\u691C\u8A3C\u3057\u307E\u3059\u3002\nWeb/\u30DF\u30C9\u30EB\u30A6\u30A7\u30A2\u306E\u307F\u306E\u66F4\u65B0\u306F\u8A2D\u5B9A\u3092\u7DAD\u6301\u3057\u3001\u90E8\u5206\u30D0\u30C3\u30AF\u30A8\u30F3\u30C9\u66F4\u65B0\u306F\u7BA1\u7406\u63A5\u7D9A\u3092\u7DAD\u6301\u3001\u5168\u91CF\u306F\u65B0\u8A2D\u5B9A\u3068\u65E2\u5B58\u8CC7\u683C\u60C5\u5831\u3092\u4F7F\u7528\u3057\u307E\u3059\u3002\u5931\u6557\u6642\u306F\u5148\u306B\u8A2D\u5B9A\u3001\u6B21\u306B\u30B5\u30FC\u30D3\u30B9\u3092\u5FA9\u5143\u3057\u307E\u3059\u3002\n\u30CD\u30A4\u30C6\u30A3\u30D6\u74B0\u5883\u3001\u9759\u7684 Web\u3001\u30DD\u30FC\u30C8\u3001\u30DE\u30A6\u30F3\u30C8\u3001Node \u8D77\u52D5\u5F15\u6570\u3001Nginx\u3001HTTPS \u306E\u5909\u66F4\u306F\u914D\u5099\u304C\u5FC5\u8981\u3067\u3059\u3002\u30B5\u30A4\u30C8 base \u306F\u518D\u69CB\u7BC9\u3082\u5FC5\u8981\u3067\u3059\u3002\u6052\u4E45\u7684\u306A\u5024\u306F\u5143\u306E\u74B0\u5883\u306B\u3082\u53CD\u6620\u3057\u307E\u3059\u3002",
25298
+ deploy_bundleRuntime: "\u8A2D\u5B9A\u30D5\u30A1\u30A4\u30EB\u3068\u53CD\u6620\u306E\u30BF\u30A4\u30DF\u30F3\u30B0\n\u5C55\u958B\u5148\u306E config/.env.runtime \u306F\u4ECA\u56DE\u306E\u914D\u5099\u5165\u529B\u3067\u3059\u3002\u30A2\u30D7\u30EA\u8A2D\u5B9A\u3068\u540C\u68B1\u30DF\u30C9\u30EB\u30A6\u30A7\u30A2\u306E\u5019\u88DC\u5024\u304C\u542B\u307E\u308C\u307E\u3059\u3002\u5909\u66F4\u306F\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u74B0\u5883\u8A2D\u5B9A\u306B\u53CD\u6620\u3057\u3066\u518D\u30D1\u30C3\u30B1\u30FC\u30B8\u5316\u3057\u3066\u304F\u3060\u3055\u3044\u3002apply.sh \u304C\u5C55\u958B\u5185\u5BB9\u3092\u691C\u8A3C\u3057\u307E\u3059\u3002\n{directory}/config/.env.runtime \u306F\u73FE\u5728\u306E\u5B9F\u884C\u8A2D\u5B9A\u3067\u3059\u3002Serv \u3068 SvelteKit SSR \u306F\u8D77\u52D5\u3054\u3068\u306B\u8AAD\u307F\u53D6\u308A\u5C02\u7528\u306E /run/hai/config \u30DE\u30A6\u30F3\u30C8\u304B\u3089\u8AAD\u307F\u8FBC\u307F\u307E\u3059\u3002\n\u5B9F\u884C\u30D5\u30A1\u30A4\u30EB\u306F dotenv \u306E\u30EA\u30C6\u30E9\u30EB\u69CB\u6587\u3092\u4F7F\u7528\u3057\u3001\u4E0A\u9650\u306F 1 MiB \u3067\u3059\u3002\u6B20\u843D\u3001\u8AAD\u307F\u53D6\u308A\u4E0D\u80FD\u3001\u91CD\u8907\u5B9A\u7FA9\u3001\u4E0A\u9650\u8D85\u904E\u306F\u30A2\u30D7\u30EA\u8D77\u52D5\u524D\u306B\u30A8\u30E9\u30FC\u306B\u306A\u308A\u307E\u3059\u3002\n{directory}/releases/{deploymentId}/config/.env.runtime \u306F\u4ECA\u56DE\u306E\u914D\u5099\u8A18\u9332\u3067\u3059\u3002Web \u307E\u305F\u306F\u30DF\u30C9\u30EB\u30A6\u30A7\u30A2\u306E\u307F\u66F4\u65B0\u3059\u308B\u5834\u5408\u306F\u5F53\u6642\u306E\u5B9F\u884C\u8A2D\u5B9A\u3092\u8A18\u9332\u3057\u307E\u3059\u3002\u73FE\u5728\u5024\u306F\u30EB\u30FC\u30C8\u306E\u30D5\u30A1\u30A4\u30EB\u3092\u3001\u904E\u53BB\u306E\u5024\u306F\u8A72\u5F53\u3059\u308B release \u3092\u53C2\u7167\u3057\u3066\u304F\u3060\u3055\u3044\u3002\n\u5168\u91CF\u914D\u5099\u3067\u306F\u65B0\u3057\u3044\u30A2\u30D7\u30EA\u8A2D\u5B9A\u3068\u65E2\u5B58\u306E\u7BA1\u7406\u8CC7\u683C\u60C5\u5831\u3092\u4F7F\u7528\u3057\u307E\u3059\u3002\u4E3B\u30A2\u30D7\u30EA\u3092\u542B\u3080\u90E8\u5206\u66F4\u65B0\u3067\u306F\u65B0\u3057\u3044\u30A2\u30D7\u30EA\u8A2D\u5B9A\u3068\u5916\u90E8\u63A5\u7D9A\u3092\u9069\u7528\u3057\u3001\u65E2\u5B58\u306E\u7BA1\u7406\u63A5\u7D9A\u3092\u7DAD\u6301\u3057\u307E\u3059\u3002\u4E3B\u30A2\u30D7\u30EA\u3092\u542B\u307E\u306A\u3044\u90E8\u5206\u66F4\u65B0\u3067\u306F\u73FE\u5728\u306E\u8A2D\u5B9A\u3092\u7DAD\u6301\u3057\u307E\u3059\u3002\u5916\u90E8\u3068\u540C\u68B1\u306E\u5207\u308A\u66FF\u3048\u306B\u306F\u5168\u91CF\u914D\u5099\u304C\u5FC5\u8981\u3067\u3059\u3002\nNode \u30D0\u30C3\u30AF\u30A8\u30F3\u30C9\u306E\u4E00\u6642\u4FEE\u6B63\u3067\u306F\u3001\u73FE\u5728\u306E\u30D5\u30A1\u30A4\u30EB\u3092\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u3057\u3066\u7DE8\u96C6\u3057\u3001docker restart <\u30B3\u30F3\u30C6\u30CA\u30FC> \u307E\u305F\u306F podman restart <\u30B3\u30F3\u30C6\u30CA\u30FC> \u3092\u5B9F\u884C\u3057\u3066\u3001\u30D8\u30EB\u30B9\u3068\u5BFE\u8C61\u6A5F\u80FD\u3092\u78BA\u8A8D\u3057\u307E\u3059\u3002\u7D99\u7D9A\u3059\u308B\u5909\u66F4\u306F\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u306E\u74B0\u5883\u8A2D\u5B9A\u306B\u3082\u53CD\u6620\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u30B3\u30F3\u30C6\u30CA\u30FC\u30D7\u30ED\u30BB\u30B9\u306B\u660E\u793A\u3057\u305F\u540C\u540D\u306E HAI_* \u304C\u512A\u5148\u3055\u308C\u307E\u3059\u3002\n\u9759\u7684 Web\u3001\u30DF\u30C9\u30EB\u30A6\u30A7\u30A2\u56FA\u6709\u306E\u74B0\u5883\u5909\u6570\u3001\u30DD\u30FC\u30C8\u3001\u30DE\u30A6\u30F3\u30C8\u3001Node \u8D77\u52D5\u5F15\u6570\u3001Nginx \u306E\u30EB\u30FC\u30C8\u3084\u5236\u9650\u3001HTTPS \u306E\u5909\u66F4\u306F\u518D\u914D\u5099\u3057\u307E\u3059\u3002\u30B5\u30A4\u30C8\u306E base \u30D1\u30B9\u5909\u66F4\u306B\u306F\u518D\u30D3\u30EB\u30C9\u3082\u5FC5\u8981\u3067\u3059\u3002\n\u969C\u5BB3\u5FA9\u65E7\u3067\u306F\u5B9F\u884C\u8A2D\u5B9A\u3092\u5148\u306B\u623B\u3057\u3001\u4EE5\u524D\u306E\u30B5\u30FC\u30D3\u30B9\u3092\u5FA9\u5143\u3057\u307E\u3059\u3002\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u5185\u3067\u5B9F\u884C\u6E08\u307F\u306E\u30D1\u30B9\u30EF\u30FC\u30C9\u3084\u30C7\u30FC\u30BF\u306E\u5909\u66F4\u306F\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u306E\u4FDD\u5B88\u624B\u9806\u3067\u6271\u3044\u307E\u3059\u3002",
25299
+ deploy_refreshCookieSecureInvalid: "HAI_SERV_REFRESH_COOKIE_SECURE \u306B\u306F true\u3001false\u3001\u307E\u305F\u306F\u7A7A\u5024\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u5BFE\u8C61\u74B0\u5883\u3068\u30D1\u30C3\u30B1\u30FC\u30B8\u4F5C\u6210\u30D7\u30ED\u30BB\u30B9\u306E\u540C\u540D\u5909\u6570\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
25300
+ deploy_postgresPasswordConflict: "\u5916\u90E8 PostgreSQL \u306E HAI_DB_URL\uFF08\u307E\u305F\u306F HAI_DB.url\uFF09\u3068 HAI_DB_PASSWORD\uFF08\u307E\u305F\u306F HAI_DB.password\uFF09\u306E\u30D1\u30B9\u30EF\u30FC\u30C9\u304C\u4E00\u81F4\u3057\u307E\u305B\u3093\u3002\u5B8C\u5168\u306A\u63A5\u7D9A URL \u307E\u305F\u306F\u500B\u5225\u9805\u76EE\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
25301
+ deploy_bundleVariables: "\u74B0\u5883\u5909\u6570\u3068\u8ABF\u67FB\uFF08\u540D\u524D\u306E\u307F\uFF09\n\u5BFE\u8C61\u74B0\u5883\u306F {environment} \u3067\u3059\u3002\u4F5C\u6210\u6642\u306E\u512A\u5148\u9806\u306F\u30D7\u30ED\u30BB\u30B9\u3001.env.{environment}.local\u3001.env.local\u3001.env.{environment}\u3001.env\u3001\u30A2\u30D7\u30EA YAML \u306E\u65E2\u5B9A\u5024\u3067\u3059\u3002--env-dir \u3067\u8AAD\u307F\u53D6\u308A\u5148\u3092\u9078\u3073\u307E\u3059\u3002\u540C\u3058\u30BD\u30FC\u30B9\u3067\u306F\u500B\u5225\u9805\u76EE\u304C\u89AA JSON \u3088\u308A\u512A\u5148\u3055\u308C\u3001\u4E0A\u4F4D\u306E\u89AA JSON \u306F\u4E0B\u4F4D\u306E\u69CB\u9020\u9805\u76EE\u3092\u7F6E\u304D\u63DB\u3048\u307E\u3059\u3002\n\u540C\u68B1\u306E config/.env.runtime \u306B\u542B\u307E\u308C\u308B\u5909\u6570\u540D\uFF08--plan \u306F\u5165\u529B\u5074\u306E\u540D\u524D\u3092\u8868\u793A\uFF09: {keys}\nHAI_SERV_REFRESH_COOKIE_SECURE \u306F\u72EC\u7ACB\u3057\u305F\u30D7\u30ED\u30BB\u30B9\u5909\u6570\u3067\u3001\u540C\u540D\u306E\u5024\u306E\u307F\u3067\u4E0A\u66F8\u304D\u3057\u307E\u3059\u3002true \u306F Secure \u3092\u6709\u52B9\u306B\u3057\u3001false \u306F\u7BA1\u7406\u3055\u308C\u305F\u30A4\u30F3\u30C8\u30E9\u30CD\u30C3\u30C8\u307E\u305F\u306F VPN \u306E HTTP \u7528\u3067\u3059\u3002\u7A7A\u5024\u3068\u672A\u8A2D\u5B9A\u306F Serv \u74B0\u5883\u306E\u65E2\u5B9A\u5024\uFF08\u672C\u756A\u3067\u306F\u6709\u52B9\uFF09\u3092\u4F7F\u7528\u3057\u307E\u3059\u3002\u5B9F\u969B\u306E HTTP \u30AA\u30EA\u30B8\u30F3\u3092 HAI_SERV_CORS_ORIGIN \u306B\u8A2D\u5B9A\u3057\u3001\u914D\u5099\u5F8C\u306B\u30ED\u30B0\u30A4\u30F3\u3068\u66F4\u65B0\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002\n\u7BA1\u7406\u3055\u308C\u305F HTTP \u306E\u4F8B\u3067\u306F\u3001.env.{environment}.local \u306B HAI_SERV_REFRESH_COOKIE_SECURE=false \u3068\u5B9F\u969B\u306E CORS \u30AA\u30EA\u30B8\u30F3\u3092\u8A2D\u5B9A\u3057\u307E\u3059\u3002\u5168\u91CF\u914D\u5099\u304C\u6210\u529F\u6E08\u307F\u3067 serv \u30A4\u30E1\u30FC\u30B8\u6210\u679C\u7269\u304C\u3042\u308B\u5834\u5408\u3001\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u3067 pnpm run deploy --env {environment} --bundle-only --yes --services serv \u3092\u5B9F\u884C\u3057\u307E\u3059\u3002\u30B5\u30FC\u30D0\u30FC\u3067\u5C55\u958B\u3057\u3066 sh ./apply.sh \u3092\u5B9F\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002\n\u5916\u90E8 PostgreSQL \u306F\u8A8D\u8A3C\u3092\u542B\u3080\u5B8C\u5168\u306A HAI_DB_URL\u3001\u307E\u305F\u306F HAI_DB_HOST\u3001HAI_DB_PORT\u3001HAI_DB_USER\u3001HAI_DB_DATABASE\u3001HAI_DB_PASSWORD \u3092\u4F7F\u7528\u3057\u307E\u3059\u3002URL \u304C\u512A\u5148\u3055\u308C\u307E\u3059\u3002\u30C7\u30FC\u30BF\u30D9\u30FC\u30B9\u30A2\u30AB\u30A6\u30F3\u30C8\u3068\u30D7\u30ED\u30B8\u30A7\u30AF\u30C8\u74B0\u5883\u306E\u6709\u52B9\u306A\u8A2D\u5B9A\u3092\u66F4\u65B0\u3057\u3001serv \u307E\u305F\u306F\u5168\u91CF\u3092\u914D\u5099\u3057\u3066\u304F\u3060\u3055\u3044\u3002\nHAI_CACHE_*\u3001HAI_STORAGE_*\u3001HAI_VECDB_*\u3001HAI_IAM_LDAP_* \u306F\u30A2\u30D7\u30EA\u63A5\u7D9A\u7528\u3067\u3059\u3002S3 \u306E\u30A8\u30F3\u30C9\u30DD\u30A4\u30F3\u30C8\u3068\u30A2\u30AF\u30BB\u30B9\u30AD\u30FC\u306F\u500B\u5225\u306B\u8A2D\u5B9A\u3057\u307E\u3059\u3002\u5916\u90E8\u304A\u3088\u3073\u30AF\u30E9\u30A6\u30C9\u4E0A\u306E\u30B5\u30FC\u30D3\u30B9\u306B\u306F\u3001\u901A\u5E38\u3053\u306E\u30D0\u30F3\u30C9\u30EB\u306E\u30B3\u30F3\u30C6\u30CA\u30FC\u56FA\u6709\u5909\u6570\u306F\u3042\u308A\u307E\u305B\u3093\u3002\n\u540C\u68B1 PostgreSQL \u3067\u306F managed-secrets.env \u306E DB_PASSWORD \u304B\u3089\u30A2\u30D7\u30EA\u7528\u306E HAI_DB_URL \u3068\u30A4\u30E1\u30FC\u30B8\u7528\u306E POSTGRES_PASSWORD \u3092\u751F\u6210\u3057\u307E\u3059\u3002POSTGRES_PASSWORD \u306F\u7A7A\u306E\u30C7\u30FC\u30BF\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u30FC\u3092\u521D\u671F\u5316\u3057\u307E\u3059\u3002\u4ED6\u306E\u540C\u68B1\u30A4\u30E1\u30FC\u30B8\u3067\u306F MYSQL_*\u3001RUSTFS_*\u3001MINIO_*\u3001LDAP_* \u304C\u4F7F\u308F\u308C\u308B\u5834\u5408\u304C\u3042\u308A\u307E\u3059\u3002\u65E2\u5B58\u30DC\u30EA\u30E5\u30FC\u30E0\u306E\u30D1\u30B9\u30EF\u30FC\u30C9\u5909\u66F4\u306F\u5B9F\u969B\u306E\u30A2\u30AB\u30A6\u30F3\u30C8\u3068\u7BA1\u7406\u72B6\u614B\u3092\u540C\u671F\u3057\u307E\u3059\u3002\nNODE_ENV \u306F\u30A2\u30D7\u30EA\u306E\u5B9F\u884C\u74B0\u5883\u3067\u3059\u3002HOST\u3001PORT\u3001HAI_SERV_SERVER_* \u306E\u5F85\u53D7\u8A2D\u5B9A\u306F\u914D\u5099\u6642\u306B\u78BA\u5B9A\u3057\u307E\u3059\u3002NODE_OPTIONS \u3068 HAI_DEPLOY_PRIVATE_PROXY \u306F\u30B3\u30F3\u30C6\u30CA\u30FC\u306E\u69CB\u6210\u3067\u8A2D\u5B9A\u3055\u308C\u307E\u3059\u3002HAI_DEPLOY_PROVIDER_SSH_PASSWORD \u306F\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u5074\u306E SSH \u7528\u3067\u3059\u3002\n\u30A2\u30FC\u30AB\u30A4\u30D6\u3001\u5B9F\u884C\u8A2D\u5B9A\u3001\u8CC7\u683C\u60C5\u5831\u3001\u79D8\u5BC6\u9375\u3001\u969C\u5BB3\u30ED\u30B0\u306F\u975E\u516C\u958B\u3067\u4FDD\u7BA1\u3057\u3066\u304F\u3060\u3055\u3044\u3002\u904B\u7528\u62C5\u5F53\u8005\u3084 AI \u3068\u5171\u6709\u3059\u308B\u969B\u306F\u5909\u6570\u540D\u3001\u53D6\u5F97\u5143\u3001\u79D8\u533F\u5316\u6E08\u307F\u306E\u30A8\u30E9\u30FC\u3001\u914D\u5099 ID \u306E\u307F\u3092\u4F7F\u7528\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
25287
25302
  deploy_bundleHttpOnly: "HTTPS\uFF1A\u7121\u52B9\u3002HTTP \u30DD\u30FC\u30C8 {port} \u306E\u307F\u3092\u516C\u958B\u3057\u3001\u8A3C\u660E\u66F8\u306F\u540C\u68B1\u305B\u305A\u3001\u30B5\u30FC\u30D0\u30FC\u3067\u3082\u7533\u8ACB\u3057\u307E\u305B\u3093\u3002",
25288
25303
  deploy_bundleHttps: "HTTPS\uFF1A\u6709\u52B9\u3001https://{domain}:{port}\u3001\u30E2\u30FC\u30C9 {mode}\u3002\n\u30B5\u30FC\u30D0\u30FC\u8A3C\u660E\u66F8\uFF1A{certificates}/fullchain.pem\u3001\u79D8\u5BC6\u9375\uFF1A{certificates}/privkey.pem\u3002\u30B3\u30F3\u30C6\u30CA\u306E /etc/nginx/tls/ \u306B\u8AAD\u307F\u53D6\u308A\u5C02\u7528\u3067\u30DE\u30A6\u30F3\u30C8\u3057\u307E\u3059\u3002\n\u914D\u5E03\u5143 .env.{environment}.local \u306E HAI_DEPLOY_PROVIDER \u5185 expose.https\u3001\u307E\u305F\u306F\u4E0A\u66F8\u304D\u3055\u308C\u3066\u3044\u306A\u3044 hai.json.deploy.provider.expose.https \u3092\u7DE8\u96C6\u3057\u307E\u3059\u3002\u6709\u52B9/\u7121\u52B9\u3001\u30E2\u30FC\u30C9\u3001\u30C9\u30E1\u30A4\u30F3\u3001\u30DD\u30FC\u30C8\u5909\u66F4\u306F\u65B0\u3057\u3044\u5168\u91CF\u914D\u5099\u304C\u5FC5\u8981\u3067\u3059\u3002.env.runtime \u306E\u7DE8\u96C6\u3068\u518D\u8D77\u52D5\u3067\u306F\u65B0\u30C9\u30E1\u30A4\u30F3\u306E\u8A3C\u660E\u66F8\u3092\u7533\u8ACB\u3057\u307E\u305B\u3093\u3002",
25289
25304
  deploy_bundleAcme: "Certbot \u6C38\u7D9A\u72B6\u614B\uFF1A{state}\u3001\u73FE\u5728\u306E\u8A3C\u660E\u66F8\u5165\u53E3\uFF1A{state}/live/{domain}\u3002\u30D1\u30C3\u30B1\u30FC\u30B8\u6642\u306F CA \u306B\u63A5\u7D9A\u305B\u305A\u3001\u30B5\u30FC\u30D0\u30FC\u914D\u5099\u6642\u306B\u7533\u8ACB\u3057\u3001\u305D\u306E\u5F8C\u81EA\u52D5\u66F4\u65B0\u3057\u307E\u3059\u3002\u516C\u958B\u30DD\u30FC\u30C8 80 \u3068\u30EB\u30FC\u30C8 /.well-known/acme-challenge/ \u306F\u696D\u52D9 context path \u3068\u5225\u306B\u5230\u9054\u53EF\u80FD\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
25290
25305
  deploy_bundleAccounts: "\u521D\u671F\u30A2\u30AB\u30A6\u30F3\u30C8\u5909\u6570\uFF08\u540D\u524D\u3068\u53D6\u5F97\u5143\u306E\u307F\u3001\u30D1\u30B9\u30EF\u30FC\u30C9\u975E\u8868\u793A\uFF09\uFF1A\n{sources}\n\u5BFE\u5FDC\u3059\u308B\u521D\u671F\u5316\u3092\u6301\u3064\u30A2\u30D7\u30EA\u3067\u306F HAI_CONFIG_ADMIN_PASSWORD \u304C config_admin \u8A2D\u5B9A\u7BA1\u7406\u8005\u3092\u4F5C\u6210\u3057\u307E\u3059\u3002HAI_ADMIN_DEFAULT_PASSWORD\u3001HAI_AUDIT_ADMIN_PASSWORD\u3001HAI_BUSINESS_OPERATOR_PASSWORD \u306F\u4ED6\u306E\u30C6\u30F3\u30D7\u30EC\u30FC\u30C8\u5F79\u5272\u306B\u5BFE\u5FDC\u3057\u307E\u3059\u3002\nFullstack \u4F5C\u6210\u6642\u306B\u74B0\u5883\u3054\u3068\u306E\u72EC\u7ACB\u521D\u671F\u30D1\u30B9\u30EF\u30FC\u30C9\u3092\u751F\u6210\u3057\u3001\u914D\u5E03\u6642\u306F\u9078\u629E\u74B0\u5883\u3068\u30D7\u30ED\u30BB\u30B9\u4E0A\u66F8\u304D\u3092\u8AAD\u307F\u307E\u3059\u3002\u30B5\u30FC\u30D0\u30FC\u914D\u5099\u3067\u65B0\u305F\u306B\u751F\u6210\u3057\u307E\u305B\u3093\u3002\u8A2D\u5B9A\u304C\u3042\u308B\u672A\u4F5C\u6210\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u8D77\u52D5\u6642\u306B\u4F5C\u308A\u3001\u65E2\u5B58\u306E\u30D1\u30B9\u30EF\u30FC\u30C9\u3084\u5909\u66F4\u5F8C\u306E\u5F79\u5272\u306F\u5909\u6570\u5909\u66F4\u3067\u623B\u3057\u307E\u305B\u3093\u3002\u72EC\u81EA\u30A2\u30D7\u30EA\u306F\u5B9F\u88C5\u306B\u5F93\u3044\u307E\u3059\u3002",
25291
- deploy_bundleDirectories: "\u30B5\u30FC\u30D0\u30FC\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u30FC\uFF08\u30EB\u30FC\u30C8 {directory}\uFF09\uFF1A\nincoming/\uFF1A\u30A2\u30FC\u30AB\u30A4\u30D6\u3068\u5C55\u958B\u5148\u3002\u6210\u529F\u5F8C\u306B\u4ECA\u56DE\u5206\u3092\u524A\u9664\u3057\u3001\u5931\u6557\u30FB\u5B9F\u884C\u4E0D\u660E\u3067\u306F\u8A3C\u62E0\u3092\u4FDD\u6301\u3057\u307E\u3059\u3002\nconfig/.env.runtime\uFF1A\u552F\u4E00\u306E\u7DE8\u96C6\u7528\u30A2\u30D7\u30EA\u8A2D\u5B9A\u3002releases/{deploymentId}/config/.env.runtime \u306F\u4ECA\u56DE\u306E\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u3067\u3059\u3002\nreleases/{deploymentId}/manifest.json\uFF1A\u5236\u54C1\u3068\u975E\u6A5F\u5BC6 metadata\u3002\u69CB\u6210\u3001\u4F9D\u5B58\u3001\u30D8\u30EB\u30B9\u3001\u30A4\u30E1\u30FC\u30B8\u3001\u7BA1\u7406\u63A5\u7D9A\u3001\u30D0\u30C3\u30AF\u30A8\u30F3\u30C9\u5BA3\u8A00\u3092\u7D71\u5408\u3057\u3001\u79D8\u5BC6\u5024\u3092\u542B\u3081\u307E\u305B\u3093\u3002\n\u5404 release \u306E .hai/compose.json \u306F\u5B8C\u5168\u306A\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u3067\u3001\u90E8\u5206\u66F4\u65B0\u306F\u9078\u629E\u30B5\u30FC\u30D3\u30B9\u3092\u7F6E\u63DB\u3057\u4ED6\u3092\u4FDD\u6301\u3057\u307E\u3059\u3002.hai/ \u306B\u30CD\u30A4\u30C6\u30A3\u30D6\u74B0\u5883\u3001\u30ED\u30FC\u30C0\u30FC\u3001Nginx/TLS\u3001\u30DD\u30EA\u30B7\u30FC\u3001\u30C1\u30A7\u30C3\u30AF\u30B5\u30E0\u3001\u5FA9\u65E7\u8A3C\u62E0\u3092\u4FDD\u5B58\u3057\u3001\u88DC\u52A9\u51E6\u7406\u306F apply.sh \u306B\u7D71\u5408\u3057\u307E\u3059\u3002\nimages/ \u306F\u5C0E\u5165\u5C02\u7528\u3067 release \u306B\u30B3\u30D4\u30FC\u305B\u305A\u3001\u30C7\u30FC\u30BF\u306F\u30DC\u30EA\u30E5\u30FC\u30E0\u306B\u4FDD\u5B58\u3057\u307E\u3059\u3002\u30EB\u30FC\u30C8 managed-secrets.env\u3001persistent-backends \u3092\u30C7\u30FC\u30BF\u3068\u4E00\u7DD2\u306B\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u3057\u307E\u3059\u3002\ncurrent \u306F\u30D8\u30EB\u30B9\u6210\u529F\u5F8C\u3060\u3051\u66F4\u65B0\u3057\u307E\u3059\u3002result-{deploymentId}.json \u3068 steps-{deploymentId}.jsonl \u3067\u7D50\u679C\u3092\u78BA\u8A8D\u3057\u3001\u53E4\u3044 release \u306E\u524A\u9664\u524D\u306B\u5168 Mounts\u3001\u5B8C\u5168\u306A .hai/compose.json\u3001\u5FA9\u65E7\u8981\u4EF6\u3092\u78BA\u8A8D\u3057\u307E\u3059\u3002",
25306
+ deploy_bundleDirectories: "\u30D5\u30A1\u30A4\u30EB\u7D22\u5F15\uFF08\u30B5\u30FC\u30D0\u30FC\u30D1\u30B9\u306F\u5B9F\u969B\u306E\u914D\u5099\u30EB\u30FC\u30C8\u57FA\u6E96\u3001\u65E2\u5B9A\u5024\u306F {directory}\uFF09\n\u4EA4\u4ED8\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u30FC\u306E README.txt \u306F\u6982\u8981\u3067\u3059\u3002deploy.sh \u3068 deploy.ps1 \u306F SSH \u3067\u8EE2\u9001\u3057\u3066\u9069\u7528\u3057\u307E\u3059\u3002deploy-target.json \u306F\u63A5\u7D9A\u5148\u3001\u8A8D\u8A3C\u3001\u30C7\u30A3\u30EC\u30AF\u30C8\u30EA\u30FC\u3092\u6307\u5B9A\u3057\u3001read-target.awk \u306F\u30B9\u30AF\u30EA\u30D7\u30C8\u7528\u306E\u8AAD\u307F\u53D6\u308A\u51E6\u7406\u3067\u3059\u3002deploy-local.sh \u306F\u30B5\u30FC\u30D0\u30FC\u4E0A\u3067\u5C55\u958B\u3057\u3066\u9069\u7528\u3057\u307E\u3059\u3002\n\u30A2\u30FC\u30AB\u30A4\u30D6\u306E APPLY.txt \u306F\u624B\u52D5\u64CD\u4F5C\u3068\u8A2D\u5B9A\u306E\u8AAC\u660E\u3067\u3059\u3002apply.sh \u306F\u691C\u8A3C\u3001\u30ED\u30C3\u30AF\u3001\u30A4\u30F3\u30DD\u30FC\u30C8\u3001\u8D77\u52D5\u3092\u5B9F\u884C\u3057\u307E\u3059\u3002manifest.json \u306F\u6210\u679C\u7269\u3001\u914D\u5099\u30E2\u30FC\u30C9\u3001\u5BFE\u8C61\u30B5\u30FC\u30D3\u30B9\u3001\u975E\u6A5F\u5BC6\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u8A18\u9332\u3057\u307E\u3059\u3002images/ \u306E OCI \u30A2\u30FC\u30AB\u30A4\u30D6\u3092\u30A8\u30F3\u30B8\u30F3\u306B\u53D6\u308A\u8FBC\u307F\u307E\u3059\u3002\n\u30A2\u30FC\u30AB\u30A4\u30D6\u306E .hai/compose.json \u306F\u9078\u629E\u3057\u305F\u30B5\u30FC\u30D3\u30B9\u3092\u542B\u307F\u3001\u914D\u5099\u5F8C\u306F\u7D71\u5408\u6E08\u307F\u306E\u5B8C\u5168\u306A\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u306B\u306A\u308A\u307E\u3059\u3002.hai/SHA256SUMS \u306F\u5143\u306E\u5C55\u958B\u5185\u5BB9\u3092\u691C\u8A3C\u3057\u307E\u3059\u3002\u30B5\u30FC\u30D0\u30FC\u5074\u306E\u30B3\u30D4\u30FC\u306F\u8A2D\u5B9A\u78BA\u5B9A\u3084\u7D71\u5408\u6642\u306B\u5909\u66F4\u3055\u308C\u307E\u3059\u3002\n.hai/middleware-runtime.env \u306F\u540C\u68B1\u30B3\u30F3\u30C6\u30CA\u30FC\u7528\u306E Compose env_file \u3067\u3059\u3002\u5FC5\u8981\u306A\u56FA\u6709\u5909\u6570\u304C\u306A\u3051\u308C\u3070\u7A7A\u306B\u306A\u308B\u5834\u5408\u304C\u3042\u308A\u307E\u3059\u3002\u7DAD\u6301\u3057\u305F\u30B5\u30FC\u30D3\u30B9\u304C\u53E4\u3044 release \u3092\u53C2\u7167\u3059\u308B\u5834\u5408\u306F\u3001\u6709\u52B9\u306A Compose \u306E env_file \u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002apply.sh \u306F .hai/managed-candidates.env \u306E\u521D\u56DE\u7528\u5019\u88DC\u3092\u51E6\u7406\u3057\u307E\u3059\u3002\n.hai/runtime-env.mjs \u306F Node \u306E\u8A2D\u5B9A\u78BA\u5B9A\u3068\u8D77\u52D5\u6642\u306E\u8AAD\u307F\u8FBC\u307F\u3092\u62C5\u5F53\u3057\u307E\u3059\u3002.hai/request-access.yml\u3001.hai/web.conf\u3001\u30D7\u30ED\u30AD\u30B7\u30B9\u30AF\u30EA\u30D7\u30C8\u3001.hai/tls/ \u306F\u30A2\u30AF\u30BB\u30B9\u5236\u5FA1\u3001\u30EA\u30D0\u30FC\u30B9\u30D7\u30ED\u30AD\u30B7\u3001HTTPS \u7528\u306E\u4EFB\u610F\u30D5\u30A1\u30A4\u30EB\u3067\u3059\u3002\n\u30B5\u30FC\u30D0\u30FC\u306E incoming/ \u306F\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u3068\u5C55\u958B\u5185\u5BB9\u3001releases/ \u306F\u914D\u5099\u3068\u5FA9\u65E7\u306E\u8A18\u9332\u3092\u4FDD\u6301\u3057\u307E\u3059\u3002managed-secrets.env\u3001persistent-backends\u3001\u30C7\u30FC\u30BF\u30DC\u30EA\u30E5\u30FC\u30E0\u306F\u4E00\u7DD2\u306B\u4FDD\u8B77\u3057\u30D0\u30C3\u30AF\u30A2\u30C3\u30D7\u3057\u307E\u3059\u3002.deploy.lock \u306F\u914D\u5099\u3068\u8CC7\u683C\u60C5\u5831\u64CD\u4F5C\u306E\u8ABF\u6574\u306B\u4F7F\u3044\u307E\u3059\u3002\n\u30B5\u30FC\u30D0\u30FC\u306E\u30D8\u30EB\u30B9\u30C1\u30A7\u30C3\u30AF\u901A\u904E\u5F8C\u306B current \u3092\u66F4\u65B0\u3057\u307E\u3059\u3002result-{deploymentId}.json \u306F\u7D50\u679C\u3068\u5FA9\u65E7\u72B6\u614B\u3001steps-{deploymentId}.jsonl \u306F\u9032\u884C\u72B6\u6CC1\u3001diagnostics-{deploymentId}.log \u306F\u8D77\u52D5\u5931\u6557\u6642\u306E\u975E\u516C\u958B\u8A3A\u65AD\u3067\u3059\u3002\u53E4\u3044 release \u306E\u6574\u7406\u524D\u306B\u73FE\u5728\u306E Compose \u306E\u53C2\u7167\u3001\u30DE\u30A6\u30F3\u30C8\u3001\u5FA9\u65E7\u306E\u8981\u4EF6\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
25292
25307
  deploy_downloadInvalid: "\u53D6\u5F97\u5143\u307E\u305F\u306F\u30D7\u30ED\u30AD\u30B7\u8A2D\u5B9A\u304C\u7121\u52B9\u3067\u3059\u3002URL \u306B\u8A8D\u8A3C\u60C5\u5831\u3084\u30AF\u30A8\u30EA\u3092\u542B\u3081\u306A\u3044\u3067\u304F\u3060\u3055\u3044\u3002",
25293
25308
  deploy_imageSourceMissing: "\u30AB\u30B9\u30BF\u30E0\u53D6\u5F97\u5143\u306B\u30EC\u30B8\u30B9\u30C8\u30EA\u30FC\u306E\u5BFE\u5FDC\u8868\u304C\u3042\u308A\u307E\u305B\u3093\uFF1A{registry}",
25294
25309
  deploy_proxySystemUnsupported: "\u9759\u7684\u30B7\u30B9\u30C6\u30E0\u30D7\u30ED\u30AD\u30B7\u3092\u53D6\u5F97\u3067\u304D\u306A\u3044\u304B\u3001PAC\uFF0F\u81EA\u52D5\u691C\u51FA\u306E\u307F\u304C\u8A2D\u5B9A\u3055\u308C\u3066\u3044\u307E\u3059\u3002\u74B0\u5883\u5909\u6570\u3092 inherit \u3059\u308B\u304B\u3001custom HTTP(S) URL \u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
@@ -25423,12 +25438,15 @@ var zh_CN_default2 = {
25423
25438
  deploy_requestAccessInvalid: "\u8BF7\u6C42\u8BBF\u95EE\u7B56\u7565\u914D\u7F6E\u65E0\u6548\uFF08{field}\uFF09\u3002\u8BF7\u68C0\u67E5\u5B57\u6BB5\u3001IP\u3001\u65F6\u533A\u53CA\u65F6\u95F4\u7A97\u53E3\uFF1B\u5982\u5F15\u7528\u6587\u4EF6\uFF0C\u8BF7\u786E\u8BA4\u6587\u4EF6\u53EF\u8BFB\u3001\u683C\u5F0F\u4E3A YAML \u4E14\u4E0D\u8D85\u8FC7 1 MiB\u3002\u4FEE\u6B63\u540E\u91CD\u65B0\u6253\u5305\u3002",
25424
25439
  deploy_httpsPortsInvalid: "HTTP \u4E0E HTTPS \u7AEF\u53E3\u5FC5\u987B\u4E0D\u540C\uFF1BLet\u2019s Encrypt \u7684 HTTP-01 \u5165\u53E3\u5FC5\u987B\u4F7F\u7528\u5BBF\u4E3B\u673A 80 \u7AEF\u53E3\u3002",
25425
25440
  deploy_httpsCertificateInvalid: "HTTPS \u8BC1\u4E66\u65E0\u6548\uFF1A\u8BF7\u6838\u5BF9 PEM \u6587\u4EF6\u53EF\u8BFB\u3001\u8BC1\u4E66\u4E0E\u672A\u52A0\u5BC6\u79C1\u94A5\u5339\u914D\u3001\u8BC1\u4E66\u6709\u6548\u671F\u53CA\u57DF\u540D\uFF0C\u7136\u540E\u91CD\u65B0\u6253\u5305\u3002",
25426
- deploy_bundleRuntime: "\u8FD0\u884C\u914D\u7F6E\u4E0E\u751F\u6548\uFF1A\n\u5E94\u7528\u552F\u4E00\u914D\u7F6E\uFF1A{directory}/config/.env.runtime\n\u672C\u6B21\u914D\u7F6E\u5FEB\u7167\uFF1A{directory}/releases/{deploymentId}/config/.env.runtime\n\u914D\u7F6E\u76EE\u5F55\u53EA\u8BFB\u6302\u8F7D\u5230 /run/hai/config\uFF0C\u4FEE\u6539\u7EC6\u9879\u540E\u91CD\u542F Node \u540E\u7AEF\u5373\u53EF\uFF0C\u7F16\u8F91\u5668\u539F\u5B50\u66FF\u6362\u6587\u4EF6\u4E5F\u4F1A\u88AB\u8BFB\u53D6\u3002\u540C\u6E90\u7EC6\u9879\u8986\u76D6\u7236 JSON\uFF1B\u6258\u7BA1\u8FDE\u63A5\u5DF2\u5408\u5E76\u5230\u540C\u4E00\u6587\u4EF6\u3002\u5907\u4EFD\u540E\u7F16\u8F91\uFF0C\u518D docker restart <\u5BB9\u5668\u540D>\uFF08Podman \u540C\u7406\uFF09\uFF0C\u9A8C\u8BC1\u5065\u5EB7\u4E0E\u53D7\u5F71\u54CD\u4E1A\u52A1\u3002\nWeb/\u4E2D\u95F4\u4EF6\u5C40\u90E8\u66F4\u65B0\u4FDD\u7559\u5F53\u524D\u6587\u4EF6\uFF1B\u5C40\u90E8\u540E\u7AEF\u66F4\u65B0\u4FDD\u7559\u6258\u7BA1\u8FDE\u63A5\uFF0C\u5B8C\u6574\u66F4\u65B0\u91C7\u7528\u65B0\u5305\u5E76\u590D\u7528\u670D\u52A1\u5668\u51ED\u636E\u3002\u5931\u8D25\u6062\u590D\u5148\u8FD8\u539F\u5E94\u7528\u914D\u7F6E\u518D\u6062\u590D\u670D\u52A1\u3002\n\u9759\u6001 Web/\u4E2D\u95F4\u4EF6\u539F\u751F\u73AF\u5883\u3001\u7AEF\u53E3\u3001\u6302\u8F7D\u3001Node \u542F\u52A8\u53C2\u6570\u3001Nginx \u8DEF\u7531/\u9650\u989D\u548C HTTPS \u5E03\u5C40\u53D8\u66F4\u9700\u8981\u91CD\u65B0\u90E8\u7F72\uFF1B\u7F51\u7AD9 base \u53D8\u5316\u8FD8\u9700\u91CD\u5EFA\u3002\u957F\u671F\u914D\u7F6E\u540C\u6B65\u6E90\u73AF\u5883\u3002",
25441
+ deploy_bundleRuntime: "\u914D\u7F6E\u6587\u4EF6\u4E0E\u751F\u6548\u65F6\u673A\n\u89E3\u5305\u76EE\u5F55 config/.env.runtime \u662F\u672C\u5305\u8F93\u5165\uFF0C\u5305\u542B\u5E94\u7528\u914D\u7F6E\u548C\u53EF\u80FD\u7684\u968F\u5305\u4E2D\u95F4\u4EF6\u5019\u9009\u3002\u4FEE\u6539\u9879\u76EE\u6E90\u73AF\u5883\u540E\u91CD\u65B0\u6253\u5305\u3002apply.sh \u4F1A\u6821\u9A8C\u5F52\u6863\u5185\u5BB9\u3002\n{directory}/config/.env.runtime \u662F\u5F53\u524D\u8FD0\u884C\u914D\u7F6E\u3002Serv \u548C SvelteKit SSR \u6BCF\u6B21\u542F\u52A8\u4ECE\u53EA\u8BFB\u6302\u8F7D\u7684 /run/hai/config/.env.runtime \u8BFB\u53D6\u3002\n\u8FD0\u884C\u6587\u4EF6\u6309 dotenv \u5B57\u9762\u8BED\u6CD5\u8BFB\u53D6\uFF0C\u5927\u5C0F\u4E0A\u9650\u4E3A 1 MiB\u3002\u7F3A\u5931\u3001\u4E0D\u53EF\u8BFB\u3001\u91CD\u590D\u8D4B\u503C\u6216\u8D85\u9650\u65F6\u4F1A\u5728\u5E94\u7528\u542F\u52A8\u524D\u62A5\u9519\u3002\n{directory}/releases/{deploymentId}/config/.env.runtime \u662F\u672C\u6B21\u53D1\u5E03\u8BB0\u5F55\u3002\u4EC5\u66F4\u65B0 Web \u6216\u4E2D\u95F4\u4EF6\u65F6\uFF0C\u8BB0\u5F55\u91C7\u7528\u5F53\u65F6\u7684\u5F53\u524D\u914D\u7F6E\u3002\u67E5\u5F53\u524D\u503C\u7528\u90E8\u7F72\u6839\u6587\u4EF6\uFF0C\u67E5\u67D0\u6B21\u53D1\u5E03\u7528\u5BF9\u5E94 release\u3002\n\u5168\u91CF\u91C7\u7528\u65B0\u5305\u914D\u7F6E\u5E76\u590D\u7528\u670D\u52A1\u5668\u53D7\u7BA1\u5BC6\u7801\u3002\u5305\u542B\u4E3B\u5E94\u7528\u7684\u589E\u91CF\u91C7\u7528\u65B0\u5305\u7684\u5916\u90E8\u8FDE\u63A5\u548C\u5E94\u7528\u914D\u7F6E\uFF0C\u5E76\u4FDD\u7559\u65E2\u6709\u53D7\u7BA1\u8FDE\u63A5\u3002\u672A\u9009\u4E3B\u5E94\u7528\u7684\u589E\u91CF\u4FDD\u7559\u5F53\u524D\u914D\u7F6E\u3002\u5916\u90E8\u548C\u53D7\u7BA1\u4E4B\u95F4\u7684\u5207\u6362\u9700\u8981\u5168\u91CF\u53D1\u5E03\u3002\n\u4E34\u65F6\u4FEE\u590D Node \u540E\u7AEF\u914D\u7F6E\u65F6\uFF0C\u5907\u4EFD\u540E\u4FEE\u6539\u90E8\u7F72\u6839\u7684\u8FD0\u884C\u6587\u4EF6\uFF0C\u518D docker restart <\u5BB9\u5668\u540D> \u6216 podman restart <\u5BB9\u5668\u540D>\uFF0C\u9A8C\u8BC1\u5065\u5EB7\u548C\u76F8\u5173\u4E1A\u52A1\u3002\u957F\u671F\u4FEE\u6539\u5199\u56DE\u9879\u76EE\u6E90\u73AF\u5883\uFF0C\u5426\u5219\u4E0B\u6B21\u5305\u542B\u540E\u7AEF\u7684\u53D1\u5E03\u53EF\u80FD\u8986\u76D6\u3002\u5BB9\u5668\u8FDB\u7A0B\u663E\u5F0F\u4F20\u5165\u7684\u540C\u540D HAI_* \u4F18\u5148\u3002\n\u9759\u6001 Web\u3001\u4E2D\u95F4\u4EF6\u539F\u751F\u73AF\u5883\u3001\u7AEF\u53E3\u548C\u6302\u8F7D\u3001Node \u542F\u52A8\u53C2\u6570\u3001Nginx \u8DEF\u7531\u548C\u9650\u989D\u3001HTTPS \u88C5\u914D\u5747\u5728\u90E8\u7F72\u65F6\u751F\u6548\u3002\u7F51\u7AD9 base \u53D8\u66F4\u8FD8\u9700\u91CD\u5EFA\u3002\n\u5931\u8D25\u6062\u590D\u5148\u8FD8\u539F\u5E94\u7528\u8FD0\u884C\u6587\u4EF6\uFF0C\u518D\u6062\u590D\u65E7\u670D\u52A1\u3002\u6570\u636E\u5E93\u4E2D\u5DF2\u6267\u884C\u7684\u5BC6\u7801\u6216\u6570\u636E\u53D8\u66F4\u987B\u7531\u6570\u636E\u5E93\u7EF4\u62A4\u6D41\u7A0B\u5904\u7406\u3002",
25442
+ deploy_refreshCookieSecureInvalid: "HAI_SERV_REFRESH_COOKIE_SECURE \u53EA\u63A5\u53D7 true\u3001false \u6216\u7A7A\u503C\u3002\u8BF7\u68C0\u67E5\u6240\u9009\u90E8\u7F72\u73AF\u5883\u53CA\u6253\u5305\u8FDB\u7A0B\u4E2D\u7684\u540C\u540D\u53D8\u91CF\u3002",
25443
+ deploy_postgresPasswordConflict: "\u5916\u90E8 PostgreSQL \u7684 HAI_DB_URL\uFF08\u6216 HAI_DB.url\uFF09\u4E0E HAI_DB_PASSWORD\uFF08\u6216 HAI_DB.password\uFF09\u5BC6\u7801\u4E0D\u4E00\u81F4\u3002\u8BF7\u4F7F\u7528\u5B8C\u6574\u8FDE\u63A5\u4E32\u6216\u5206\u5B57\u6BB5\u914D\u7F6E\u3002",
25444
+ deploy_bundleVariables: "\u73AF\u5883\u53D8\u91CF\u4E0E\u6392\u67E5\uFF08\u53EA\u5217\u540D\u79F0\uFF09\n\u6240\u9009\u73AF\u5883\u4E3A {environment}\u3002\u6253\u5305\u8F93\u5165\u4ECE\u9AD8\u5230\u4F4E\u4E3A\u6253\u5305\u8FDB\u7A0B\u3001.env.{environment}.local\u3001.env.local\u3001.env.{environment}\u3001.env\uFF0C\u7136\u540E\u662F\u5E94\u7528 YAML \u9ED8\u8BA4\u503C\u3002--env-dir \u9009\u62E9\u73AF\u5883\u6587\u4EF6\u76EE\u5F55\u3002\u540C\u6E90\u7EC6\u9879\u8986\u76D6\u7236 JSON\uFF0C\u8F83\u9AD8\u6765\u6E90\u7684\u7236 JSON \u66FF\u6362\u65E7\u7ED3\u6784\u7EC6\u9879\u3002\n\u672C\u5305 config/.env.runtime \u4E2D\u7684\u53D8\u91CF\u540D\uFF08--plan \u5217\u7684\u662F\u6E90\u73AF\u5883\u8F93\u5165\u952E\uFF09\uFF1A{keys}\nHAI_SERV_REFRESH_COOKIE_SECURE \u662F\u72EC\u7ACB\u8FDB\u7A0B\u5F00\u5173\uFF0C\u53EA\u7531\u540C\u540D\u53D8\u91CF\u8986\u76D6\u3002true \u542F\u7528 Secure\uFF0Cfalse \u4EC5\u7528\u4E8E\u53D7\u63A7\u5185\u7F51\u6216 VPN \u7684 HTTP \u5165\u53E3\uFF0C\u7A7A\u503C\u6216\u672A\u8BBE\u7F6E\u4F7F\u7528 Serv \u73AF\u5883\u9ED8\u8BA4\u7B56\u7565\uFF08\u751F\u4EA7\u5F00\u542F\uFF09\u3002HTTP \u5165\u53E3\u4ECD\u9700\u8BBE\u7F6E\u5B9E\u9645 HAI_SERV_CORS_ORIGIN\u3002\u90E8\u7F72\u540E\u786E\u8BA4\u767B\u5F55\u548C\u5237\u65B0\u3002\n\u793A\u4F8B\uFF1A\u5728\u53D7\u63A7 HTTP \u73AF\u5883\u7684 .env.{environment}.local \u4E2D\u5199 HAI_SERV_REFRESH_COOKIE_SECURE=false\uFF0C\u5E76\u8BBE\u7F6E\u5B9E\u9645\u7684 CORS Origin\u3002\u5DF2\u6709\u6210\u529F\u5168\u91CF\u548C serv \u955C\u50CF\u5236\u54C1\u65F6\uFF0C\u53EF\u5728\u9879\u76EE\u76EE\u5F55\u6267\u884C pnpm run deploy --env {environment} --bundle-only --yes --services serv\uFF0C\u7136\u540E\u5728\u670D\u52A1\u5668\u89E3\u5305\u5E76\u6267\u884C sh ./apply.sh\u3002\n\u5916\u90E8 PostgreSQL \u4F7F\u7528 HAI_DB_URL\uFF08\u5B8C\u6574\u8FDE\u63A5\u4E32\uFF0C\u542B\u6240\u9700\u8BA4\u8BC1\uFF09\u6216 HAI_DB_HOST\u3001HAI_DB_PORT\u3001HAI_DB_USER\u3001HAI_DB_DATABASE\u3001HAI_DB_PASSWORD\u3002URL \u4F1A\u4F18\u5148\uFF0C\u6539\u5BC6\u65F6\u66F4\u65B0\u751F\u6548\u7684\u914D\u7F6E\u65B9\u5F0F\u3002\u6570\u636E\u5E93\u8D26\u53F7\u548C\u6E90\u73AF\u5883\u6539\u597D\u540E\uFF0C\u91CD\u65B0\u53D1\u5E03 serv \u6216\u5168\u91CF\u53D1\u5E03\u3002\nHAI_CACHE_*\u3001HAI_STORAGE_*\u3001HAI_VECDB_* \u548C HAI_IAM_LDAP_* \u662F\u5E94\u7528\u8FDE\u63A5\u3002S3 \u5730\u5740\u4E0E\u8BBF\u95EE\u5BC6\u94A5\u5206\u522B\u914D\u7F6E\u3002\u5916\u90E8\u6216\u4E91\u5F00\u901A\u7684\u670D\u52A1\u7531\u5E94\u7528\u8FDE\u63A5\uFF0C\u901A\u5E38\u65E0\u672C\u5305\u7684\u955C\u50CF\u539F\u751F\u53D8\u91CF\u3002\n\u968F\u5305 PostgreSQL \u4ECE managed-secrets.env \u7684 DB_PASSWORD \u751F\u6210\u5E94\u7528\u8FDE\u63A5 HAI_DB_URL \u548C\u539F\u751F POSTGRES_PASSWORD\u3002POSTGRES_PASSWORD \u7528\u4E8E\u521D\u59CB\u5316\u7A7A\u6570\u636E\u76EE\u5F55\u3002\u5176\u4ED6\u968F\u5305\u955C\u50CF\u53EF\u80FD\u4F7F\u7528 MYSQL_*\u3001RUSTFS_*\u3001MINIO_* \u6216 LDAP_*\u3002\u5DF2\u6709\u5377\u7684\u8D26\u53F7\u8F6E\u6362\u9700\u8981\u540C\u6B65\u5B9E\u9645\u8D26\u53F7\u548C\u53D7\u7BA1\u72B6\u6001\u3002\u4EC5\u91CD\u542F\u6216\u91CD\u5EFA\u5BB9\u5668\u65E0\u6CD5\u5B8C\u6210\u6570\u636E\u5E93\u6362\u5BC6\u3002\nNODE_ENV \u5F71\u54CD\u5E94\u7528\u73AF\u5883\u3002HOST\u3001PORT \u548C HAI_SERV_SERVER_* \u7684\u76D1\u542C\u5730\u5740/\u7AEF\u53E3\u7531\u4EA4\u4ED8\u62D3\u6251\u5B9A\u7A3F\u3002NODE_OPTIONS \u548C HAI_DEPLOY_PRIVATE_PROXY \u5C5E\u4E8E\u5BB9\u5668\u88C5\u914D\u3002HAI_DEPLOY_PROVIDER_SSH_PASSWORD \u7531\u4E0A\u4F20\u7AEF\u7528\u4E8E SSH\uFF0C\u4E0E\u5E94\u7528\u8FDE\u63A5\u5206\u5F00\u3002\n\u5F52\u6863\u3001\u8FD0\u884C\u6587\u4EF6\u3001\u51ED\u636E\u3001\u79C1\u94A5\u548C\u6545\u969C\u65E5\u5FD7\u6309\u79C1\u6709\u8D44\u6599\u4FDD\u7BA1\u3002\u6392\u67E5\u6216\u4EA4\u7ED9 AI \u65F6\u53EA\u63D0\u4F9B\u53D8\u91CF\u540D\u3001\u6765\u6E90\u3001\u8131\u654F\u9519\u8BEF\u548C\u90E8\u7F72 ID\u3002",
25427
25445
  deploy_bundleHttpOnly: "HTTPS\uFF1A\u672A\u542F\u7528\u3002\u672C\u5305\u4EC5\u53D1\u5E03 HTTP \u7AEF\u53E3 {port}\uFF0C\u6CA1\u6709\u8BC1\u4E66\u9644\u4EF6\uFF0C\u4E5F\u4E0D\u4F1A\u5728\u670D\u52A1\u5668\u7533\u8BF7\u8BC1\u4E66\u3002",
25428
25446
  deploy_bundleHttps: "HTTPS\uFF1A\u5DF2\u542F\u7528\uFF0Chttps://{domain}:{port}\uFF1B\u6A21\u5F0F {mode}\u3002\n\u670D\u52A1\u5668\u8BC1\u4E66\uFF1A{certificates}/fullchain.pem\uFF1B\u79C1\u94A5\uFF1A{certificates}/privkey.pem\u3002\u5BB9\u5668\u53EA\u8BFB\u6302\u8F7D\u5230 /etc/nginx/tls/\u3002\n\u4FEE\u6539\u672C\u5730\u6253\u5305\u73AF\u5883 .env.{environment}.local \u7684 HAI_DEPLOY_PROVIDER \u4E2D expose.https\uFF0C\u6216\u672A\u88AB\u8986\u76D6\u7684 hai.json.deploy.provider.expose.https\u3002\u542F\u505C\u3001\u5207\u6362\u6A21\u5F0F/\u57DF\u540D/\u7AEF\u53E3\u540E\u751F\u6210\u65B0\u7684\u5168\u91CF\u90E8\u7F72\u5305\uFF1B\u4FEE\u6539 .env.runtime \u5E76\u91CD\u542F\u4E0D\u80FD\u89E6\u53D1\u65B0\u57DF\u540D\u7B7E\u53D1\u3002",
25429
25447
  deploy_bundleAcme: "Certbot \u6301\u4E45\u72B6\u6001\uFF1A{state}\uFF1B\u5F53\u524D\u8BC1\u4E66\u5165\u53E3\uFF1A{state}/live/{domain}\u3002\u6253\u5305\u4E0D\u8BF7\u6C42 CA\uFF0C\u670D\u52A1\u5668\u90E8\u7F72\u65F6\u7533\u8BF7\uFF0C\u4E4B\u540E\u81EA\u52A8\u7EED\u671F\u3002\u516C\u7F51 80 \u7AEF\u53E3\u53CA\u6839\u8DEF\u5F84 /.well-known/acme-challenge/ \u5FC5\u987B\u53EF\u8FBE\uFF0C\u4E0D\u80FD\u53EA\u5141\u8BB8\u4E1A\u52A1 context path\u3002",
25430
25448
  deploy_bundleAccounts: "\u521D\u59CB\u8D26\u53F7\u53D8\u91CF\uFF08\u53EA\u5217\u540D\u79F0\u548C\u6765\u6E90\uFF0C\u4E0D\u663E\u793A\u5BC6\u7801\uFF09\uFF1A\n{sources}\nHAI_CONFIG_ADMIN_PASSWORD \u4F9B\u6709\u76F8\u5E94\u5F15\u5BFC\u903B\u8F91\u7684\u5E94\u7528\u521B\u5EFA config_admin \u914D\u7F6E\u7BA1\u7406\u5458\uFF1BHAI_ADMIN_DEFAULT_PASSWORD\u3001HAI_AUDIT_ADMIN_PASSWORD\u3001HAI_BUSINESS_OPERATOR_PASSWORD \u5BF9\u5E94\u5176\u4ED6\u6A21\u677F\u804C\u8D23\u8D26\u53F7\u3002\nCLI \u521B\u5EFA Fullstack \u65F6\u4E3A\u5404\u73AF\u5883\u751F\u6210\u72EC\u7ACB\u521D\u59CB\u5BC6\u7801\uFF1B\u6253\u5305\u8BFB\u53D6\u6240\u9009\u73AF\u5883\u4E0E\u8FDB\u7A0B\u8986\u76D6\uFF0C\u4E0D\u4F1A\u56E0\u670D\u52A1\u5668\u90E8\u7F72\u518D\u751F\u6210\u5E94\u7528\u8D26\u53F7\u5BC6\u7801\u3002\u6709\u914D\u7F6E\u4E14\u8D26\u53F7\u7F3A\u5931\u65F6\u7531\u5E94\u7528\u542F\u52A8\u5F15\u5BFC\uFF1B\u5DF2\u6709\u8D26\u53F7\u4E0D\u4F1A\u56E0\u4FEE\u6539\u53D8\u91CF\u91CD\u7F6E\u5BC6\u7801\u6216\u6062\u590D\u65E7\u804C\u8D23\u3002\u65E0\u76F8\u5E94\u5F15\u5BFC\u903B\u8F91\u7684\u81EA\u5B9A\u4E49\u5E94\u7528\u4EE5\u81EA\u8EAB\u5B9E\u73B0\u4E3A\u51C6\u3002",
25431
- deploy_bundleDirectories: "\u670D\u52A1\u5668\u76EE\u5F55\u8BF4\u660E\uFF08\u6839\u76EE\u5F55 {directory}\uFF09\uFF1A\nincoming/\uFF1A\u4E0A\u4F20\u5F52\u6863\u548C\u89E3\u5305\u76EE\u5F55\uFF0C\u6210\u529F\u540E\u6E05\u7406\u672C\u6B21\u5185\u5BB9\uFF0C\u5931\u8D25\u6216\u6267\u884C\u672A\u77E5\u65F6\u4FDD\u7559\u8BC1\u636E\u3002\nconfig/.env.runtime\uFF1A\u552F\u4E00\u53EF\u7F16\u8F91\u5E94\u7528\u914D\u7F6E\uFF1Breleases/{deploymentId}/config/.env.runtime \u4FDD\u5B58\u672C\u6B21\u5FEB\u7167\u3002\nreleases/{deploymentId}/manifest.json\uFF1A\u5236\u54C1\u548C\u975E\u654F\u611F metadata\uFF0C\u96C6\u4E2D\u4FDD\u5B58\u5E03\u5C40\u3001\u4F9D\u8D56\u3001\u5065\u5EB7\u8DEF\u5F84\u3001\u955C\u50CF\u5217\u8868\u3001\u53D7\u7BA1\u7ED1\u5B9A\u548C\u5377\u540E\u7AEF\u58F0\u660E\uFF0C\u4E0D\u542B\u79D8\u5BC6\u3002\n\u6BCF\u4E2A release \u7684 .hai/compose.json \u662F\u5B8C\u6574\u670D\u52A1\u5FEB\u7167\uFF0C\u5C40\u90E8\u90E8\u7F72\u6309\u670D\u52A1\u66FF\u6362\u5E76\u4FDD\u7559\u672A\u9009\u5B9A\u4E49\uFF1B.hai/ \u8FD8\u4FDD\u5B58\u539F\u751F\u73AF\u5883\u3001\u52A0\u8F7D\u5668\u3001Nginx/TLS\u3001\u7B56\u7565\u3001\u6821\u9A8C\u548C\u4E0E\u6062\u590D\u8BC1\u636E\u3002\u8F85\u52A9\u811A\u672C\u5185\u5D4C apply.sh\u3002\nimages/ \u4EC5\u7528\u4E8E\u672C\u6B21\u5BFC\u5165\uFF0C\u4E0D\u590D\u5236\u5230 release\uFF1B\u955C\u50CF\u4FDD\u5B58\u5728\u5F15\u64CE\uFF0C\u4E1A\u52A1\u6570\u636E\u5728\u5377\u3002\u6839\u76EE\u5F55 managed-secrets.env\u3001persistent-backends \u4E0E\u6570\u636E\u5377\u6210\u5957\u5907\u4EFD\u3002\ncurrent \u53EA\u5728\u5065\u5EB7\u901A\u8FC7\u540E\u66F4\u65B0\uFF1B\u7ED3\u5408 result-{deploymentId}.json \u548C steps-{deploymentId}.jsonl \u5224\u65AD\u672C\u6B21\u7ED3\u679C\u3002\u6E05\u7406\u65E7 release \u524D\u6838\u5BF9\u6240\u6709\u6D3B\u52A8\u6302\u8F7D\u3001\u5B8C\u6574 .hai/compose.json \u548C\u6062\u590D\u9700\u8981\u3002",
25449
+ deploy_bundleDirectories: "\u6587\u4EF6\u7D22\u5F15\uFF08\u670D\u52A1\u5668\u8DEF\u5F84\u4EE5\u5B9E\u9645\u90E8\u7F72\u6839\u4E3A\u51C6\uFF0C\u9ED8\u8BA4 {directory}\uFF09\n\u4EA4\u4ED8\u76EE\u5F55 README.txt \u63D0\u4F9B\u603B\u89C8\u3002deploy.sh \u548C deploy.ps1 \u901A\u8FC7 SSH \u4F20\u8F93\u5E76\u6267\u884C\u3002deploy-target.json \u9009\u62E9\u76EE\u6807\u3001\u9274\u6743\u548C\u76EE\u5F55\uFF0Cread-target.awk \u4F9B\u811A\u672C\u8BFB\u53D6\u914D\u7F6E\u3002deploy-local.sh \u5728\u670D\u52A1\u5668\u672C\u5730\u89E3\u5305\u5E76\u6267\u884C\u3002\n\u5F52\u6863\u5185 APPLY.txt \u662F\u624B\u5DE5\u64CD\u4F5C\u548C\u914D\u7F6E\u8BF4\u660E\u3002apply.sh \u6821\u9A8C\u3001\u52A0\u9501\u3001\u5BFC\u5165\u5E76\u542F\u52A8\u3002manifest.json \u8BB0\u5F55\u5236\u54C1\u3001\u6A21\u5F0F\u3001\u9009\u4E2D\u670D\u52A1\u53CA\u975E\u654F\u611F\u5143\u6570\u636E\u3002images/ \u662F OCI \u955C\u50CF\u5F52\u6863\uFF0C\u5BFC\u5165\u540E\u955C\u50CF\u7531\u5F15\u64CE\u4FDD\u5B58\u3002\n\u5F52\u6863\u5185 .hai/compose.json \u8BB0\u5F55\u6240\u9009\u670D\u52A1\uFF0C\u5B89\u88C5\u540E\u7684\u540C\u540D\u6587\u4EF6\u662F\u5408\u5E76\u540E\u7684\u5B8C\u6574\u670D\u52A1\u5FEB\u7167\u3002.hai/SHA256SUMS \u7528\u4E8E\u6821\u9A8C\u539F\u59CB\u89E3\u5305\u5185\u5BB9\u3002\u670D\u52A1\u5668\u526F\u672C\u4F1A\u5728\u5B9A\u7A3F\u548C\u5408\u5E76\u65F6\u6539\u53D8\u3002\n.hai/middleware-runtime.env \u53EA\u4F9B\u968F\u5305\u4E2D\u95F4\u4EF6\u7684 Compose env_file \u4F7F\u7528\u3002\u65E0\u539F\u751F\u73AF\u5883\u65F6\u53EF\u4EE5\u4E3A\u7A7A\u3002\u589E\u91CF\u4FDD\u7559\u7684\u670D\u52A1\u53EF\u80FD\u5F15\u7528\u66F4\u65E9\u7684 release\uFF0C\u4EE5\u6709\u6548 Compose \u7684 env_file \u4E3A\u51C6\u3002.hai/managed-candidates.env \u662F\u9996\u6B21\u5B89\u88C5\u5019\u9009\uFF0C\u7531 apply.sh \u6D88\u8D39\u3002\n.hai/runtime-env.mjs \u662F Node \u542F\u52A8\u52A0\u8F7D\u5668\u548C\u914D\u7F6E\u5B9A\u7A3F\u811A\u672C\u3002\u6309\u9700\u5305\u542B .hai/request-access.yml\u3001.hai/web.conf\u3001\u4EE3\u7406\u811A\u672C\u548C .hai/tls/ \u7B49\u8BBF\u95EE\u7B56\u7565\u3001\u53CD\u5411\u4EE3\u7406\u548C HTTPS \u8D44\u4EA7\u3002\n\u670D\u52A1\u5668 incoming/ \u4FDD\u5B58\u672C\u6B21\u4E0A\u4F20\u548C\u89E3\u5305\u5185\u5BB9\u3002releases/ \u4FDD\u5B58\u53D1\u5E03\u4E0E\u6062\u590D\u8BB0\u5F55\u3002managed-secrets.env\u3001persistent-backends \u548C\u6570\u636E\u5377\u6210\u5957\u4FDD\u62A4\u4E0E\u5907\u4EFD\uFF0C.deploy.lock \u4F9B\u90E8\u7F72\u548C\u51ED\u636E\u64CD\u4F5C\u534F\u8C03\u3002\ncurrent \u5728\u670D\u52A1\u5668\u5065\u5EB7\u68C0\u67E5\u901A\u8FC7\u540E\u66F4\u65B0\u3002result-{deploymentId}.json \u8BB0\u5F55\u7ED3\u679C\u548C\u6062\u590D\u72B6\u6001\uFF0Csteps-{deploymentId}.jsonl \u8BB0\u5F55\u6B65\u9AA4\uFF0Cdiagnostics-{deploymentId}.log \u5728\u542F\u52A8\u5931\u8D25\u65F6\u63D0\u4F9B\u79C1\u6709\u8BCA\u65AD\u3002\u6E05\u7406\u65E7 release \u524D\u6838\u5BF9\u5F53\u524D Compose\u3001\u6D3B\u52A8\u6302\u8F7D\u4E0E\u6062\u590D\u9700\u8981\u3002",
25432
25450
  deploy_downloadInvalid: "\u4E0B\u8F7D\u6E90\u6216\u4EE3\u7406\u914D\u7F6E\u65E0\u6548\uFF0C\u5730\u5740\u4E0D\u80FD\u5305\u542B\u8BA4\u8BC1\u4FE1\u606F\u6216\u67E5\u8BE2\u53C2\u6570\u3002",
25433
25451
  deploy_imageSourceMissing: "\u81EA\u5B9A\u4E49\u955C\u50CF\u6E90\u7F3A\u5C11\u4ED3\u5E93\u6620\u5C04\uFF1A{registry}",
25434
25452
  deploy_proxySystemUnsupported: "\u65E0\u6CD5\u8BFB\u53D6\u8BE5\u7CFB\u7EDF\u7684\u9759\u6001\u4EE3\u7406\uFF0C\u6216\u7CFB\u7EDF\u4EC5\u63D0\u4F9B PAC/\u81EA\u52A8\u53D1\u73B0\u3002\u8BF7\u4F7F\u7528 inherit \u73AF\u5883\u53D8\u91CF\u6216 custom HTTP(S) \u5730\u5740\u3002",
@@ -26947,7 +26965,7 @@ function buildProxyArguments(proxy, runtime, network) {
26947
26965
  }
26948
26966
  return Object.entries(environment).flatMap(([key, value]) => ["--build-arg", `${key}=${value}`]);
26949
26967
  }
26950
- async function preflightDownloadProxy(runtime, proxy) {
26968
+ async function preflightDownloadProxy(runtime, proxy, report = writeCliMessage) {
26951
26969
  const environment = resolveDownloadProxy(proxy);
26952
26970
  for (const value of new Set([environment.HTTP_PROXY, environment.HTTPS_PROXY].filter(Boolean))) {
26953
26971
  const url2 = new URL(value);
@@ -26971,12 +26989,12 @@ async function preflightDownloadProxy(runtime, proxy) {
26971
26989
  for (const candidate of runtime === "auto" ? ["podman", "docker"] : [runtime]) {
26972
26990
  try {
26973
26991
  const data = JSON.parse(execFileSync(candidate, ["info", "--format", "{{json .}}"], { encoding: "utf8", windowsHide: true, timeout: 5e3, stdio: ["ignore", "pipe", "ignore"] }));
26974
- 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 } }));
26992
+ report(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 } }));
26975
26993
  return;
26976
26994
  } catch {
26977
26995
  }
26978
26996
  }
26979
- writeCliMessage(cliM("cli_download_engine_proxy_hint", { params: { runtime } }));
26997
+ report(cliM("cli_download_engine_proxy_hint", { params: { runtime } }));
26980
26998
  }
26981
26999
  function validateDownloadDockerfile(file2, downloads) {
26982
27000
  const content = readFileSync(file2, "utf8");
@@ -27380,7 +27398,7 @@ async function forwardWindowsBuildOutput(source, destination) {
27380
27398
  }
27381
27399
 
27382
27400
  // src/commands/cli-build.ts
27383
- async function run(command, args, cwd, quiet = false, identity, compileEnvironment) {
27401
+ async function run(command, args, cwd, quiet = false, identity, compileEnvironment, progressOnStderr = false) {
27384
27402
  await new Promise((resolve16, reject) => {
27385
27403
  const env = Object.fromEntries(Object.entries(process14.env).filter(([key]) => !/^(?:HAI_|PUBLIC_|VITE_)/.test(key)));
27386
27404
  Object.assign(env, compileEnvironment);
@@ -27397,11 +27415,12 @@ async function run(command, args, cwd, quiet = false, identity, compileEnvironme
27397
27415
  if (env.CI === "1" || env.CI === "0")
27398
27416
  env.CI = env.CI === "1" ? "true" : "false";
27399
27417
  const windowsOutput = !quiet && process14.platform === "win32";
27400
- const child = spawn(command, args, { cwd, env, windowsHide: true, stdio: quiet ? "ignore" : windowsOutput ? ["inherit", "pipe", "pipe"] : "inherit", shell: false });
27418
+ const stdio = quiet ? "ignore" : windowsOutput ? ["inherit", "pipe", "pipe"] : progressOnStderr ? ["inherit", process14.stderr, "inherit"] : "inherit";
27419
+ const child = spawn(command, args, { cwd, env, windowsHide: true, stdio, shell: false });
27401
27420
  let output2 = Promise.resolve();
27402
27421
  if (windowsOutput && child.stdout && child.stderr) {
27403
27422
  output2 = Promise.all([
27404
- forwardWindowsBuildOutput(child.stdout, process14.stdout),
27423
+ forwardWindowsBuildOutput(child.stdout, progressOnStderr ? process14.stderr : process14.stdout),
27405
27424
  forwardWindowsBuildOutput(child.stderr, process14.stderr)
27406
27425
  ]).then(() => void 0);
27407
27426
  void output2.catch(() => child.kill());
@@ -27451,11 +27470,44 @@ function sourceCommit(cwd) {
27451
27470
  const options = { cwd, encoding: "utf8", stdio: "pipe", windowsHide: true };
27452
27471
  execFileSync("git", ["--literal-pathspecs", "ls-files", "--error-unmatch", "--", "package.json"], options);
27453
27472
  const commit = execFileSync("git", ["rev-parse", "HEAD"], options).trim();
27454
- return /^(?:[a-f\d]{40}|[a-f\d]{64})$/i.test(commit) ? commit : "unknown";
27473
+ return /^(?:[a-f\d]{40}|[a-f\d]{64})$/i.test(commit) ? commit.toLowerCase() : "unknown";
27455
27474
  } catch {
27456
27475
  return "unknown";
27457
27476
  }
27458
27477
  }
27478
+ function sourceDirty(cwd, commit) {
27479
+ if (commit === "unknown")
27480
+ return null;
27481
+ try {
27482
+ const status = execFileSync("git", ["--no-optional-locks", "-c", "core.fsmonitor=false", "status", "--porcelain=v2", "--branch", "--untracked-files=normal", "--", "."], {
27483
+ cwd,
27484
+ encoding: "utf8",
27485
+ stdio: "pipe",
27486
+ windowsHide: true,
27487
+ timeout: 15e3
27488
+ }).trim().split(/\r?\n/);
27489
+ if (status[0] !== `# branch.oid ${commit}`)
27490
+ return null;
27491
+ return status.some((line) => !line.startsWith("# "));
27492
+ } catch {
27493
+ return null;
27494
+ }
27495
+ }
27496
+ function imagePlatform(runtime, image, cwd) {
27497
+ try {
27498
+ const platform = execFileSync(runtime, ["image", "inspect", "--format", "{{.Os}}/{{.Architecture}}", image], {
27499
+ cwd,
27500
+ encoding: "utf8",
27501
+ stdio: "pipe",
27502
+ windowsHide: true,
27503
+ timeout: 15e3
27504
+ }).trim();
27505
+ if (/^[a-z0-9][a-z0-9_.-]*\/[a-z0-9][a-z0-9_.-]*$/.test(platform))
27506
+ return platform;
27507
+ } catch {
27508
+ }
27509
+ throw new Error(cliM("cli_build_image_platform_invalid"));
27510
+ }
27459
27511
  async function buildRuntime(cwd, choice) {
27460
27512
  const candidates = choice && choice !== "auto" ? [choice] : ["podman", "docker"];
27461
27513
  if (candidates.every((candidate) => candidate === "podman" || candidate === "docker")) {
@@ -27482,7 +27534,7 @@ async function buildCommand(options) {
27482
27534
  const containerAndroid = target === "app" && options.platform === "android" && options.runtime !== void 0;
27483
27535
  if (target === "app" && options.platform === "ios" && options.runtime !== void 0)
27484
27536
  throw new Error(cliM("cli_build_ios_runtime"));
27485
- if (target !== "image" && (options.images !== void 0 || options.concurrency !== void 0 || options.sqlitePrebuildMirror !== void 0) || target !== "image" && !containerAndroid && (options.runtime !== void 0 || options.network !== 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.debug !== void 0) || target !== "desktop" && options.arch !== void 0) {
27537
+ if (target !== "image" && (options.images !== void 0 || options.concurrency !== void 0 || options.sqlitePrebuildMirror !== void 0 || options.json) || target !== "image" && !containerAndroid && (options.runtime !== void 0 || options.network !== 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.debug !== void 0) || target !== "desktop" && options.arch !== void 0) {
27486
27538
  throw new Error(cliM("cli_build_options_invalid"));
27487
27539
  }
27488
27540
  if (target === "compile") {
@@ -27572,17 +27624,18 @@ async function buildCommand(options) {
27572
27624
  if (!existsSync(resolve(cwd, image.dockerfile)))
27573
27625
  throw new Error(cliM("cli_build_dockerfile_missing", { params: { path: image.dockerfile } }));
27574
27626
  }
27575
- const downloads = await resolveBuildDownloads(cwd, options);
27627
+ const { buildId, commit } = identity;
27628
+ const artifact = { version: 4, primaryService: config2.images.some((image) => image.name === "serv") ? "serv" : "web", appVersion, buildId, source: { commit, dirty: sourceDirty(cwd, commit) }, partial: images.length !== config2.images.length, hasWeb: config2.images.some((image) => image.name === "web"), images: [] };
27629
+ const downloads = await resolveBuildDownloads(cwd, options.json ? { ...options, yes: true } : options);
27576
27630
  for (const image of images) validateDownloadDockerfile(resolve(cwd, image.dockerfile), downloads);
27577
27631
  const runtime = await buildRuntime(cwd, options.runtime);
27578
- await preflightDownloadProxy(runtime, downloads.proxy);
27632
+ await preflightDownloadProxy(runtime, downloads.proxy, options.json ? (message) => process14.stderr.write(`${message}
27633
+ `) : void 0);
27579
27634
  if (options.sqlitePrebuildMirror) {
27580
27635
  const url2 = new URL(options.sqlitePrebuildMirror);
27581
27636
  if (!["http:", "https:"].includes(url2.protocol) || url2.username || url2.password || url2.search || url2.hash)
27582
27637
  throw new Error(cliM("cli_build_mirror_invalid"));
27583
27638
  }
27584
- const { buildId, commit } = identity;
27585
- const artifact = { version: 4, primaryService: config2.images.some((image) => image.name === "serv") ? "serv" : "web", appVersion, buildId, partial: images.length !== config2.images.length, hasWeb: config2.images.some((image) => image.name === "web"), images: [] };
27586
27639
  if (webBasePath) {
27587
27640
  artifact.version = 5;
27588
27641
  artifact.webBasePath = webBasePath;
@@ -27595,6 +27648,7 @@ async function buildCommand(options) {
27595
27648
  mkdirSync(parent, { recursive: true });
27596
27649
  const staging = mkdtempSync(join(parent, ".building-"));
27597
27650
  const built = [];
27651
+ const runImage = (args) => run(runtime, args, cwd, false, void 0, void 0, options.json);
27598
27652
  try {
27599
27653
  for (const context of new Set(images.map((image) => resolve(cwd, image.context ?? "."))))
27600
27654
  prepareDependencyInputs(context);
@@ -27634,13 +27688,14 @@ async function buildCommand(options) {
27634
27688
  if (image.name === "web" && compileEnvironment.PUBLIC_BASE_PATH)
27635
27689
  args.push("--build-arg", `PUBLIC_BASE_PATH=${compileEnvironment.PUBLIC_BASE_PATH}`);
27636
27690
  built.push(imageRef);
27637
- await run(runtime, [...args, context], cwd);
27691
+ await runImage([...args, context]);
27692
+ const platform = imagePlatform(runtime, imageRef, cwd);
27638
27693
  const file2 = `${image.name}-${appVersion}.tar`;
27639
- await run(runtime, ["save", ...runtime === "podman" ? ["--format", "docker-archive"] : [], "-o", join(staging, file2), imageRef], cwd);
27694
+ await runImage(["save", ...runtime === "podman" ? ["--format", "docker-archive"] : [], "-o", join(staging, file2), imageRef]);
27640
27695
  const hash2 = createHash("sha256");
27641
27696
  for await (const chunk of createReadStream(join(staging, file2)))
27642
27697
  hash2.update(chunk);
27643
- return { name: image.name, file: file2, imageRef, sha256: hash2.digest("hex"), ...image.containerPort ? { containerPort: image.containerPort } : {} };
27698
+ return { name: image.name, file: file2, imageRef, sha256: hash2.digest("hex"), platform, ...image.containerPort ? { containerPort: image.containerPort } : {} };
27644
27699
  };
27645
27700
  for (let offset = 0; offset < images.length; offset += concurrency) {
27646
27701
  const results = await Promise.allSettled(images.slice(offset, offset + concurrency).map(buildImage));
@@ -27658,7 +27713,12 @@ async function buildCommand(options) {
27658
27713
  writeFileSync(join(parent, `latest-${buildId}`), `${batch}
27659
27714
  `);
27660
27715
  renameSync(join(parent, `latest-${buildId}`), join(parent, "latest"));
27661
- writeCliMessage(cliM("cli_build_ready", { params: { path: output2, runtime } }));
27716
+ if (options.json) {
27717
+ process14.stdout.write(`${JSON.stringify({ schemaVersion: 1, artifactDir: output2, manifestPath: join(output2, "manifest.json"), manifest: artifact })}
27718
+ `);
27719
+ } else {
27720
+ writeCliMessage(cliM("cli_build_ready", { params: { path: output2, runtime } }));
27721
+ }
27662
27722
  } catch (error62) {
27663
27723
  for (const imageRef of built) {
27664
27724
  try {
@@ -29851,7 +29911,7 @@ async function initProject(options) {
29851
29911
  const { project, existing, missing } = result;
29852
29912
  spinner.succeed(cliM("cli_initDetected", { params: { name: chalk.cyan(project.name) } }));
29853
29913
  if (project.isHaiProject) {
29854
- const { generateProjectAiSupport, resolveSkillNamesForPackages } = await import('./cli-skill-templates-M64VPXZ4.js');
29914
+ const { generateProjectAiSupport, resolveSkillNamesForPackages } = await import('./cli-skill-templates-W4I6ZKYW.js');
29855
29915
  const generatedFiles = await generateProjectAiSupport(cwd, resolveSkillNamesForPackages(project.haiPackages), {
29856
29916
  overwriteSkills: false,
29857
29917
  overwriteBridgeFiles: false
@@ -30158,11 +30218,15 @@ cli.command("generate [type] [name]", cliM("cli_help_generate")).option("-w, --w
30158
30218
  process14.exit(1);
30159
30219
  }
30160
30220
  });
30161
- 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("--debug", cliM("cli_help_buildDebug")).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) => {
30221
+ cli.command("build", cliM("cli_help_build")).option("--target <target>", cliM("cli_help_target")).option("--json", cliM("cli_help_buildJson")).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("--debug", cliM("cli_help_buildDebug")).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) => {
30162
30222
  try {
30163
30223
  await buildCommand(options);
30164
30224
  } catch (error62) {
30165
- writeCliMessage(error62 instanceof Error ? error62.message : String(error62));
30225
+ const message = error62 instanceof Error ? error62.message : String(error62);
30226
+ if (options.json)
30227
+ writeCliError(message);
30228
+ else
30229
+ writeCliMessage(message);
30166
30230
  process14.exitCode = 1;
30167
30231
  }
30168
30232
  });