@h-ai/deploy 0.1.0-alpha.67 → 0.1.0-alpha.68
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 +28 -5
- package/README.ja.md +28 -5
- package/README.md +38 -15
- package/dist/index.d.ts +466 -61
- package/dist/index.js +930 -158
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/README.en.md
CHANGED
|
@@ -37,6 +37,10 @@ pnpm build --target desktop --platform windows --arch x64
|
|
|
37
37
|
|
|
38
38
|
Each image has its own Dockerfile. Web runtime assets live in images/web/. Dockerfiles retain internal build/runtime stages; configuration does not select stages. Omit absent images and add desktop directories only for native projects.
|
|
39
39
|
|
|
40
|
+
Generated `web.conf` sets `client_max_body_size 2129920` (2 MiB + 32 KiB) for the API location and disables `proxy_request_buffering` / `proxy_buffering`. This admits encrypted JSON produced from the transport's 1 MiB plaintext budget; the application still checks its smaller 16 KiB handshake, 4 KiB public key and 1 MiB plaintext budgets incrementally. Custom proxies must admit that ciphertext budget and propagate cancellation. Raising a proxy limit does not replace serv/kit's bounded reads; large uploads need an explicit separate route and size policy.
|
|
41
|
+
|
|
42
|
+
Bodyless authenticated envelopes use X-Hai-Transport. Generated proxies set large_client_header_buffers 4 32k and proxy_buffer_size 32k to admit these headers; custom proxies must preserve and admit them.
|
|
43
|
+
|
|
40
44
|
Dependency inputs are prepared under images/dependencies/ from package manifests, local archives and patches. Combine pnpm store caching with stable dependency layers. Source changes should reuse downloaded packages. Empty caches still permit online builds. Windows node_modules cannot supply Linux native dependencies. Offline builds additionally require base images, tools and matching ABI/architecture/libc binaries.
|
|
41
45
|
|
|
42
46
|
The root package.json.version identifies the application. `.hai/build/docker/<buildId>/` contains manifest format 3, selected image archives and SHA-256. partial marks incremental builds and hasWeb records topology. appContainerPort and webContainerPort retain explicitly configured app/web listening ports, including the image left out of a partial build. Omitted ports keep the deployment defaults. Rebuilding the same application version is allowed; unique build IDs/image references distinguish contents. Publish the local build pointer only after all exports succeed. Pin base images, middleware and tools; do not use latest.
|
|
@@ -56,7 +60,7 @@ container:
|
|
|
56
60
|
s3Engine: rustfs
|
|
57
61
|
```
|
|
58
62
|
|
|
59
|
-
|
|
63
|
+
For direct deployment, the wizard asks for missing server, SSH user, optional key/fingerprint files and public port settings using readable labels, and reuses complete settings. Local connection settings go to .env.local; private keys are referenced by path. `--bundle-only` skips SSH connection questions; fill in `deploy-target.json` before uploading later.
|
|
60
64
|
|
|
61
65
|
#### Configure only the middleware the application needs
|
|
62
66
|
|
|
@@ -64,7 +68,7 @@ Runtime lockfile dependencies and configuration determine middleware. Choose def
|
|
|
64
68
|
|
|
65
69
|
#### Deployment options
|
|
66
70
|
|
|
67
|
-
--env/--env-dir select configuration. --build builds selected application images before packaging. --services selects Compose services; --artifact-dir selects existing artifacts. --bundle-only creates a tar and platform scripts without SSH. --runtime selects the local build/export engine; --output
|
|
71
|
+
--env/--env-dir select configuration. --build builds selected application images before packaging. --services selects Compose services; --artifact-dir selects existing artifacts. --bundle-only creates a tar and platform scripts without SSH. --runtime selects the local build/export engine; --output overrides the archive path, resolved from the command's working directory, and adds the application version suffix. --yes uses valid settings without interaction and reports missing required values.
|
|
68
72
|
|
|
69
73
|
#### When the machines can connect: automatic deployment
|
|
70
74
|
|
|
@@ -83,16 +87,18 @@ Here `-d` starts in the background; `--no-deps` leaves dependencies untouched; `
|
|
|
83
87
|
#### When the machines cannot connect: copy a bundle
|
|
84
88
|
|
|
85
89
|
```sh
|
|
86
|
-
pnpm run deploy --env prod --build --bundle-only
|
|
90
|
+
pnpm run deploy --env prod --build --bundle-only
|
|
87
91
|
```
|
|
88
92
|
|
|
89
|
-
|
|
93
|
+
Deployment caches, archives and adjacent -deploy/ directories default to `.hai/deploy/<environment>/` at the same project root as `.hai/build/`. Archive names include the project, deployment ID and application version, such as `bundle-demo-<deploymentId>-1.2.3.tar`. An explicit `--output release-prod.tar` instead produces `release-prod-1.2.3.tar` and its adjacent operation directory relative to the command's working directory. The tar includes selected application/middleware images, configurations, private environment files, checksums, README and apply.sh. Before running either upload script, open `deploy-target.json` in the operation directory and use its per-field descriptions to edit and check the server, SSH user and port, private key and known-hosts files, remote directory and other settings. Run deploy.ps1 on Windows or deploy.sh on Linux/macOS; both scripts read this JSON to upload over SSH and execute the same server workflow. Running deploy.sh locally requires sh, awk, ssh and scp. Use `sh deploy.sh HOST [PORT] [USER]` to override the connection address, or pass `-IdentityFile` to deploy.ps1 to override its private key. Both scripts support HAI_DEPLOY_IDENTITY_FILE and HAI_DEPLOY_KNOWN_HOSTS_FILE to override key and known-hosts paths. After moving to another computer or operating system, update these paths to files on that computer.
|
|
90
94
|
|
|
91
95
|
On isolated Linux servers, extract into a separate package directory and run `sh apply.sh`, optionally passing the deployment root. Every failed step exits nonzero. Image loading, service startup and HTTP checks are distinct steps. result-<deploymentId>.json records the result; current changes only after successful checks. Reapplying the same deployment ID stops clearly; a newly generated bundle for the same application version is allowed. Failed updates attempt to restore selected containers and configuration while preserving data volumes and diagnostics. Data already written by the application is not rolled back.
|
|
92
96
|
|
|
97
|
+
The server holds a nonblocking kernel lock with util-linux `flock` on `.deploy.lock` in the deployment root, throughout deployment and recovery. Normal foreground deployment and synchronous failure recovery explicitly unlock after finalization and terminal-result publication, so background services do not block later deployments. Keep this file permanently: never delete, replace or steal it based on elapsed time, and use a filesystem that supports `flock`. On HUP/INT/TERM or a killed parent shell, active child commands retain the inherited lock until every holder exits or the server restarts. The old `.deploy-lock` directory is ignored and left untouched; stop old deployment processes before upgrading and avoid mixing old bundles. Forced termination or power loss skips recovery traps. Without a result file, execution is unknown: inspect containers, images and the successful `current` baseline before recovering with a new bundle. An unlocked file does not prove success or rolled-back effects.
|
|
98
|
+
|
|
93
99
|
#### Before going fully offline
|
|
94
100
|
|
|
95
|
-
Complete bundles include self-hosted middleware archives and matching architecture; server startup never pulls images. Linux needs Docker/Podman, Docker Compose v2 or podman-compose 1.6.0+ (supports --pull never), sh, tar, sha256sum, awk, curl and filesystem/container permissions. Protect private bundle contents. Keep volume identities stable across versions. Verify actual offline startup, login, refresh, restart and persistence. HTTPS, certificates, DNS and external services need separate preparation.
|
|
101
|
+
Complete bundles include self-hosted middleware archives and matching architecture; server startup never pulls images. Linux needs Docker/Podman, Docker Compose v2 or podman-compose 1.6.0+ (supports --pull never), sh, tar, sha256sum, awk, curl, util-linux flock and filesystem/container permissions. Protect private bundle contents. Keep volume identities stable across versions. Verify actual offline startup, login, refresh, restart and persistence. HTTPS, certificates, DNS and external services need separate preparation.
|
|
96
102
|
|
|
97
103
|
### SDK
|
|
98
104
|
|
|
@@ -121,6 +127,14 @@ finally {
|
|
|
121
127
|
|
|
122
128
|
`selectedServices: ['web']` selects a partial update. `onProgress` receives actual packaging/server stages. `deploy.scan` and `deploy.credentials.*` are available before init. Check HaiResult.success before using data. Vercel uploads existing .vercel/output through the prebuilt API and requires internet; it does not provide offline or Compose partial deployment.
|
|
123
129
|
|
|
130
|
+
Command execution redacts correctly decoded UTF-8 logical streams, including known secrets split across stdout/stderr chunks. Successful captures, errors and output callbacks use the same boundary. Internal command callers must enumerate sensitive literals in `secrets`, including separately encoded or transformed forms. Each stream captures only its last 1 Mi characters by default; `maxCaptureChars` accepts 1 through 16 Mi characters. Check `stdoutTruncated` / `stderrTruncated` before parsing structured output. Async `onOutput` callbacks receive all safe stdout in order with pipe backpressure; deployment progress parses only the first 512 characters of each line. Total secret length is limited to 1 Mi UTF-16 units; invalid redaction fails closed. A timeout reports failure; remote process termination still requires confirmation.
|
|
131
|
+
|
|
132
|
+
Command deadlines include helper startup and output handling. Timeouts, input/output errors and callback failures terminate managed processes. POSIX uses a separate process group. Windows uses an embedded PowerShell/.NET Job Object: create suspended, assign successfully, then resume, with no breakaway. Helper, compilation or assignment failure never falls back to an unmanaged process. System PowerShell and Add-Type are required on Windows; execution is hidden without user profiles, preserving arguments, environment and UTF-8 pipes. POSIX commands must keep descendants in the inherited group; detached system daemons and remote services are outside local termination confirmation.
|
|
133
|
+
|
|
134
|
+
`terminationTimeoutMs` separately bounds failure cleanup verification, default 10000 and maximum 60000 milliseconds. Sending kill is not confirmation. `localTermination` is `confirmed` only after the managed Job/group has no active members, `unknown` if verification fails or expires, and `not-started` before launch. In the `if (!result.success)` branch, call public `getDeployCommandState(result.error)` for the reason and state, without raw exceptions or command arguments. An output callback already entered cannot be undone; failures stop further output delivery.
|
|
135
|
+
|
|
136
|
+
SSH interruptions initially report `remoteExecution: 'unknown'`. The docker-ssh SDK reconnects read-only to inspect `result-<deploymentId>.json`. Only a complete, untruncated terminal record with the matching ID confirms `finished`, with the actual stage and exit code. Finished scripts do not imply stopped containers. Even exit code 0 preserves the original SSH/output failure. CLI shows local and remote states separately with the result path. Missing, stale, damaged or unreadable records remain unknown; deployment and rollback are never retried automatically. Manual upload scripts conservatively report unknown on SSH failure with the inspection directory; find the deployment ID in the bundle manifest. Inspect steps, `current`, actual services and data before recovery.
|
|
137
|
+
|
|
124
138
|
## Development and testing
|
|
125
139
|
|
|
126
140
|
```sh
|
|
@@ -128,12 +142,21 @@ pnpm --filter @h-ai/deploy typecheck
|
|
|
128
142
|
pnpm --filter @h-ai/deploy lint
|
|
129
143
|
pnpm --filter @h-ai/deploy build
|
|
130
144
|
pnpm --filter @h-ai/deploy test
|
|
145
|
+
pnpm --filter @h-ai/deploy test:e2e
|
|
131
146
|
pnpm --filter @h-ai/cli test:scaffold-gates
|
|
132
147
|
pnpm --filter @h-ai/cli test:deploy-gates
|
|
133
148
|
```
|
|
134
149
|
|
|
150
|
+
Real deployment selects API, SSR, static mobile and fullstack representatives. Admin covers the SSR Dockerfile and production deployment branch shared by website/h5; all application types retain their own installation, compilation and HTTP/browser acceptance in the eight scaffold scenarios. Measured resource contention keeps scaffold and generated-route runtime in sequential batches; three smaller CLI gates can share the runtime batch with at most two file workers. Generated scenarios reuse the complete E2E build while preserving production build isolation and actual output checks. CLI deployment gates preserve authentication/transport, incremental updates, damaged artifacts and rollback, and run the production Nginx version against a public deployment bundle with `nginx -t`. Fixtures enable init and verify that adopted orphan PIDs actually disappear.
|
|
151
|
+
|
|
135
152
|
Run actual generated projects and SSH/manual deployment, including an isolated registry environment, incremental updates, damaged archives, same-version releases and failed health checks. Clean only test-owned projects, images, containers, logs and processes in finally/teardown.
|
|
136
153
|
|
|
154
|
+
`test:e2e` builds the current package and enables both Linux lock and process gates in a child process, running the files serially. Root `pnpm e2e` includes this entry. The gates require reachable Podman (preferred) or Docker to run the public API's generated `apply.sh`: concurrent execution, child-held locks after killing the parent, full termination and restart recovery. Compose/HTTP use deterministic fixtures; this does not replace real service deployment acceptance.
|
|
155
|
+
|
|
156
|
+
Process gates run with `pnpm --filter @h-ai/deploy exec vitest run tests/deploy-command-process.test.ts tests/deploy-secret-masker.test.ts`. With the same `HAI_DEPLOY_E2E=1`, build deploy first and run `tests/deploy-command-runtime.e2e.test.ts` for real Linux/OpenSSH, published dist, remote continuation/completion and local process groups. The fixture needs network access to install sshd; Compose/HTTP are deterministic fixtures. It scales deployment deadlines to 2500 milliseconds and pauses output consumption to inject lost acknowledgments.
|
|
157
|
+
|
|
158
|
+
Deployment fixtures inspect pinned public base images and pull only confirmed missing images; HAI_DEPLOY_E2E_MIRROR remains available. Public image caches are never cleanup targets. A successful create records its container ID before asynchronous APT/pip/sshd preparation inside a private PID namespace. Preparation errors, deadlines and cooperative cancellation wait for the local client to close, then remove and verify that exact owned ID; only the nested Podman fixture is privileged. HAI_DEPLOY_E2E_APT_MIRROR accepts a mirror hostname and keeps HTTPS. Ownership tests use run-specific private tags of pinned public images while preserving foreign same-content tags, retag protection, dynamic ports and external sentinels. A lost create acknowledgment without a trusted ID, or a forcibly terminated test process, remains unknown and never authorizes adoption by name or label.
|
|
159
|
+
|
|
137
160
|
## License
|
|
138
161
|
|
|
139
162
|
Apache-2.0
|
package/README.ja.md
CHANGED
|
@@ -37,6 +37,10 @@ pnpm build --target desktop --platform windows --arch x64
|
|
|
37
37
|
|
|
38
38
|
各イメージに独立した Dockerfile を用意します。Web 用設定は images/web/ に置きます。Dockerfile 内の構築・実行段階は維持しますが、設定から段階を選びません。不要なイメージ項目は削除し、desktop ディレクトリは対象プロジェクトのみ設定します。
|
|
39
39
|
|
|
40
|
+
生成する `web.conf` は API location に `client_max_body_size 2129920`(2 MiB + 32 KiB)を設定し、`proxy_request_buffering` / `proxy_buffering` を無効にします。transport の平文 1 MiB を暗号化した JSON を通過させ、アプリ側では鍵交換 16 KiB、公開鍵 4 KiB、平文 1 MiB の制限を逐次検証します。独自プロキシでも暗号文の上限を許可し、キャンセルを伝播してください。プロキシ上限の変更だけでは serv/kit の有界読み取りを代替できません。大容量アップロードは専用パスと容量ポリシーを用意します。
|
|
41
|
+
|
|
42
|
+
本文なし認証封装には X-Hai-Transport を使います。生成設定は large_client_header_buffers 4 32k と proxy_buffer_size 32k を指定します。独自プロキシもこのヘッダーを保持し、通過させてください。
|
|
43
|
+
|
|
40
44
|
構築器はパッケージ情報、ローカルアーカイブとパッチを images/dependencies/ に準備し、pnpm store と依存レイヤーをキャッシュします。通常のソース変更で全依存を再ダウンロードしない構成です。キャッシュが空でもオンライン構築できます。Windows の node_modules は Linux のネイティブ依存を代替できません。完全オフライン構築には基底イメージ、ツールと一致する ABI・アーキテクチャ・libc のバイナリも準備します。
|
|
41
45
|
|
|
42
46
|
アプリの版はルート package.json.version で管理します。`.hai/build/docker/<buildId>/` に形式 3 の manifest.json、選択イメージの tar と SHA-256 を出力します。partial は部分構築、hasWeb は構成を記録します。appContainerPort と webContainerPort は明示した app/web の待受ポートを保持し、部分構築で選ばなかったイメージのポートも失いません。未指定のポートにはデプロイ時の既定値を使います。同じアプリ版でも再構築可能で、構築 ID とイメージ参照で内容を区別します。全出力に成功してからローカルの構築参照を更新します。基底・ミドルウェア・ツールは版を固定し、latest を使いません。
|
|
@@ -56,7 +60,7 @@ container:
|
|
|
56
60
|
s3Engine: rustfs
|
|
57
61
|
```
|
|
58
62
|
|
|
59
|
-
|
|
63
|
+
直接デプロイでは、サーバー、SSH ユーザー、任意の鍵・指紋ファイル、公開ポートの不足項目を説明付きで質問し、完全な設定は再利用します。接続情報は .env.local、秘密鍵はパスのみ保存します。`--bundle-only` では SSH 接続情報を質問せず、後でアップロードする前に `deploy-target.json` に設定します。
|
|
60
64
|
|
|
61
65
|
#### 本当に必要なミドルウェアだけを設定する
|
|
62
66
|
|
|
@@ -64,7 +68,7 @@ container:
|
|
|
64
68
|
|
|
65
69
|
#### deploy のオプション
|
|
66
70
|
|
|
67
|
-
--env/--env-dir は環境、--build は先行する選択イメージ構築、--services は更新対象、--artifact-dir は既存成果物を指定します。--bundle-only は SSH 接続なしで tar と OS 別スクリプトを生成します。--runtime
|
|
71
|
+
--env/--env-dir は環境、--build は先行する選択イメージ構築、--services は更新対象、--artifact-dir は既存成果物を指定します。--bundle-only は SSH 接続なしで tar と OS 別スクリプトを生成します。--runtime はローカル構築・イメージ出力エンジンです。--output はコマンドの作業ディレクトリを基準とする出力先を指定し、アプリ版を末尾に付けます。--yes は有効な設定を非対話で使い、不足値はエラーで示します。一体化構築でも --network、--no-http-proxy、--sqlite-prebuild-mirror を指定できます。
|
|
68
72
|
|
|
69
73
|
#### マシン同士が接続できる場合:自動デプロイ
|
|
70
74
|
|
|
@@ -83,16 +87,18 @@ pnpm run deploy --env prod --build --services web
|
|
|
83
87
|
#### マシン同士が接続できない場合:パッケージをコピー
|
|
84
88
|
|
|
85
89
|
```sh
|
|
86
|
-
pnpm run deploy --env prod --build --bundle-only
|
|
90
|
+
pnpm run deploy --env prod --build --bundle-only
|
|
87
91
|
```
|
|
88
92
|
|
|
89
|
-
|
|
93
|
+
既定では `.hai/build/` と同じプロジェクトルートの `.hai/deploy/<環境>/` にデプロイキャッシュ、tar と隣接する -deploy/ 操作ディレクトリを生成します。アーカイブ名はプロジェクト名、配置 ID、アプリ版を含み、例は `bundle-demo-<配置ID>-1.2.3.tar` です。`--output release-prod.tar` を明示すると、コマンドの作業ディレクトリを基準に release-prod-1.2.3.tar と操作ディレクトリを生成します。tar は選択アプリ・ミドルウェアのイメージ、設定、秘密の環境ファイル、チェックサム、README、apply.sh を含みます。アップロードスクリプトの実行前に、操作ディレクトリの `deploy-target.json` を開き、各項目の説明に従ってサーバー、SSH ユーザーとポート、秘密鍵・指紋ファイル、リモートディレクトリなどを変更・確認します。Windows は deploy.ps1、Linux/macOS は deploy.sh を実行します。どちらも同じ JSON を読み、SSH 転送後に同じサーバー処理を実行します。ローカルで deploy.sh を実行するには sh、awk、ssh、scp が必要です。`sh deploy.sh ホスト [ポート] [ユーザー]` で接続先を、deploy.ps1 の `-IdentityFile` で秘密鍵を上書きできます。両方のスクリプトで HAI_DEPLOY_IDENTITY_FILE と HAI_DEPLOY_KNOWN_HOSTS_FILE による鍵・指紋ファイルのパスの上書きも可能です。別の PC・OS に移す場合、これらのパスを移動先の実ファイルに合わせます。
|
|
90
94
|
|
|
91
95
|
隔離された Linux では独立ディレクトリに展開し、`sh apply.sh` を実行します。引数で配置先を上書きできます。各段階の失敗は非ゼロ終了し、イメージ導入・起動・HTTP 検査を別々に報告します。result-<配置ID>.json に結果を記録し、成功時だけ current を更新します。同じ配置 ID の再適用は停止しますが、同じアプリ版から生成した新しい配布物は適用できます。更新失敗時は対象コンテナーと設定を以前の状態に戻すことを試み、データボリュームと診断情報を保持します。すでに書き込まれた業務データは元に戻しません。
|
|
92
96
|
|
|
97
|
+
サーバーは util-linux の `flock` で配置ルートの `.deploy.lock` に非ブロッキングのカーネルロックを取得し、復元処理の終了まで保持します。通常の前景配置と同期の失敗復元は、後処理と終端結果の公開後に明示解放し、背景サービスの稼働は次の配置を妨げません。このファイルは残し、削除・置換・経過時間による横取りをしないでください。対応するファイルシステムが必要です。HUP/INT/TERM または親 shell の強制終了時は、記述子を継承した実行中の子コマンドが全 holder の終了かサーバー再起動までロックを保持します。旧 `.deploy-lock` ディレクトリは判定に使わず削除もしません。更新前に旧配置プロセスを終了し、旧パッケージを併用しないでください。強制終了・停電では復元 trap が動きません。結果ファイルがなければ実行状態は不明です。コンテナー、イメージ、成功した `current` を確認して新しいパッケージで復旧してください。ロック解放は成功や副作用の取消を意味しません。
|
|
98
|
+
|
|
93
99
|
#### 完全オフラインの前に確認する
|
|
94
100
|
|
|
95
|
-
完全 tar は自前ミドルウェアのアーカイブと一致するアーキテクチャを含み、起動時にレジストリーへ接続しません。Linux に Docker/Podman、Docker Compose v2 または podman-compose 1.6.0 以降、sh、tar、sha256sum、awk、curl、ディレクトリ・コンテナー権限が必要です。秘密設定を安全に転送し、版間でボリューム識別を保持します。外部ネットワークを切って起動、ログイン、再読込、再起動と永続化を検証します。HTTPS、証明書、DNS、外部サービスは別途用意します。
|
|
101
|
+
完全 tar は自前ミドルウェアのアーカイブと一致するアーキテクチャを含み、起動時にレジストリーへ接続しません。Linux に Docker/Podman、Docker Compose v2 または podman-compose 1.6.0 以降、sh、tar、sha256sum、awk、curl、util-linux の flock、ディレクトリ・コンテナー権限が必要です。秘密設定を安全に転送し、版間でボリューム識別を保持します。外部ネットワークを切って起動、ログイン、再読込、再起動と永続化を検証します。HTTPS、証明書、DNS、外部サービスは別途用意します。
|
|
96
102
|
|
|
97
103
|
### SDK
|
|
98
104
|
|
|
@@ -121,6 +127,14 @@ finally {
|
|
|
121
127
|
|
|
122
128
|
`selectedServices: ['web']` は部分更新を選択し、`onProgress` はパッケージ作成とサーバー実行の段階を通知します。`deploy.scan` と `deploy.credentials.*` は初期化前も使用できます。HaiResult.success を確認してからデータを読み取ります。Vercel は既存 .vercel/output を prebuilt API でアップロードするためネット接続が必要で、オフラインや Compose の部分公開には対応しません。
|
|
123
129
|
|
|
130
|
+
コマンド出力は正しく UTF-8 デコードした論理ストリーム単位で秘匿し、stdout/stderr のチャンク境界をまたぐ既知の秘密も保護します。成功結果、エラー、出力コールバックは同じ境界を使います。内部コマンドの `secrets` に機密リテラルを指定し、変換・エンコードした値も別途指定してください。各ストリームは既定で末尾 1 Mi 文字を保持し、`maxCaptureChars` は 1~16 Mi 文字です。構造化出力の解析前に `stdoutTruncated` / `stderrTruncated` を確認します。非同期 `onOutput` を順に待ち pipe の背圧を保ち、安全な stdout 全体を渡します。進捗解析は各行の先頭 512 文字のみです。秘密の合計上限は UTF-16 で 1 Mi 単位、秘匿失敗は処理失敗とします。タイムアウトだけでリモートプロセスの終了を断定せず、終了を確認してください。
|
|
131
|
+
|
|
132
|
+
コマンド期限は helper 起動と出力処理を含みます。タイムアウト、入出力・コールバック失敗時は管理対象プロセスを終了します。POSIX は独立したプロセスグループ、Windows は内嵌 PowerShell/.NET Job Object を使い、停止状態で作成して割当成功後だけ再開します。breakaway は許可せず、helper・コンパイル・割当失敗時に裸のプロセスへ切り替えません。Windows はシステム PowerShell と Add-Type が必要です。非表示で profile を読み込まず、引数・環境・UTF-8 pipe を保持します。POSIX の子孫は同じグループを継承してください。独立したシステム daemon と遠隔サービスはローカル終了確認の対象外です。
|
|
133
|
+
|
|
134
|
+
失敗後の確認待ちは `terminationTimeoutMs`(既定 10000、最大 60000 ミリ秒)です。kill 送信だけでは確認とせず、管理対象 Job/グループの活動メンバーがなくなった場合だけ `localTermination: 'confirmed'`、確認失敗・期限切れは `unknown`、起動前は `not-started` を記録します。`if (!result.success)` 内で公開 `getDeployCommandState(result.error)` を使い、原始例外やコマンド引数を含まない状態を読みます。実行中の非同期出力 callback は取り消せませんが、失敗後に新しい出力を渡しません。
|
|
135
|
+
|
|
136
|
+
SSH 中断は最初に `remoteExecution: 'unknown'` とし、docker-ssh SDK は別接続で `result-<deploymentId>.json` を読みます。完全で未切断、ID が一致する終端結果だけ `finished` と実際の段階・終了値を確認できます。script 終了はコンテナー停止を意味しません。終了値が 0 でも元の SSH/出力失敗は失敗として残します。CLI はローカルと遠隔の状態と結果パスを別々に表示します。欠落・旧 ID・破損・再接続失敗は不明のまま、配置や rollback を自動再実行しません。手動アップロード script は SSH 失敗を不明と表示し、確認先を示します。配置 ID はパッケージの manifest で確認します。手順、`current`、実サービスとデータを確認して復旧してください。
|
|
137
|
+
|
|
124
138
|
## 開発とテスト
|
|
125
139
|
|
|
126
140
|
```sh
|
|
@@ -128,12 +142,21 @@ pnpm --filter @h-ai/deploy typecheck
|
|
|
128
142
|
pnpm --filter @h-ai/deploy lint
|
|
129
143
|
pnpm --filter @h-ai/deploy build
|
|
130
144
|
pnpm --filter @h-ai/deploy test
|
|
145
|
+
pnpm --filter @h-ai/deploy test:e2e
|
|
131
146
|
pnpm --filter @h-ai/cli test:scaffold-gates
|
|
132
147
|
pnpm --filter @h-ai/cli test:deploy-gates
|
|
133
148
|
```
|
|
134
149
|
|
|
150
|
+
実配置は API、SSR、静的モバイル、fullstack を代表として選びます。admin は website/h5 と共通の SSR Dockerfile と本番配置分岐を検証し、全アプリ種別の個別インストール、コンパイル、HTTP/ブラウザー検証は八つの scaffold シナリオで維持します。実測の資源競合に基づき scaffold と生成ルート runtime は逐次バッチとし、三つの軽い CLI ゲートは runtime と最大二つの worker で並列実行できます。生成シナリオは E2E の完全構築を再利用し、本番構築分離と実成果物の検証を維持します。CLI 配置ゲートは認証/暗号化、増分更新、破損成果物と復旧を維持し、本番と同じ Nginx で公開 bundle に `nginx -t` を実行します。fixture は init を有効化し、引き取った孤児 PID の実消失を検証します。
|
|
151
|
+
|
|
135
152
|
実際の生成プロジェクト、SSH と手動公開を検証します。レジストリー接続禁止、部分更新、破損アーカイブ、同一版での再公開、ヘルスチェック失敗を含めます。finally/teardown ではテスト自身が作成したプロジェクト、イメージ、コンテナー、ログ、プロセスのみを削除します。
|
|
136
153
|
|
|
154
|
+
`test:e2e` は現在のパッケージをビルドし、子プロセスで Linux のロックとプロセスの両ゲートを有効にしてファイルを順番に実行します。ルートの `pnpm e2e` もこの入口を含みます。接続可能な Podman(優先)または Docker を使い、公開 API が生成した `apply.sh` を実行します。同時実行、親の強制終了後の子によるロック保持、全終了と再起動からの復旧を確認します。Compose/HTTP は決定的なテスト用実装で、実サービス公開の検証を代替しません。
|
|
155
|
+
|
|
156
|
+
プロセス専用ゲートは `pnpm --filter @h-ai/deploy exec vitest run tests/deploy-command-process.test.ts tests/deploy-secret-masker.test.ts` です。同じ `HAI_DEPLOY_E2E=1` を設定し、deploy をビルドしてから `tests/deploy-command-runtime.e2e.test.ts` を実行すると、実 Linux/OpenSSH、公開 dist、遠隔の継続・完了、ローカルグループを検証します。sshd 導入にネットワークが必要で、Compose/HTTP はテスト用実装です。配置期限を 2500 ミリ秒に短縮し、出力消費を停止して応答喪失を再現します。
|
|
157
|
+
|
|
158
|
+
デプロイ用 fixture は固定版の公開基盤イメージを確認し、不在を確認した場合だけ取得します。HAI_DEPLOY_E2E_MIRROR を利用でき、公開キャッシュは回収対象にしません。create 成功時のコンテナー ID を先に記録し、専用 PID namespace 内で APT/pip/sshd を非同期準備します。準備失敗、期限超過、協調的取消ではローカルクライアントの終了を待ち、記録した ID だけを削除して消失を確認します。特権を使うのはネストした Podman fixture のみです。HAI_DEPLOY_E2E_APT_MIRROR はホスト名のみを受け付け、HTTPS を維持します。所有権テストは固定公開イメージに実行専用 tag を付け、同じ内容の外部 tag、tag の付け替え、動的ポート、外部 sentinel の保護を維持します。create の応答喪失で信頼できる ID がない場合や、テストが強制終了した場合は不明状態を残し、名前や label を根拠に回収しません。
|
|
159
|
+
|
|
137
160
|
## ライセンス
|
|
138
161
|
|
|
139
162
|
Apache-2.0
|
package/README.md
CHANGED
|
@@ -53,6 +53,10 @@ pnpm build --target desktop --platform windows --arch x64
|
|
|
53
53
|
|
|
54
54
|
每个镜像独立 Dockerfile;web 的 Nginx 配置与启动资源放 `images/web/`。Dockerfile 内保留编译/运行阶段,配置不再选择阶段。没有 Web 或 desktop 时删除相应项。
|
|
55
55
|
|
|
56
|
+
部署生成的 `web.conf` 在 API location 设置 `client_max_body_size 2129920`(2 MiB + 32 KiB),并关闭 `proxy_request_buffering` / `proxy_buffering`。这允许 transport 的 1 MiB 明文经编码形成密文后通过,应用仍逐块执行更细的握手 JSON 16 KiB、公钥 4 KiB、明文 1 MiB 预算。自有反向代理须允许该密文预算并传递取消,不能用增大代理上限代替 serv/kit 的有界读取;大文件上传走明确的独立路径和体积策略。
|
|
57
|
+
|
|
58
|
+
无正文认证封装通过 X-Hai-Transport 头传输,生成配置使用 large_client_header_buffers 4 32k 与 proxy_buffer_size 32k 容纳头字段;自有代理也须允许并保留该头。
|
|
59
|
+
|
|
56
60
|
构建器将锁文件、包配置、本地归档和补丁准备为 `images/dependencies/` 输入,结合 pnpm store 缓存与 Docker 分层复用下载。源码修改不应重新下载全部依赖;缓存为空仍能联网构建。Windows node_modules 不用于 Linux 镜像。完全离线构建还需预先准备基础镜像、工具链和匹配 ABI/架构/libc 的原生预编译包。
|
|
57
61
|
|
|
58
62
|
版本来自应用根 package.json.version。制品位于 `.hai/build/docker/<buildId>/`,包括格式版本 3 的 manifest.json、所选镜像 tar 和 SHA-256;partial 标识部分构建,hasWeb 保留工程拓扑。清单还会记住配置中填写的 app/web 容器端口(appContainerPort、webContainerPort),只打包一个镜像也不会丢掉另一个的端口;没填写则沿用部署默认值。相同应用版本允许重建,构建编号和镜像引用区分实际内容;全部导出成功才更新本机构建入口。基础镜像、中间件及工具使用明确版本,不使用 latest。
|
|
@@ -72,7 +76,7 @@ container:
|
|
|
72
76
|
s3Engine: rustfs
|
|
73
77
|
```
|
|
74
78
|
|
|
75
|
-
|
|
79
|
+
直接部署时,向导按“服务器地址、SSH 登录用户、私钥文件、访问端口”等说明补齐缺少的配置,并复用已有完整配置。SSH 参数仅写本机 `.env.local`;私钥只保存路径。`--bundle-only` 不询问 SSH 连接信息,后续上传前在 `deploy-target.json` 中填写。
|
|
76
80
|
|
|
77
81
|
#### 按应用真正需要的中间件处理
|
|
78
82
|
|
|
@@ -80,17 +84,17 @@ container:
|
|
|
80
84
|
|
|
81
85
|
#### deploy 的可选参数
|
|
82
86
|
|
|
83
|
-
| 参数 | 用途
|
|
84
|
-
| --------------------- |
|
|
85
|
-
| `--env` / `--env-dir` | 环境和环境文件目录
|
|
86
|
-
| `--build` | 先构建选中应用镜像,再打包部署;可结合 bundle-only
|
|
87
|
-
| `--services` | 只更新指定 Compose 服务,例如 web、app、app,web、storage
|
|
88
|
-
| `--artifact-dir` | 精确选择已构建制品
|
|
89
|
-
| `--bundle-only` | 只生成 tar 和跨平台脚本,不连接服务器
|
|
90
|
-
| `--runtime` | 本地构建及中间件镜像导出引擎
|
|
91
|
-
| `--output` |
|
|
92
|
-
| `--skip-middleware` | 跳过中间件配置与开通
|
|
93
|
-
| `--yes` | 无交互使用有效配置;缺必要值明确报错
|
|
87
|
+
| 参数 | 用途 |
|
|
88
|
+
| --------------------- | --------------------------------------------------------- |
|
|
89
|
+
| `--env` / `--env-dir` | 环境和环境文件目录 |
|
|
90
|
+
| `--build` | 先构建选中应用镜像,再打包部署;可结合 bundle-only |
|
|
91
|
+
| `--services` | 只更新指定 Compose 服务,例如 web、app、app,web、storage |
|
|
92
|
+
| `--artifact-dir` | 精确选择已构建制品 |
|
|
93
|
+
| `--bundle-only` | 只生成 tar 和跨平台脚本,不连接服务器 |
|
|
94
|
+
| `--runtime` | 本地构建及中间件镜像导出引擎 |
|
|
95
|
+
| `--output` | 自定义部署 tar 路径,相对命令执行目录解析,自动补版本后缀 |
|
|
96
|
+
| `--skip-middleware` | 跳过中间件配置与开通 |
|
|
97
|
+
| `--yes` | 无交互使用有效配置;缺必要值明确报错 |
|
|
94
98
|
|
|
95
99
|
#### 两机连通:直接部署
|
|
96
100
|
|
|
@@ -109,17 +113,19 @@ pnpm run deploy --env prod --build --services web
|
|
|
109
113
|
#### 两机不通:生成包,手工复制
|
|
110
114
|
|
|
111
115
|
```sh
|
|
112
|
-
pnpm run deploy --env prod --build --bundle-only
|
|
116
|
+
pnpm run deploy --env prod --build --bundle-only
|
|
113
117
|
```
|
|
114
118
|
|
|
115
|
-
|
|
119
|
+
默认将部署缓存、tar 和同名 `-deploy/` 操作目录放到工程根 `.hai/deploy/<环境>/`,与 `.hai/build/` 使用同一工程根。归档名包含项目名、部署 ID 和应用版本,例如 `bundle-demo-<部署ID>-1.2.3.tar`。显式传入 `--output release-prod.tar` 时,按命令执行目录输出 `release-prod-1.2.3.tar` 和相邻操作目录。包包含所选应用/中间件镜像、服务配置、私有环境、校验和、README 和 apply.sh。运行上传脚本前,先打开操作目录的 `deploy-target.json`,按其中逐项说明修改并核对服务器、SSH 用户和端口、私钥及指纹文件、远程目录等配置。Windows 运行 deploy.ps1,Linux/macOS 运行 deploy.sh;两个脚本均读取该 JSON,通过 SSH 上传后执行同一服务器流程。本机运行 deploy.sh 需 sh、awk、ssh、scp;可用 `sh deploy.sh 主机 [端口] [用户]` 覆盖连接地址,或给 deploy.ps1 传入 `-IdentityFile` 覆盖私钥。两个脚本均支持用 HAI_DEPLOY_IDENTITY_FILE、HAI_DEPLOY_KNOWN_HOSTS_FILE 覆盖私钥及指纹文件路径。换电脑或操作系统后,这些路径必须指向当前电脑上的实际文件。
|
|
116
120
|
|
|
117
121
|
完全隔离的 Linux 服务器上,将 tar 解到独立目录,运行 `sh apply.sh`,也可传入部署根目录覆盖默认值。每步检查结果,任何失败返回非零退出码;镜像导入、服务启动和 HTTP 检查分别报告。结果写到服务器部署目录 `result-<部署ID>.json`,只有检查通过才更新 current 成功状态。重复应用同一部署包会明确停止;相同版本重新生成的新包允许发布。已有版本失败时尝试恢复选中的旧容器和配置,保留数据卷及诊断材料;不会回退已写入的业务数据。
|
|
118
122
|
|
|
123
|
+
服务器使用 util-linux `flock` 对部署根目录的 `.deploy.lock` 持有非阻塞内核锁,覆盖部署和失败恢复。正常前台部署及同步失败恢复收尾、发布终态后显式解锁,后台服务继续运行不阻塞后续部署。锁文件永久保留,禁止删除、替换或按经过时间抢锁;目录所在文件系统须支持 `flock`。HUP/INT/TERM 中断或父 shell 被强杀后,继承文件描述符的活跃子命令继续持锁,所有 holder 退出或服务器重启后才释放。旧 `.deploy-lock` 目录不再参与判锁,也不自动删除;升级前须结束旧版部署进程,勿混用旧包。强杀/断电不会运行恢复 trap,缺少结果文件时执行状态未知:先核对容器、镜像和 `current` 成功基线,再用新部署包恢复,不能把锁释放视为部署成功或副作用已回滚。
|
|
124
|
+
|
|
119
125
|
#### 完全离线前再核对一次
|
|
120
126
|
|
|
121
127
|
- 完整 tar 已含自建中间件归档,镜像架构与服务器一致;服务器启动不访问 registry。
|
|
122
|
-
- Linux 已安装 Docker/Podman、可执行的 Compose、sh、tar、sha256sum、awk、curl;用户有目录与容器权限。
|
|
128
|
+
- Linux 已安装 Docker/Podman、可执行的 Compose、sh、tar、sha256sum、awk、curl、util-linux 的 flock;用户有目录与容器权限。
|
|
123
129
|
- 包含私有配置,安全搬运,不提交 Git;持久化卷身份跨版本稳定。
|
|
124
130
|
- 实际断外网验证启动、登录、页面刷新、重启与数据持久化。生产 HTTPS、证书、DNS 和外部服务需另行准备。
|
|
125
131
|
|
|
@@ -150,6 +156,14 @@ finally {
|
|
|
150
156
|
|
|
151
157
|
`selectedServices: ['web']` 选择局部更新,`onProgress` 返回打包与服务器执行阶段。`deploy.scan` 和 `deploy.credentials.*` 可在初始化前使用。先判断 HaiResult.success 再读取数据。Vercel 使用 prebuilt API 上传已有 .vercel/output,需要网络,不提供离线交付或 Compose 局部发布。
|
|
152
158
|
|
|
159
|
+
命令执行按正确解码的 UTF-8 逻辑流脱敏,已知秘密即使跨 stdout/stderr 数据块也不会原样释放;成功捕获结果、错误与进度回调遵循同一边界。调用内部命令工具时用 `secrets` 明确列出敏感字面量;编码、截取或转换后的值须单独列入。每条流默认仅捕获最后 1 Mi 字符,`maxCaptureChars` 可设 1~16 Mi 字符,结果用 `stdoutTruncated` / `stderrTruncated` 标记截断,解析结构化输出前必须检查。`onOutput` 可异步,按序等待并保留 pipe 背压,收到的是全部安全 stdout;部署进度仅解析每行前 512 字符。秘密总长度最多 1 Mi UTF-16 单元,超限或脱敏异常失败关闭;超时表示命令执行失败,远程进程终止仍需确认。
|
|
160
|
+
|
|
161
|
+
命令 deadline 包含 helper 启动和输出处理;超时、输入/输出或回调异常会终止受管理进程。POSIX 使用独立进程组,Windows 通过内嵌 PowerShell/.NET Job Object 先挂起创建、成功分配后恢复,禁止 breakaway;helper、编译或分配失败不会降级为裸进程。Windows 需要系统 PowerShell 和 Add-Type,调用隐藏窗口且不加载用户 profile,参数、环境与 UTF-8 管道保持原样。POSIX 命令须让后代继承进程组;已脱离组的系统守护进程及远端服务不在本地终止确认范围。
|
|
162
|
+
|
|
163
|
+
`terminationTimeoutMs` 是异常后的独立核验等待,默认 10000、最大 60000 毫秒。发送 kill 不等于确认;结果在受管理 Job/进程组归零后记录 `localTermination: 'confirmed'`,核验超时或失败为 `unknown`,尚未启动为 `not-started`。在 `if (!result.success)` 分支调用公开 `getDeployCommandState(result.error)` 读取原因和状态;不含原始异常或命令参数。已经进入的异步输出回调不能撤销,异常后不再交付新输出。
|
|
164
|
+
|
|
165
|
+
SSH 中断始终先记 `remoteExecution: 'unknown'`。docker-ssh SDK 用新连接只读核对 `result-<deploymentId>.json`,仅完整、未截断且 ID 匹配的终态记录可确认 `finished`,同时给出真实阶段及退出码;脚本结束不表示容器停止。即使终态退出码为 0,原 SSH/输出失败仍保留为失败,避免丢失回执被伪装成成功。CLI 分别显示本地和远端状态及结果路径;缺结果、旧 ID、损坏内容或重连失败均保持未知,不自动重跑发布或回滚。手工上传脚本在 SSH 失败时保守提示未知和核对目录,部署 ID 见包内 manifest。先核对步骤文件、`current`、真实服务与数据,再决定恢复。
|
|
166
|
+
|
|
153
167
|
## 开发测试
|
|
154
168
|
|
|
155
169
|
```sh
|
|
@@ -157,12 +171,21 @@ pnpm --filter @h-ai/deploy typecheck
|
|
|
157
171
|
pnpm --filter @h-ai/deploy lint
|
|
158
172
|
pnpm --filter @h-ai/deploy build
|
|
159
173
|
pnpm --filter @h-ai/deploy test
|
|
174
|
+
pnpm --filter @h-ai/deploy test:e2e
|
|
160
175
|
pnpm --filter @h-ai/cli test:scaffold-gates
|
|
161
176
|
pnpm --filter @h-ai/cli test:deploy-gates
|
|
162
177
|
```
|
|
163
178
|
|
|
179
|
+
真实部署按 API、SSR、静态移动前端和 fullstack 选取代表:admin 覆盖 website/h5 共用的 SSR Dockerfile 与生产部署分支;各应用类型仍由八个 scaffold 场景分别安装、编译并执行 HTTP/浏览器验收。scaffold 与生成路由 runtime 按实测资源争用分批顺序执行,三个轻型 CLI 门禁可与 runtime 在最多两个 worker 内并行;生成场景复用 E2E 自带完整构建,保留生产构建隔离及真实产物检查。CLI 部署门禁保留认证/传输、增量更新、损坏制品和回滚,并用生产同版本 Nginx 对公开部署包执行 `nginx -t`。测试夹具通过 init 回收孤儿进程,并验证真实 PID 消失。
|
|
180
|
+
|
|
164
181
|
验证真实生成项目与 SSH/人工部署,覆盖禁止访问镜像仓库、局部更新、归档损坏、同版本发布和健康失败。finally/teardown 只清理本次测试创建的项目、镜像、容器、日志和进程。
|
|
165
182
|
|
|
183
|
+
`test:e2e` 构建当前包,并在子进程中启用、串行执行锁与进程两组真实 Linux 门禁,根 `pnpm e2e` 也包含此入口。需要可连接的 Podman(优先)或 Docker,运行公开 API 生成的 `apply.sh`,验证并发、父进程强杀后的子进程持锁、全部进程退出和重启恢复。Compose/HTTP 使用确定性夹具,不能替代真实容器服务部署验收。
|
|
184
|
+
|
|
185
|
+
进程门禁运行 `pnpm --filter @h-ai/deploy exec vitest run tests/deploy-command-process.test.ts tests/deploy-secret-masker.test.ts`。设置同一 `HAI_DEPLOY_E2E=1` 后运行 `tests/deploy-command-runtime.e2e.test.ts`,先构建 deploy;它使用真实 Linux、OpenSSH 和发布 dist,验证远端继续执行/完成回执以及本地进程组。该夹具需联网安装 sshd;Compose/HTTP 为确定性夹具,发布 deadline 缩短为 2500 毫秒,并注入暂停消费模拟丢失回执。
|
|
186
|
+
|
|
187
|
+
部署夹具先检查固定公开基础镜像,仅明确缺失时拉取,可沿用 HAI_DEPLOY_E2E_MIRROR;公共缓存不进入清理账本。成功 create 后先登记容器 ID,再在其私有 PID namespace 内异步安装 APT/pip 并启动 sshd。准备失败、超时或合作式取消会等待本地客户端退出,按已登记 ID 回收并确认消失;仅重型嵌套 Podman 夹具使用特权。HAI_DEPLOY_E2E_APT_MIRROR 只接受镜像站主机名并保留 HTTPS。拥有权测试用固定公开镜像的本轮私有 tag,保留同内容外部 tag、重指向保护、动态端口和外部 sentinel 检查。create 回执丢失且未获得可信 ID、测试进程被强制终止等情况仍需记录未知状态,不能按名称或 label 认领清理。
|
|
188
|
+
|
|
166
189
|
## 许可证
|
|
167
190
|
|
|
168
191
|
Apache-2.0
|