@h-ai/deploy 0.1.0-alpha.64 → 0.1.0-alpha.66

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.en.md CHANGED
@@ -1,243 +1,79 @@
1
1
  # @h-ai/deploy
2
2
 
3
- [简体中文](./README.md) | [English](./README.en.md) | [日本語](./README.ja.md)
3
+ [简体中文](README.md) | [English](README.en.md) | [日本語](README.ja.md)
4
4
 
5
- [Framework home](../../README.en.md) · Related modules: [@h-ai/core](../core/README.en.md)
5
+ Deploy consumes existing artifacts. It never compiles source or builds images. Build once, deploy the same images to multiple environments.
6
6
 
7
- An automated deployment module with two targets: deploy SvelteKit apps to Vercel with cloud infrastructure provisioning, or containerize and deploy to any Linux host over SSH (docker-ssh).
7
+ Follow the [usage guide](../../docs/usage/README.en.md) for the complete creation, development, build, and deployment workflow. This page focuses on deployment requirements, the SDK, and module development.
8
8
 
9
- ## Deployment targets
9
+ ## Build
10
10
 
11
- | Provider | Target | Description |
12
- | ------------ | --------------- | ------------------------------------------------------------- |
13
- | `vercel` | Vercel platform | SvelteKit + adapter-vercel with cloud provisioners |
14
- | `docker-ssh` | Any Linux host | SvelteKit + adapter-node, containerized and deployed over SSH |
11
+ Node `^22.22.2 || ^24.15.0 || >=26.0.0`, pnpm 12.11.2; Windows: `pnpm.cmd`. Node 20 / pnpm 9.5.0 are unsupported.
15
12
 
16
- ## Cloud services (provisioners)
17
-
18
- | Service type | Provisioner | Description |
19
- | ------------ | ------------- | ------------------------------- |
20
- | Database | Neon | PostgreSQL Serverless |
21
- | Cache | Upstash | Redis TCP + TLS |
22
- | Storage | Cloudflare R2 | S3-compatible object storage |
23
- | Email | Resend | SMTP (existing verified domain) |
24
- | SMS | Alibaba Cloud | Alibaba Cloud SMS |
25
-
26
- ## Quick start
27
-
28
- ```typescript
29
- import { deploy } from '@h-ai/deploy'
30
-
31
- // 可选:从 ~/.hai/credentials.yml 注入 HAI_DEPLOY_* 环境变量
32
- deploy.credentials.load()
33
-
34
- // 初始化
35
- await deploy.init({
36
- provider: { type: 'vercel', token: 'vel_xxx' },
37
- services: {
38
- db: { provisioner: 'neon', apiKey: 'neon_xxx' },
39
- cache: { provisioner: 'upstash', email: 'a@b.com', apiKey: 'up_xxx' },
40
- },
41
- })
42
-
43
- // 扫描应用依赖
44
- const scan = await deploy.scan('./apps/my-app')
45
-
46
- // 开通基础设施
47
- const provisions = await deploy.provisionAll('my-app')
48
-
49
- // 完整部署
50
- const result = await deploy.deployApp('./apps/my-app')
51
-
52
- await deploy.close()
13
+ ```sh
14
+ pnpm build # source only; no environment selection
15
+ pnpm build --target docker # reachable Podman first, then Docker
16
+ pnpm build --target docker --runtime docker
17
+ pnpm build --target desktop --platform windows --arch x64
53
18
  ```
54
19
 
55
- ## Configuration
56
-
57
- Keep Git-safe configuration in `config/_deploy.yml` and secrets in `~/.hai/credentials.yml`:
58
-
59
- ```yaml
60
- # config/_deploy.yml
61
- provider:
62
- type: vercel
63
- token: ${HAI_DEPLOY_VERCEL_TOKEN}
64
-
65
- services:
66
- db:
67
- provisioner: neon
68
- apiKey: ${HAI_DEPLOY_NEON_API_KEY}
69
- cache:
70
- provisioner: upstash
71
- email: ${HAI_DEPLOY_UPSTASH_EMAIL}
72
- apiKey: ${HAI_DEPLOY_UPSTASH_API_KEY}
73
- ```
20
+ `hai.build.json` describes Docker targets and Tauri directories. Images and SHA-256 manifest are under `.hai/build/docker/<buildId>`. API/Web share one build ID; latest changes only after complete success. Tauri runs on the matching Windows/Linux/macOS host with Rust targets, SDKs and packaging tools installed; installers are under `src-tauri/target/<target>/release/bundle`. Build has no dev/test/prod mode and excludes deployment credentials.
74
21
 
75
- These variables are explicit special mappings managed by `deploy.credentials`. If convention-based variables
76
- such as `HAI_DEPLOY_PROVIDER_TOKEN` are also set, the convention-based variables take precedence.
22
+ Versions come from the application root package.json.version. For version 1.2.3, archives are app-1.2.3.tar/web-1.2.3.tar and Compose is docker-compose-1.2.3.yml. Manifest version: 2 is its format; appVersion is the application version. --output release-prod.tar becomes release-prod-1.2.3.tar, and Tauri receives the same root version. See the [complete guide](../../docs/usage/README.en.md) for defaults and examples.
77
23
 
78
- Use `deploy.credentials.*` to manage credential files explicitly in scripts or the CLI:
24
+ ## Deployment
79
25
 
80
- ```typescript
81
- deploy.credentials.load()
82
- deploy.credentials.save('HAI_DEPLOY_VERCEL_TOKEN', 'vel_xxx')
83
- deploy.credentials.saveAll({
84
- HAI_DEPLOY_NEON_API_KEY: 'neon_xxx',
85
- })
26
+ ```sh
27
+ pnpm run deploy --env test
28
+ pnpm run deploy --env prod --artifact-dir .hai/build/docker/<buildId> --skip-middleware
29
+ pnpm run deploy --env prod --bundle-only --output release-prod.tar
30
+ # equivalent fullstack CLI invocation
31
+ pnpm exec hai deploy packages/my-app-serv --env prod --env-dir .
86
32
  ```
87
33
 
88
- > `deploy.scan()` and `deploy.credentials.*()` use the local filesystem and do not require `deploy.init()`.
89
-
90
- ## docker-ssh deployment
91
-
92
- Containerize the application and deploy over SSH to any Linux host; no cloud account is required.
93
-
94
- ### Prerequisites
95
-
96
- - **Local**: install docker or podman (`auto` prefers podman).
97
- - **Remote host**: SSH access, docker/podman and compose installed, and a login user permitted to run containers.
98
- - **Application**: SvelteKit must use `@sveltejs/adapter-node` (covered by the supplied `Dockerfile`); otherwise `ADAPTER_MISSING` is returned.
99
-
100
- ### Steps
34
+ Requires matching `@h-ai/cli` / `@h-ai/deploy`, `_deploy.yml`, lockfile and `.env.<mode>`. Missing environment files stop deployment. Public `.env`, `.env.dev/test/prod` and documented `.env.example` are committed; private `.env.local` is ignored. Priority: process > local > mode > base. SSH fields/tokens can be stored in private `HAI_DEPLOY_PROVIDER` JSON. Bundle-only needs no SSH config or local container engine.
101
35
 
102
- 1. Store the SSH private key path in the credential file, outside the repository. Edit `~/.hai/credentials.yml` or use the API:
36
+ The wizard traverses only lockfile runtime dependencies, excluding dev/peer. Select default, custom or keep for each middleware; `--skip-middleware` bypasses all middleware work. Compose supports PostgreSQL/MySQL/Redis/RustFS/MinIO/Qdrant/pgvector/Chroma/OpenLDAP/Mailpit. Optional cloud provisioning supports Neon/Upstash/R2/Resend/Aliyun SMS and requires network access.
103
37
 
104
- ```typescript
105
- deploy.credentials.save('HAI_DEPLOY_SSH_KEY', '~/.ssh/hai_deploy')
106
- ```
38
+ Optional `container.s3Engine` defaults to rustfs and chooses RustFS/MinIO only when creating a Compose S3 service. Existing custom S3 services are unaffected. Use `--skip-middleware` to bypass middleware setup; the SDK field is `skipMiddleware`.
107
39
 
108
- 2. Declare the target host in `config/_deploy.yml`:
109
-
110
- ```yaml
111
- provider:
112
- type: docker-ssh
113
- ssh:
114
- host: 10.0.0.20 # 主机 IP 或 ~/.ssh/config 别名
115
- port: 22
116
- username: deploy
117
- identityFile: ${HAI_DEPLOY_SSH_KEY} # 私钥文件路径,省略则用 ssh-agent
118
- remote:
119
- baseDir: /opt/hai/apps # 远程部署根目录
120
- runtime: auto # 远程运行时;auto 优先 podman,其次 docker
121
- expose:
122
- type: port
123
- containerPort: 3000 # 容器内端口(adapter-node 默认 3000)
124
- hostPort: 18080 # 宿主机端口 → 访问地址 http://10.0.0.20:18080
125
-
126
- container:
127
- runtime: auto # 本地构建运行时(可选)
128
-
129
- services: {} # 启用的服务会自动生成 compose sidecar,见下
130
- ```
40
+ A single private tar contains Compose, runtime env, app/web images, optional Web proxy, checksums, README and `start-<mode>.sh`. SSH uploads this tar, extracts and starts it remotely. No source upload or remote build. With app/web images, Web exposes the public port and proxies the internal API on the same origin; no API secrets enter Web. Online success requires both health checks. Vercel uploads existing `.vercel/output` , sets runtime variables and never builds locally.
131
41
 
132
- 3. Deploy and verify with the CLI or API (equivalent behavior):
42
+ ## Offline / manual transfer
133
43
 
134
- ```bash
135
- hai deploy # 读取 config/_deploy.yml,输出访问地址
136
- ```
44
+ Prepare supported Node/pnpm and installed project CLI/SDK dependencies on Windows, plus the complete prebuilt image directory for the Linux server architecture. Deploy requires tar locally; automatic mode also needs ssh/scp, trusted host keys and reachable SSH/application ports. Bundle-only works with removable media and no network between machines.
137
45
 
138
- ```typescript
139
- import { deploy } from '@h-ai/deploy'
140
-
141
- deploy.credentials.load() // 注入 HAI_DEPLOY_* 环境变量
142
- await deploy.init(dockerSshConfig)
143
- const result = await deploy.deployApp('./apps/my-app')
144
- if (result.success) {
145
- result.data.url // http://<host>:<hostPort>
146
- result.data.healthCheck // 'passed'(HTTP 探测成功)
147
- }
148
- await deploy.close()
149
- ```
46
+ Linux needs Docker/Podman, compose, sh, tar, sha256sum, writable deployment/data directories and container permissions. Middleware images must already be loaded with the exact names/tags printed in the bundle README; app/web archives are included. Missing images stop startup without downloading. Custom connections require reachable running services, accounts, databases/buckets and credentials.
150
47
 
151
- ### How it works
152
-
153
- For docker-ssh, `deployApp()` runs these steps:
154
-
155
- 1. **Scan**: read `package.json` and `config/*.yml` to identify `@sveltejs/adapter-node`, required services, and backend types.
156
- 2. **Local build**: use the project's `Dockerfile` to build `hai-<app>:<deploymentId>` (podman adds `--format docker --jobs=1`).
157
- 3. **Export**: save the image as tar with `docker/podman save`.
158
- 4. **Preflight**: verify SSH connectivity and remote `docker/podman version` / `compose version`.
159
- 5. **Transfer/load**: upload tar with `scp`, load remotely, and retag under `localhost/` to avoid accidental registry pulls.
160
- 6. **Runtime files**: generate `compose.yml` (app + sidecars) and `.env.runtime` (including `HAI_*` overrides and credentials), upload to `<baseDir>/<app>/`, and set `.env.runtime` permissions to `600`.
161
- 7. **Start**: `compose up -d` with fixed project name `hai-<app>` for idempotent redeployment.
162
- 8. **Health check**: poll `http://<host>:<hostPort>/`; only HTTP 200 yields `ready`.
163
-
164
- > Images, `compose.yml`, and `.env.runtime` are stored in the application's `.hai/deploy/`, excluded by the template `.gitignore`.
165
-
166
- ### Feature-based compose sidecars
167
-
168
- `deploy.scan()` identifies services and their **actual backend types** (`type` in `_db.yml` / `_vecdb.yml`, etc.), generates matching sidecars, and injects `HAI_*` overrides:
169
-
170
- | Detected service | Backend (`type`) | Added sidecar | Injected variables |
171
- | ---------------- | ---------------- | ------------------------------- | ------------------ |
172
- | `db` | `postgresql` | `postgres:16-alpine` | `HAI_DB` |
173
- | `db` | `mysql` | `mysql:8.4` | `HAI_DB` |
174
- | `db` | `sqlite` | None (mount `/app/data` volume) | — |
175
- | `cache` | `redis` | `redis:7-alpine` | `HAI_CACHE` |
176
- | `storage` | `s3` | `minio` + bucket initialization | `HAI_STORAGE` |
177
- | `vecdb` | `qdrant` | `qdrant/qdrant` | `HAI_VECDB` |
178
- | `vecdb` | `pgvector` | `pgvector/pgvector` | `HAI_VECDB` |
179
- | `vecdb` | `chroma` | `chromadb/chroma` | `HAI_VECDB` |
180
- | `vecdb` | `lancedb` | None (mount `/app/data` volume) | — |
181
-
182
- - Memory `cache` and external email/SMS `reach` APIs do not generate sidecars.
183
- - Existing cloud provisioners take precedence (for example Neon providing `HAI_DB`); no duplicate sidecar is created.
184
- - Sidecar secrets such as passwords go only in remote `.env.runtime` (`600`), never `compose.yml`.
185
-
186
- > Security: `identityFile` is a private key **path**, not key content. `strictHostKeyChecking: true` (default)
187
- > uses accept-new: trust first use and reject changed keys. You may connect once manually with `ssh` for an unknown host.
188
-
189
- ## Error handling
190
-
191
- ```typescript
192
- import { HaiDeployError } from '@h-ai/deploy'
193
-
194
- const result = await deploy.deployApp('./apps/my-app')
195
- if (!result.success) {
196
- switch (result.error.code) {
197
- case HaiDeployError.AUTH_FAILED.code:
198
- // Vercel Token 无效
199
- break
200
- case HaiDeployError.BUILD_FAILED.code:
201
- // 构建失败
202
- break
203
- }
204
- }
48
+ ```sh
49
+ mkdir -p release && chmod 700 release
50
+ tar -xf release-prod-1.2.3.tar -C release
51
+ cd release
52
+ HAI_DEPLOY_PROVIDER_REMOTE_RUNTIME=docker sh start-prod.sh
205
53
  ```
206
54
 
207
- Common error codes:
208
-
209
- | Error code | code | Description |
210
- | --------------------------------- | ---------------- | ------------------------------------- |
211
- | `HaiDeployError.DEPLOY_FAILED` | `hai:deploy:001` | Deployment failed |
212
- | `HaiDeployError.BUILD_FAILED` | `hai:deploy:003` | Build failed |
213
- | `HaiDeployError.AUTH_FAILED` | `hai:deploy:006` | Authentication failed |
214
- | `HaiDeployError.PROVISION_FAILED` | `hai:deploy:007` | Provisioning failed |
215
- | `HaiDeployError.NOT_INITIALIZED` | `hai:deploy:010` | Not initialized |
216
- | `HaiDeployError.ENV_VAR_FAILED` | `hai:deploy:011` | Environment variable operation failed |
55
+ The tar contains secrets: restrict permissions and never commit it. `packaged` means no server has been started or health-checked. After manual startup, use `docker compose -f docker-compose-1.2.3.yml --env-file .env.runtime ps` (or logs), then verify Web, /health, real login/refresh, restart and persistence. Production sessions need HTTPS, trusted certificates, DNS and correct CORS; TLS is managed separately.
217
56
 
218
- docker-ssh-specific error codes:
57
+ Prebuilt deployment needs no local container engine, Linux Node base image, compiler, CUDA or SQLite download. Fully offline **building** separately needs Linux base images, pnpm/Corepack, complete Linux dependency caches and SQLite prebuilds matching driver/ABI/architecture/libc. Windows node_modules are insufficient. Use `pnpm build --target docker --sqlite-prebuild-mirror http://trusted-host/better-sqlite3` when appropriate. No AI runtime dependency means no AI/CUDA installation. Cloud services are unsuitable offline. Prove offline behavior by actually disconnecting; online tests do not establish it.
219
58
 
220
- | Error code | code | Description |
221
- | -------------------------------------------- | ---------------- | --------------------------- |
222
- | `HaiDeployError.CONTAINER_RUNTIME_NOT_FOUND` | `hai:deploy:015` | Container runtime not found |
223
- | `HaiDeployError.CONTAINER_BUILD_FAILED` | `hai:deploy:016` | Image build failed |
224
- | `HaiDeployError.REMOTE_CONNECT_FAILED` | `hai:deploy:017` | Remote connection failed |
225
- | `HaiDeployError.REMOTE_COMMAND_FAILED` | `hai:deploy:018` | Remote command failed |
226
- | `HaiDeployError.IMAGE_TRANSFER_FAILED` | `hai:deploy:019` | Image transfer failed |
227
- | `HaiDeployError.HEALTH_CHECK_FAILED` | `hai:deploy:020` | Health check failed |
59
+ ## SDK / development
228
60
 
229
- ## Tests
61
+ Call `deploy.init(config)`, check success, then `deploy.deployApp(appDir, { environment: 'prod', envDir: '.', artifactDir, bundleOnly: true })`, check success and finally `deploy.close()`. `deploy.scan` / credentials do not require init. Results return bundlePath/instructions for packaged mode, URL and health status for automatic deployment.
230
62
 
231
- ```bash
63
+ ```sh
64
+ pnpm --filter @h-ai/deploy typecheck
65
+ pnpm --filter @h-ai/deploy lint
66
+ pnpm --filter @h-ai/deploy build
232
67
  pnpm --filter @h-ai/deploy test
68
+ pnpm --filter @h-ai/cli test
69
+ pnpm --filter @h-ai/cli test:scaffold-gates
70
+ pnpm --filter @h-ai/cli test:deploy-gates
233
71
  ```
234
72
 
235
- ## License
236
-
237
- Apache-2.0
73
+ Deploy gates generate fullstack from current archives, build API/Web once, exercise SSH and manual bundle startup and run real browser flows. Tests clean temporary projects, images, containers, screenshots/reports and helper processes in finally/teardown even on failure. Native installer acceptance requires each OS. See [configuration and middleware](../cli/templates/skills/hai-deploy/middleware.md) and [complete examples](README.md).
238
74
 
239
- Provisioned configuration: Neon emits HAI_DB (PostgreSQL JSON), Upstash HAI_CACHE (Redis rediss URL JSON), and R2 HAI_STORAGE (flat S3 JSON). Email/SMS emit HAI_REACH_PROVIDERS; deployApp merges both channels while preserving YAML message templates, replacing the original providers array. Core supports whole-object/array overrides, with parents preceding leaves and schema validation retained. Build subprocesses and target runtimes share provisioned values. R2 needs existing S3 accessKeyId/secretAccessKey, Resend a verified-domain from address, and Alibaba Cloud approved signName/templates. Applications need matching `_db.yml` / `_cache.yml` / `_storage.yml` / `_reach.yml` loaded at startup; network clients require Node.
75
+ Deploy gates do not forward host proxies by default. To download build dependencies through a proxy, set test-only `HAI_DEPLOY_E2E_CONTAINER_PROXY` (unset by default), for example `$env:HAI_DEPLOY_E2E_CONTAINER_PROXY='http://host.containers.internal:10808'` in PowerShell for Windows Podman. The address must be reachable from build containers; it is not written to application configuration or release images.
240
76
 
241
- Configuration references: [Upstash TLS](https://upstash.com/docs/redis/features/security), [Resend SMTP](https://resend.com/docs/send-with-smtp). Deterministic acceptance generates real applications and validates Core and module schemas. It does not create cloud resources or send email/SMS, so it does not establish cloud read/write acceptance.
77
+ Test-only `HAI_DEPLOY_E2E_CONTAINER_NETWORK` is unset by default and forwards its value to build's `--network`. For example, rootless Podman can use `$env:HAI_DEPLOY_E2E_CONTAINER_NETWORK='pasta'`. Build and run networks may differ; verify the proxy address on the build network too.
242
78
 
243
- Deployment recovery: `ProvisionResult.resourceStatus` marks created/reused. `getDeployRecovery(result.error)` reads projectName, stage, platformProjectId, and resource lists; unknown means an uncertain request result that must first be checked in the provider console. Preserve returned IDs for failed resources. Recovery excludes envVars, raw exceptions, and credentials; the CLI shows resources and advice. Same-name retries reuse resources. Reused resources are never deleted automatically; clean up newly created resources only after manually confirming they are unused.
79
+ On Windows, set test-only HAI_CLI_NATIVE_BUILD=1 (unset by default), then run `pnpm --filter @h-ai/cli test:scaffold-gates -t "fullstack scaffold"`. With Rust/MSVC/Windows SDK installed, it additionally builds the generated Tauri installer and checks that root version 2.4.6 appears in the exe filename. The temporary project and native output are cleaned automatically.
package/README.ja.md CHANGED
@@ -1,243 +1,79 @@
1
1
  # @h-ai/deploy
2
2
 
3
- [简体中文](./README.md) | [English](./README.en.md) | [日本語](./README.ja.md)
3
+ [简体中文](README.md) | [English](README.en.md) | [日本語](README.ja.md)
4
4
 
5
- [フレームワークのホーム](../../README.ja.md) · 関連モジュール:[@h-ai/core](../core/README.ja.md)
5
+ deploy は既存の成果物だけを配布します。ソースのコンパイルやイメージのビルドは行いません。同じイメージを複数環境へ配布できます。
6
6
 
7
- 自動デプロイモジュールです。SvelteKit アプリをクラウド基盤の作成とともに Vercel へ展開する方式と、コンテナー化して任意の Linux ホストへ SSH で展開する方式(docker-ssh)に対応します。
7
+ 作成、開発、ビルド、デプロイの全体は[使用ガイド](../../docs/usage/README.ja.md)を参照してください。本ページではデプロイの準備、SDK、モジュール開発を説明します。
8
8
 
9
- ## 対応デプロイ方式
9
+ ## ビルド
10
10
 
11
- | Provider | 展開先 | 説明 |
12
- | ------------ | ------------------- | ------------------------------------------------------- |
13
- | `vercel` | Vercel | SvelteKit + adapter-vercel、クラウド Provisioner と連携 |
14
- | `docker-ssh` | 任意の Linux ホスト | SvelteKit + adapter-node、コンテナー化して SSH で展開 |
11
+ Node `^22.22.2 || ^24.15.0 || >=26.0.0` と pnpm 12.11.2 を使用します。Windows では `pnpm.cmd` を実行してください。Node 20 / pnpm 9.5.0 は対象外です。
15
12
 
16
- ## 対応クラウドサービス(Provisioner)
17
-
18
- | サービス種別 | Provisioner | 説明 |
19
- | ------------ | ------------- | ------------------------------ |
20
- | データベース | Neon | PostgreSQL Serverless |
21
- | キャッシュ | Upstash | Redis TCP + TLS |
22
- | ストレージ | Cloudflare R2 | S3 互換オブジェクトストレージ |
23
- | メール | Resend | SMTP(検証済みドメインが必要) |
24
- | SMS | Alibaba Cloud | Alibaba Cloud SMS |
25
-
26
- ## クイックスタート
27
-
28
- ```typescript
29
- import { deploy } from '@h-ai/deploy'
30
-
31
- // 可选:从 ~/.hai/credentials.yml 注入 HAI_DEPLOY_* 环境变量
32
- deploy.credentials.load()
33
-
34
- // 初始化
35
- await deploy.init({
36
- provider: { type: 'vercel', token: 'vel_xxx' },
37
- services: {
38
- db: { provisioner: 'neon', apiKey: 'neon_xxx' },
39
- cache: { provisioner: 'upstash', email: 'a@b.com', apiKey: 'up_xxx' },
40
- },
41
- })
42
-
43
- // 扫描应用依赖
44
- const scan = await deploy.scan('./apps/my-app')
45
-
46
- // 开通基础设施
47
- const provisions = await deploy.provisionAll('my-app')
48
-
49
- // 完整部署
50
- const result = await deploy.deployApp('./apps/my-app')
51
-
52
- await deploy.close()
13
+ ```sh
14
+ pnpm build # ソースだけをコンパイル。環境は選択しない
15
+ pnpm build --target docker # 利用可能な Podman、次に Docker
16
+ pnpm build --target docker --runtime docker
17
+ pnpm build --target desktop --platform windows --arch x64
53
18
  ```
54
19
 
55
- ## 設定
56
-
57
- Git に保存できる設定は `config/_deploy.yml`、秘密情報は `~/.hai/credentials.yml` で管理します:
58
-
59
- ```yaml
60
- # config/_deploy.yml
61
- provider:
62
- type: vercel
63
- token: ${HAI_DEPLOY_VERCEL_TOKEN}
64
-
65
- services:
66
- db:
67
- provisioner: neon
68
- apiKey: ${HAI_DEPLOY_NEON_API_KEY}
69
- cache:
70
- provisioner: upstash
71
- email: ${HAI_DEPLOY_UPSTASH_EMAIL}
72
- apiKey: ${HAI_DEPLOY_UPSTASH_API_KEY}
73
- ```
20
+ `hai.build.json` で Dockerfile のステージと Tauri ディレクトリーを指定します。イメージと SHA-256 付きマニフェストは `.hai/build/docker/<buildId>` に出力されます。API/Web は同じビルド ID を使い、すべて成功してから latest を更新します。Tauri は対象の Windows/Linux/macOS 上で実行し、対応する Rust target、SDK、パッケージツールが必要です。インストーラーは `src-tauri/target/<target>/release/bundle` に出力されます。ビルドでは dev/test/prod を選ばず、デプロイの認証情報も取り込みません。
74
21
 
75
- ここでの変数は `deploy.credentials` が管理する明示的な特殊マッピングです。YAML パスから生成する
76
- `HAI_DEPLOY_PROVIDER_TOKEN` なども指定した場合、規約に沿う変数が優先されます。
22
+ 版はアプリルートの package.json.version を使います。例 1.2.3 では app-1.2.3.tar、web-1.2.3.tar、docker-compose-1.2.3.yml を生成します。マニフェスト形式の版は version: 2、アプリ版は appVersion です。--output release-prod.tar は release-prod-1.2.3.tar になり、Tauri も同じ版を使います。既定値と例は[完全ガイド](../../docs/usage/README.ja.md)を参照してください。
77
23
 
78
- スクリプト・CLI で認証情報ファイルを明示的に管理するには `deploy.credentials.*` を使います:
24
+ ## デプロイ
79
25
 
80
- ```typescript
81
- deploy.credentials.load()
82
- deploy.credentials.save('HAI_DEPLOY_VERCEL_TOKEN', 'vel_xxx')
83
- deploy.credentials.saveAll({
84
- HAI_DEPLOY_NEON_API_KEY: 'neon_xxx',
85
- })
26
+ ```sh
27
+ pnpm run deploy --env test
28
+ pnpm run deploy --env prod --artifact-dir .hai/build/docker/<buildId> --skip-middleware
29
+ pnpm run deploy --env prod --bundle-only --output release-prod.tar
30
+ # fullstack で同じ処理を直接呼ぶ場合
31
+ pnpm exec hai deploy packages/my-app-serv --env prod --env-dir .
86
32
  ```
87
33
 
88
- > `deploy.scan()` と `deploy.credentials.*()` はローカルファイルシステムの機能で、`deploy.init()` に依存しません。
89
-
90
- ## docker-ssh デプロイ
91
-
92
- アプリをコンテナー化して SSH で任意の Linux ホストへ展開します。クラウドアカウントは不要です。
93
-
94
- ### 前提条件
95
-
96
- - **ローカル**:docker または podman をインストール(`auto` は podman を優先)。
97
- - **リモート**:SSH 接続可能、docker/podman と compose が導入済み、ログインユーザーがコンテナーを実行可能。
98
- - **アプリ**:SvelteKit に `@sveltejs/adapter-node` を使用(付属 `Dockerfile` は対応済み)。不足時は `ADAPTER_MISSING`。
99
-
100
- ### 使用手順
34
+ 対応する版の `@h-ai/cli` / `@h-ai/deploy`、`_deploy.yml`、lockfile、`.env.<mode>` が必要です。環境ファイルがなければ処理を停止します。公開設定の `.env`、`.env.dev/test/prod` と説明付き `.env.example` は Git に登録し、私有の `.env.local` は除外します。優先順位はプロセス変数 > local > 環境別 > 基本設定です。SSH の接続情報やトークンは私有の `HAI_DEPLOY_PROVIDER` JSON に保存できます。bundle-only では SSH 設定やローカルのコンテナーエンジンは不要です。
101
35
 
102
- 1. SSH 秘密鍵のパスをリポジトリー外の認証情報ファイルに保存します。`~/.hai/credentials.yml` を編集するか API を使います:
36
+ ウィザードは lockfile の実行時依存だけをたどり、dev/peer を除外します。ミドルウェアごとに既定構成、独自構成、既存設定の保持を選べます。`--skip-middleware` はミドルウェア処理全体を省略します。Compose は PostgreSQL/MySQL/Redis/RustFS/MinIO/Qdrant/pgvector/Chroma/OpenLDAP/Mailpit に対応します。任意のクラウド作成は Neon/Upstash/R2/Resend/Aliyun SMS に対応し、ネットワーク接続が必要です。
103
37
 
104
- ```typescript
105
- deploy.credentials.save('HAI_DEPLOY_SSH_KEY', '~/.ssh/hai_deploy')
106
- ```
38
+ `container.s3Engine` は任意で、既定値は rustfs です。Compose で S3 サービスを自動作成するときだけ RustFS/MinIO を選び、独自の既存 S3 には影響しません。ミドルウェア処理の省略は CLI の `--skip-middleware`、SDK の `skipMiddleware` で指定します。
107
39
 
108
- 2. `config/_deploy.yml` に対象ホストを定義します:
109
-
110
- ```yaml
111
- provider:
112
- type: docker-ssh
113
- ssh:
114
- host: 10.0.0.20 # 主机 IP 或 ~/.ssh/config 别名
115
- port: 22
116
- username: deploy
117
- identityFile: ${HAI_DEPLOY_SSH_KEY} # 私钥文件路径,省略则用 ssh-agent
118
- remote:
119
- baseDir: /opt/hai/apps # 远程部署根目录
120
- runtime: auto # 远程运行时;auto 优先 podman,其次 docker
121
- expose:
122
- type: port
123
- containerPort: 3000 # 容器内端口(adapter-node 默认 3000)
124
- hostPort: 18080 # 宿主机端口 → 访问地址 http://10.0.0.20:18080
125
-
126
- container:
127
- runtime: auto # 本地构建运行时(可选)
128
-
129
- services: {} # 启用的服务会自动生成 compose sidecar,见下
130
- ```
40
+ 一つの私有 tar に Compose、実行時の環境変数、app/web イメージ、必要な Web プロキシ、チェックサム、README、`start-<mode>.sh` をまとめます。SSH でこの tar を転送し、リモートで展開・起動します。ソースの転送やリモートビルドは行いません。app/web 構成では Web の公開ポートから同一オリジンで内部 API に接続し、API の秘密情報は Web に渡しません。自動デプロイの成功には両方のヘルスチェック通過が必要です。Vercel は既存の `.vercel/output` を転送して実行時変数を設定し、ローカルビルドは行いません。
131
41
 
132
- 3. CLI または API で展開・検証します(動作は同じ):
42
+ ## オフラインと手動転送
133
43
 
134
- ```bash
135
- hai deploy # 读取 config/_deploy.yml,输出访问地址
136
- ```
44
+ Windows 側に対応する Node/pnpm、インストール済みの CLI/SDK 依存関係、Linux サーバーのアーキテクチャーに合う構築済みイメージのディレクトリー全体を準備します。ローカルには tar が必要です。自動転送では ssh/scp、信頼済みホスト鍵、SSH とアプリのポートへの接続も必要です。bundle-only なら、二台の間にネットワークがなくても外部メディアで運べます。
137
45
 
138
- ```typescript
139
- import { deploy } from '@h-ai/deploy'
140
-
141
- deploy.credentials.load() // 注入 HAI_DEPLOY_* 环境变量
142
- await deploy.init(dockerSshConfig)
143
- const result = await deploy.deployApp('./apps/my-app')
144
- if (result.success) {
145
- result.data.url // http://<host>:<hostPort>
146
- result.data.healthCheck // 'passed'(HTTP 探测成功)
147
- }
148
- await deploy.close()
149
- ```
46
+ Linux 側には Docker/Podman、compose、sh、tar、sha256sum、書き込み可能な配布・データディレクトリー、コンテナー操作権限が必要です。ミドルウェアイメージは tar 内の README に記載された名前とタグで読み込んでください。app/web のアーカイブは同梱されます。イメージが不足すると、ダウンロードせずに起動を停止します。独自接続では利用可能なサービス、アカウント、DB/バケット、認証情報を準備します。
150
47
 
151
- ### 処理の流れ
152
-
153
- docker-ssh の `deployApp()` は次の順で処理します:
154
-
155
- 1. **走査**:`package.json` と `config/*.yml` から `@sveltejs/adapter-node`、必要なサービス、バックエンド種別を判定。
156
- 2. **ローカルビルド**:プロジェクトの `Dockerfile` で `hai-<app>:<deploymentId>` を作成(podman は `--format docker --jobs=1` を追加)。
157
- 3. **出力**:`docker/podman save` で tar に保存。
158
- 4. **事前確認**:SSH 接続とリモートの `docker/podman version` / `compose version` を確認。
159
- 5. **転送・読み込み**:`scp` で tar を転送し、リモートで `load` 後、誤った registry 取得を防ぐため `localhost/` タグを付与。
160
- 6. **実行定義**:走査結果から `compose.yml`(app + sidecar)と `.env.runtime`(`HAI_*` 上書き・認証情報)を生成し、`<baseDir>/<app>/` に転送。`.env.runtime` は `600` に設定。
161
- 7. **起動**:固定プロジェクト名 `hai-<app>` で `compose up -d`。再展開は冪等。
162
- 8. **ヘルスチェック**:`http://<host>:<hostPort>/` を監視し、200 応答でのみ `ready` と判定。
163
-
164
- > イメージ、`compose.yml`、`.env.runtime` はアプリの `.hai/deploy/` に保存し、テンプレートの `.gitignore` で除外済みです。
165
-
166
- ### 機能に応じた compose sidecar
167
-
168
- `deploy.scan()` は必要なサービスと**実際のバックエンド種別**(`_db.yml` / `_vecdb.yml` などの `type`)を読み、対応する sidecar と `HAI_*` 上書き変数を生成します:
169
-
170
- | 検出サービス | バックエンド(`type`) | 追加 sidecar | 注入する変数 |
171
- | ------------ | ---------------------- | ---------------------------------------- | ------------- |
172
- | `db` | `postgresql` | `postgres:16-alpine` | `HAI_DB` |
173
- | `db` | `mysql` | `mysql:8.4` | `HAI_DB` |
174
- | `db` | `sqlite` | なし(`/app/data` ボリュームをマウント) | — |
175
- | `cache` | `redis` | `redis:7-alpine` | `HAI_CACHE` |
176
- | `storage` | `s3` | `minio` + バケット初期化 | `HAI_STORAGE` |
177
- | `vecdb` | `qdrant` | `qdrant/qdrant` | `HAI_VECDB` |
178
- | `vecdb` | `pgvector` | `pgvector/pgvector` | `HAI_VECDB` |
179
- | `vecdb` | `chroma` | `chromadb/chroma` | `HAI_VECDB` |
180
- | `vecdb` | `lancedb` | なし(`/app/data` ボリュームをマウント) | — |
181
-
182
- - `memory` の `cache` と外部 API の `reach`(メール・SMS)は sidecar を生成しません。
183
- - 同じサービスにクラウド Provisioner がある場合(Neon の `HAI_DB` など)、クラウドを優先し sidecar を重複作成しません。
184
- - sidecar のパスワードなどはリモートの `.env.runtime`(`600`)のみに保存し、`compose.yml` には含めません。
185
-
186
- > セキュリティ:`identityFile` は秘密鍵の**パス**で、内容ではありません。`strictHostKeyChecking: true`(既定)は
187
- > accept-new を使い、初回は信頼し、鍵変更は拒否します。未知のホストには先に手動で `ssh` 接続できます。
188
-
189
- ## エラー処理
190
-
191
- ```typescript
192
- import { HaiDeployError } from '@h-ai/deploy'
193
-
194
- const result = await deploy.deployApp('./apps/my-app')
195
- if (!result.success) {
196
- switch (result.error.code) {
197
- case HaiDeployError.AUTH_FAILED.code:
198
- // Vercel Token 无效
199
- break
200
- case HaiDeployError.BUILD_FAILED.code:
201
- // 构建失败
202
- break
203
- }
204
- }
48
+ ```sh
49
+ mkdir -p release && chmod 700 release
50
+ tar -xf release-prod-1.2.3.tar -C release
51
+ cd release
52
+ HAI_DEPLOY_PROVIDER_REMOTE_RUNTIME=docker sh start-prod.sh
205
53
  ```
206
54
 
207
- 主なエラーコード:
208
-
209
- | エラーコード | code | 説明 |
210
- | --------------------------------- | ---------------- | -------------------- |
211
- | `HaiDeployError.DEPLOY_FAILED` | `hai:deploy:001` | デプロイに失敗 |
212
- | `HaiDeployError.BUILD_FAILED` | `hai:deploy:003` | ビルドに失敗 |
213
- | `HaiDeployError.AUTH_FAILED` | `hai:deploy:006` | 認証に失敗 |
214
- | `HaiDeployError.PROVISION_FAILED` | `hai:deploy:007` | リソースの作成に失敗 |
215
- | `HaiDeployError.NOT_INITIALIZED` | `hai:deploy:010` | 未初期化 |
216
- | `HaiDeployError.ENV_VAR_FAILED` | `hai:deploy:011` | 環境変数の処理に失敗 |
55
+ tar には秘密情報が含まれるため、アクセス権を制限し、Git に登録しないでください。`packaged` はサーバー起動やヘルスチェックをまだ行っていない状態です。手動起動後は `docker compose -f docker-compose-1.2.3.yml --env-file .env.runtime ps`(または logs)、Web、/health、実際のログインと再読み込み、再起動とデータ保持を確認します。本番のセッションには HTTPS、信頼できる証明書、DNS、正しい CORS が必要で、TLS は別途設定します。
217
56
 
218
- docker-ssh 専用エラーコード:
57
+ 構築済み成果物の配布には、ローカルのコンテナーエンジン、Linux Node ベースイメージ、コンパイラー、CUDA、SQLite のダウンロードは不要です。完全オフラインでの**ビルド**には、別途 Linux ベースイメージ、pnpm/Corepack、Linux 用依存キャッシュ一式、driver/ABI/アーキテクチャー/libc が一致する SQLite バイナリーが必要です。Windows の node_modules だけでは足りません。必要に応じて `pnpm build --target docker --sqlite-prebuild-mirror http://trusted-host/better-sqlite3` を使えます。AI の実行時依存がなければ AI/CUDA は不要です。クラウドサービスはオフラインでは使えません。完全オフラインの動作は実際に接続を切って確認してください。
219
58
 
220
- | エラーコード | code | 説明 |
221
- | -------------------------------------------- | ---------------- | ---------------------------------- |
222
- | `HaiDeployError.CONTAINER_RUNTIME_NOT_FOUND` | `hai:deploy:015` | コンテナーランタイムが見つからない |
223
- | `HaiDeployError.CONTAINER_BUILD_FAILED` | `hai:deploy:016` | イメージのビルドに失敗 |
224
- | `HaiDeployError.REMOTE_CONNECT_FAILED` | `hai:deploy:017` | リモート接続に失敗 |
225
- | `HaiDeployError.REMOTE_COMMAND_FAILED` | `hai:deploy:018` | リモートコマンドに失敗 |
226
- | `HaiDeployError.IMAGE_TRANSFER_FAILED` | `hai:deploy:019` | イメージ転送に失敗 |
227
- | `HaiDeployError.HEALTH_CHECK_FAILED` | `hai:deploy:020` | ヘルスチェックに失敗 |
59
+ ## SDK とモジュール開発
228
60
 
229
- ## テスト
61
+ `deploy.init(config)` の成功を確認してから `deploy.deployApp(appDir, { environment: 'prod', envDir: '.', artifactDir, bundleOnly: true })` を呼び、結果を確認し、最後に `deploy.close()` を実行します。`deploy.scan` と credentials は初期化不要です。packaged の結果には bundlePath/instructions、自動デプロイの結果には URL とヘルス状態が入ります。
230
62
 
231
- ```bash
63
+ ```sh
64
+ pnpm --filter @h-ai/deploy typecheck
65
+ pnpm --filter @h-ai/deploy lint
66
+ pnpm --filter @h-ai/deploy build
232
67
  pnpm --filter @h-ai/deploy test
68
+ pnpm --filter @h-ai/cli test
69
+ pnpm --filter @h-ai/cli test:scaffold-gates
70
+ pnpm --filter @h-ai/cli test:deploy-gates
233
71
  ```
234
72
 
235
- ## License
236
-
237
- Apache-2.0
73
+ デプロイのゲートは現在のソースをパッケージ化して fullstack を生成し、API/Web を一度構築してから、SSH と手動 tar の起動、実際のブラウザー操作を検証します。失敗時も finally/teardown で一時プロジェクト、イメージ、コンテナー、スクリーンショット・レポート、補助プロセスを削除します。ネイティブインストーラーは各 OS での確認が必要です。[設定とミドルウェア](../cli/templates/skills/hai-deploy/middleware.md)、[詳細な例](README.md)も参照してください。
238
74
 
239
- クラウド設定の利用:Neon は HAI_DB(PostgreSQL JSON)、Upstash は HAI_CACHE(Redis rediss URL JSON)、R2 は HAI_STORAGE(フラットな S3 JSON)を出力します。メール・SMS は HAI_REACH_PROVIDERS を出力し、deployApp が両チャネルと YAML のメッセージテンプレートを統合して元の providers 配列を置換します。Core はオブジェクト・配列全体の上書きをサポートし、親ノードを末端より優先して Schema 検証を維持します。ビルド子プロセスと対象環境は同じ値を使います。R2 は既存の S3 accessKeyId/secretAccessKey、Resend は検証済みドメインの from、Alibaba Cloud は承認済み signName・テンプレートが必要です。アプリは対応する `_db.yml` / `_cache.yml` / `_storage.yml` / `_reach.yml` を起動時に読み込み、ネットワーククライアントには Node が必要です。
75
+ デプロイのゲートは既定でホストのプロキシを転送しません。依存のダウンロードに必要な場合、テスト専用 `HAI_DEPLOY_E2E_CONTAINER_PROXY`(既定は未設定)を設定します。Windows Podman の PowerShell の例は `$env:HAI_DEPLOY_E2E_CONTAINER_PROXY='http://host.containers.internal:10808'` です。ビルドコンテナーから到達できるアドレスを使い、アプリ設定や配布イメージには保存しません。
240
76
 
241
- 設定の参照:[Upstash TLS](https://upstash.com/docs/redis/features/security)、[Resend SMTP](https://resend.com/docs/send-with-smtp)。決定的な検証では実際のアプリを生成して Core・各モジュールの Schema を確認します。クラウドリソースの作成やメール・SMS 送信は行わず、クラウドの読み書き検証済みとは言えません。
77
+ テスト専用 `HAI_DEPLOY_E2E_CONTAINER_NETWORK` は既定では未設定で、設定値を build の `--network` に渡します。rootless Podman の例は `$env:HAI_DEPLOY_E2E_CONTAINER_NETWORK='pasta'` です。build と run ではネットワークが異なる場合があるため、ビルド側でプロキシの到達性も確認してください。
242
78
 
243
- デプロイ失敗からの復旧:`ProvisionResult.resourceStatus` は created/reused を示します。`getDeployRecovery(result.error)` で projectName、stage、platformProjectId、リソース一覧を取得し、unknown は結果不明なので先にサービス側の管理画面で確認します。失敗リソースの ID が返った場合は保持します。復旧情報に envVars・元の例外・接続認証情報は含まれず、CLI が一覧と提案を表示します。同名の再試行は既存リソースを再利用し、自動削除しません。新規作成分も未使用を人が確認した後にのみ削除します。
79
+ Windows ではテスト専用 HAI_CLI_NATIVE_BUILD=1(既定は未設定)を指定し、`pnpm --filter @h-ai/cli test:scaffold-gates -t "fullstack scaffold"` を実行できます。Rust/MSVC/Windows SDK が必要で、生成 Tauri インストーラーの exe 名にルート版 2.4.6 が反映されることを確認します。一時プロジェクトとネイティブ出力も自動削除します。