@h-ai/deploy 0.1.0-alpha.65 → 0.1.0-alpha.67

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,201 +1,138 @@
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) · [CLI](../cli/README.en.md) · [Environment and middleware](../cli/templates/skills/hai-deploy/middleware.md)
5
+ ## Introduction
6
6
 
7
- Deployment SDK used by the `hai deploy` command in `@h-ai/cli`. It also runs independently in Node.js scripts.
7
+ Deploy existing images or Vercel prebuilt output, including complete offline bundles, selected service updates, SSH automation and platform upload scripts. The SDK consumes artifacts; CLI --build explicitly orchestrates build then deployment.
8
8
 
9
- ## Features and scope
9
+ ## Core features
10
10
 
11
- | Target | Application | Operation |
12
- | ------------ | --------------------------------------------------- | ----------------------------------------------------------------------------------- |
13
- | `docker-ssh` | Native Node services or SvelteKit with adapter-node | Build locally, upload over SSH, run Compose on Linux and check HTTP health |
14
- | `vercel` | SvelteKit with adapter-vercel | Build, upload, set environment variables and wait for deployment; requires internet |
11
+ - Build, package, upload over SSH, start services and check access from one CLI command.
12
+ - Include application and self-hosted middleware images, or update selected services.
13
+ - Deliver offline tar bundles with Windows/Linux/macOS operator scripts, step results and recovery on failure.
15
14
 
16
- - Follow runtime dependencies and workspace links from the target importer in `pnpm-lock.yaml`, excluding development dependencies and peers. Application configuration selects middleware backends. Optional AI peers do not enable AI/CUDA.
17
- - Select an environment and require `.env.<mode>` before choosing defaults, custom connections or keep unchanged per middleware. Complete environments can skip all middleware processing.
18
- - Compose supports PostgreSQL, MySQL, Redis, RustFS/MinIO, Qdrant, pgvector, Chroma, OpenLDAP and Mailpit. SQLite, memory, local and LanceDB use their respective local storage. Mailpit captures test mail only.
19
- - Cloud provisioning supports Neon, Upstash, Cloudflare R2, Resend and Alibaba Cloud SMS. R2 needs existing S3 credentials, Resend a verified sender domain, and SMS approved signatures/templates. Use custom connections for other backends.
15
+ ## Getting started
20
16
 
21
- **Fullstack API and Web are separate deployments.** `hai deploy packages/my-app-serv` deploys the API only. The root template Dockerfile has `runtime` and `web` targets for API and static Web images. Upload and run Web separately, setting `PUBLIC_API_BASE` and API CORS. There is no command to publish both together, nor automatic domain, TLS or reverse proxy configuration.
17
+ ### Prepare build artifacts
22
18
 
23
- ## Command-line deployment
19
+ Projects include deployment tooling by default; use `hai create my-app --no-deploy` to opt out. The deployment SDK is a development dependency and is excluded from runtime images.
24
20
 
25
- ### 1. Install and prepare
21
+ ```sh
22
+ pnpm build
23
+ pnpm build --target docker
24
+ pnpm build --target docker --images web
25
+ pnpm build --target desktop --platform windows --arch x64
26
+ ```
27
+
28
+ #### Build options
26
29
 
27
- Node must satisfy `^22.22.2 || ^24.15.0 || >=26.0.0`; generated projects pin `pnpm@12.11.2`. Node 20 / pnpm 9.5.0 are unsupported. Use `pnpm.cmd` in Windows PowerShell.
30
+ `--target` selects compile (default), docker or desktop. `--images app|web|app,web` selects images. `--runtime auto|podman|docker` selects the local engine; auto prefers reachable Podman. `--network` overrides build networking, `--no-http-proxy` disables inherited Podman proxies, and `--sqlite-prebuild-mirror` selects a trusted HTTP(S) binary mirror. Native `--platform` and `--arch` require the matching host SDK and Rust toolchain. Builds do not load deployment environments or runtime secrets.
28
31
 
29
- In the generated workspace root, install CLI/SDK versions matching the application's framework and retain the lockfile. Installation needs a package source or complete offline dependencies:
32
+ #### Describe packaging in hai.build.json
30
33
 
31
- ```powershell
32
- pnpm.cmd add -Dw @h-ai/cli @h-ai/deploy
33
- pnpm.cmd exec hai --help
34
+ ```json
35
+ { "images": [{ "name": "app", "context": ".", "dockerfile": "images/app.Dockerfile", "containerPort": 3000 }, { "name": "web", "context": ".", "dockerfile": "images/web.Dockerfile", "containerPort": 8080 }] }
34
36
  ```
35
37
 
36
- Creation with `--features deploy` already adds the local SDK, but does not install a global `hai`. With a global CLI, run `hai deploy` directly. The template's `pnpm run deploy` packages artifacts; it does not invoke this deployment command.
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.
37
39
 
38
- For docker-ssh, prepare:
40
+ 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.
39
41
 
40
- - A running local Docker/Podman engine capable of building Linux images for the server architecture. Windows needs the corresponding virtualization/WSL2/VM environment; a client alone is insufficient. `auto` prefers Podman; Docker can be selected explicitly.
41
- - Local `ssh` and `scp`, noninteractive key/agent authentication and the server host fingerprint.
42
- - Remote Docker/Podman with its `compose` command. The SSH user must run containers and write the deployment directory. Windows must reach SSH and the exposed application port.
43
- - `config/_deploy.yml` in the target package and `.env.prod` or `.env.test` in the environment directory. Missing environment files stop deployment.
42
+ 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.
44
43
 
45
- ### 2. Configure target and environment
44
+ ### Deploy artifacts
46
45
 
47
- Minimal `config/_deploy.yml` for Docker; supply machine-specific target details through the whole-object `HAI_DEPLOY_PROVIDER` override in `.env.local`:
46
+ #### Prepare the environment and destination
47
+
48
+ Prepare `.env.<environment>` and the service config/_deploy.yml. Fullstack deploy scripts point to packages/<project>-serv; API workspaces use apps/<project>-service. Artifact lookup remains rooted at the build configuration.
48
49
 
49
50
  ```yaml
50
51
  provider:
51
52
  type: docker-ssh
53
+ expose:
54
+ hostPort: 18080
52
55
  container:
53
- runtime: docker
54
56
  s3Engine: rustfs
55
- services: {}
56
- ```
57
-
58
- Replace the host, user, ports and key path for your environment. Never commit `.env.local`:
59
-
60
- ```dotenv
61
- HAI_DEPLOY_PROVIDER='{"type":"docker-ssh","ssh":{"host":"10.0.0.20","port":22,"username":"deploy","identityFile":"C:/Users/me/.ssh/hai_deploy"},"remote":{"baseDir":"/opt/hai/apps","runtime":"docker"},"expose":{"type":"port","containerPort":3000,"hostPort":18080}}'
62
- ```
63
-
64
- Alternatively, the wizard asks for missing target details, saves them in `.env.local` and reuses them. Store private key paths only. Edit `HAI_DEPLOY_PROVIDER` to switch a complete target.
65
-
66
- Precedence: `.env` → `.env.<mode>` → `.env.local` → process environment. Parent JSON such as `HAI_DB` overrides child variables. `.env.example` documents all fields and enums. Commit `.env` and `.env.dev/test/prod`; keep real credentials in `.env.local`. Fullstack's first start also needs a private `HAI_ADMIN_DEFAULT_PASSWORD` satisfying the IAM password policy.
67
-
68
- Fullstack production also requires an explicit Web Origin in `.env.prod`, such as `HAI_SERV_CORS_ORIGIN=https://app.hai.internal`; the default `*` prevents production startup. Production refresh cookies use Secure, so Web/API need trusted HTTPS endpoints. Exposing HTTP ports alone does not validate complete login/session refresh.
69
-
70
- ### 3. Deploy
71
-
72
- From the fullstack root, replace the service directory:
73
-
74
- ```powershell
75
- pnpm.cmd exec hai deploy packages/my-app-serv --env prod --env-dir .
76
- ```
77
-
78
- The wizard shows the effective backend and purpose. Defaults generate Compose services/volumes; custom connections omit that middleware container. Keep unchanged is offered only when the target environment file explicitly declares complete configuration. Public values go to the selected environment file, credentials to `.env.local`, with redacted output.
79
-
80
- When all database, cache and storage connections are already configured:
81
-
82
- ```powershell
83
- pnpm.cmd exec hai deploy packages/my-app-serv --env prod --env-dir . --yes --skip-middleware
84
57
  ```
85
58
 
86
- `--skip-middleware` (alias `--skip-provision`) skips middleware prompts, configuration updates and resource creation; application build/deployment still run. It does not start external middleware. `--yes` alone keeps complete settings and otherwise uses the current backend defaults.
87
-
88
- `--project-name <name>` sets the name; an explicit environment adds a suffix. **`--skip-build` currently skips only Vercel application builds. docker-ssh always builds an image and has no option to deploy a specified existing image directly.** Failures return a nonzero exit code.
89
-
90
- ## docker-ssh execution and files
91
-
92
- 1. Use the target package's Dockerfile, or generate a fallback with the workspace root as context. Fullstack service packages use the fallback by default, not the root Web target.
93
- 2. Build the image locally and export a tar with `docker/podman save`.
94
- 3. Check the remote engine and Compose over SSH, upload the tar with SCP, then run `load` remotely.
95
- 4. Generate `compose.yml`, `.env.runtime` and `start-<mode>.sh` locally and upload each to `<baseDir>/<projectName>-<mode>/`. These are separate from the image archive; no single Compose bundle is uploaded and no source build runs on Linux.
96
- 5. The remote script sets `HAI_DEPLOY_ENVIRONMENT`/`HAI_CORE_ENV` and runs `compose --env-file .env.runtime ... up -d`. The SDK checks native `/health` or SvelteKit `/` from the local machine before succeeding.
97
-
98
- Local artifacts live in the target package's Git-ignored `.hai/deploy/<mode>/`. Remote `.env.runtime` uses mode `600`. Retain local artifacts for repeat deployment: keep unchanged preserves services/volumes from the previous local Compose, not arbitrary server-side Compose definitions. Exclude private environment files and deployment archives from image contexts.
99
-
100
- ## Fully offline deployment
101
-
102
- Offline means no internet; Windows and Linux must still communicate over an internal SSH/HTTP network. Vercel and cloud provisioning are unavailable.
103
-
104
- ### Materials to bring in advance
105
-
106
- | Location | Requirements |
107
- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
108
- | Windows tools | Compatible Node (for example a supported Node 24), pnpm 12.11.2, installed CLI/SDK and transitive dependencies, OpenSSH, initialized and runnable Linux container engine |
109
- | Project | Complete source, pinned lockfile, environment files and private credentials; `pnpm.cmd exec hai --help` must work offline. Avoid on-demand `npx` / `pnpm dlx` downloads |
110
- | Linux | Docker CLI/Engine, Compose plugin (`docker compose version` works), authorized SSH key, container permissions, writable deployment directory, ports and disk space. Host Node/pnpm are unnecessary for running images |
111
- | Images | API, Web and middleware images matching Linux CPU architecture and exact Compose names/tags; import with `docker load -i <archive.tar>` |
112
- | Application | PostgreSQL database/account, Redis connection/password, RustFS keys/bucket and initial administrator password. Existing services must already run and be reachable from the app container; `localhost` means that container |
59
+ The wizard asks for server address, SSH user, optional key/fingerprint files and public port using readable labels. Reuse valid settings; local connection settings go to .env.local, private keys are referenced by path. Bundle-only does not require SSH.
113
60
 
114
- Defaults use `postgres:16-alpine`, `redis:7-alpine` and `ghcr.io/rustfs/rustfs:1.0.1`. Other tags do not match automatically: import the exact images, correctly retag verified compatible images, or use custom connections. The SDK does not transfer middleware images. Other pinned images are in the [Compose implementation](src/container/deploy-container-compose.ts).
61
+ #### Configure only the middleware the application needs
115
62
 
116
- **The default source build is not ready for offline use without preparation.** Dockerfiles prepare pnpm and download packages and SQLite prebuilds; the fullstack root also runs `pnpm fetch` and uses an external Dockerfile frontend. Windows `node_modules`/pnpm store cannot replace Linux build dependencies. For offline source builds, bring Node base images, the build frontend, Corepack/pnpm, Linux dependencies and native binary caches into the local engine/build environment, adapt the Dockerfile, and rehearse with internet disconnected. `pnpm install --offline --frozen-lockfile` only addresses package-store access, not additional downloads by install scripts.
63
+ Runtime lockfile dependencies and configuration determine middleware. Choose defaults, custom connections or keep settings. --skip-middleware skips configuration/provisioning. SQLite, memory cache and local storage need no external images. Complete bundles automatically include self-hosted middleware images. External services still require reachable destinations; cloud provisioning is not an offline operation.
117
64
 
118
- SQLite prebuilds must match better-sqlite3 version, Node ABI, CPU architecture and libc. Installation may still need them when runtime uses PostgreSQL. Preload prebuild-install's Linux cache or use an internal `container.sqlitePrebuildMirror`; otherwise bring the binary or a finished image. Default fullstack needs no CUDA.
65
+ #### Deployment options
119
66
 
120
- ### Reuse prebuilt images through the SDK offline
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 selects the version-suffixed archive name. --yes uses valid settings without interaction and reports missing required values.
121
68
 
122
- Prepare finished images before delivery. For a project named `my-app` with a Web frontend, build on the server's architecture in an environment with dependencies available:
69
+ #### When the machines can connect: automatic deployment
123
70
 
124
- ```powershell
125
- docker build --target runtime -t my-app-api:offline .
126
- docker build --target web -t my-app-web:offline .
127
- docker save -o my-app-images.tar my-app-api:offline my-app-web:offline
71
+ ```sh
72
+ pnpm run deploy --env prod --build
73
+ pnpm run deploy --env prod --artifact-dir .hai/build/docker/<buildId>
74
+ pnpm run deploy --env prod --build --services web
128
75
  ```
129
76
 
130
- Import the archive into the offline Windows Linux engine with `docker load -i my-app-images.tar`. Create `packages/my-app-serv/Dockerfile` containing only:
77
+ Partial updates require a successful full server installation and matching ports/layout. Merge selected services into the server's successful baseline; preserve unselected services, settings and volumes. The deployment script first removes only the selected old containers by project and service labels, retaining their volumes. It then runs `compose up -d --no-deps --no-build --pull never --no-recreate web` to create replacements while other containers keep running, without project-wide down. storage-init is a one-time S3 bucket initialization task, executed only when storage initialization is selected.
131
78
 
132
- ```dockerfile
133
- FROM my-app-api:offline
134
- ```
79
+ Here `-d` starts in the background; `--no-deps` leaves dependencies untouched; `--no-build` prevents server builds; `--pull never` forbids registry pulls; `--no-recreate` preserves containers that still exist; the selected old containers were already removed by the script, so their replacements are created. `web` is a Compose service name, not an image tag; separate multiple services with spaces.
135
80
 
136
- Add a service-package `.dockerignore` containing `*`. This makes the SDK's mandatory build reuse the finished API without package installation. Rebuild the finished image after source changes. Configure the target, then run the deployment command above. To create middleware containers, select `HAI_DB_TYPE=postgresql`, `HAI_CACHE_TYPE=redis`, `HAI_STORAGE_TYPE=s3` in `.env.prod` and choose defaults in the wizard. For existing services, enter custom connections; once complete, `--skip-middleware` is available. The SDK uploads the API image. Rehearse with internet disconnected to confirm the builder needs no network.
81
+ `storage-init` uses the application's S3 SDK to wait for storage and create a missing bucket without deleting data. Start storage first, then run `compose up --no-deps --no-build --pull never --force-recreate --exit-code-from storage-init storage-init`. Start selected application services only after initialization exits with zero. For partial updates, the script first removes the old storage-init container and uses `--no-recreate` instead of `--force-recreate` here, preserving running application containers. Updating only `storage` still requires an artifact containing the `app` image for initialization. If the most recent build contains only Web, select the original complete artifact with `--artifact-dir`, or run `pnpm build --target docker --images app` first. This image is used for initialization without updating the running `app` service.
137
82
 
138
- Transfer the Web image separately. This example assumes separately prepared internal TLS endpoints `https://app.hai.internal` and `https://api.hai.internal`, proxying Web port 18081 and API port 18080. Bring proxy configuration/images and certificates, configure internal DNS/hosts and client certificate trust, then run over SSH:
83
+ #### When the machines cannot connect: copy a bundle
139
84
 
140
85
  ```sh
141
- docker load -i /path/to/my-app-images.tar
142
- docker run -d --name my-app-web-prod --restart unless-stopped -p 18081:8080 -e PUBLIC_API_BASE=https://api.hai.internal my-app-web:offline
86
+ pnpm run deploy --env prod --build --bundle-only --output release-prod.tar
143
87
  ```
144
88
 
145
- Use a browser-reachable API URL and set API `HAI_SERV_CORS_ORIGIN=https://app.hai.internal`. Verify API `/health`, Web login/business requests, hash-route reload, session refresh, restarts and persistence. These are preparation/adaptation instructions; online deployment tests do not prove offline acceptance.
89
+ Application 1.2.3 produces release-prod-1.2.3.tar and an adjacent -deploy/ directory. The tar includes selected application/middleware images, configurations, private environment files, checksums, README and apply.sh. Run deploy.ps1 on Windows or deploy.sh on Linux/macOS to upload using saved SSH settings and execute the same server workflow. After moving to another computer or operating system, update both the private key and known-hosts paths to files on that computer. On Windows, edit deploy-target.json; on Linux/macOS, set HAI_DEPLOY_IDENTITY_FILE and HAI_DEPLOY_KNOWN_HOSTS_FILE.
146
90
 
147
- Official references: Docker [save](https://docs.docker.com/reference/cli/docker/image/save/) / [load](https://docs.docker.com/reference/cli/docker/image/load/), [pnpm install](https://pnpm.io/cli/install), [Compose plugin installation](https://docs.docker.com/compose/install/linux/).
91
+ 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.
148
92
 
149
- ## SDK and failures
93
+ #### Before going fully offline
150
94
 
151
- Scripts do not need the CLI. Supply parsed configuration; use public `loadDeploymentEnvironment` / `loadDeploymentConfig` for the same environment resolution:
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.
152
96
 
153
- ```typescript
154
- import type { DeployConfigInput } from '@h-ai/deploy'
97
+ ### SDK
98
+
99
+ ```ts
155
100
  import { deploy } from '@h-ai/deploy'
156
101
 
157
- /**
158
- * 使用现有中间件发布生产 API,并释放部署模块。
159
- * @param config - 从部署环境解析得到的配置
160
- * @returns 初始化或部署的 HaiResult,由调用者检查 success
161
- * @example `const result = await publish(config)`
162
- */
163
- export async function publish(config: DeployConfigInput) {
164
- const initialized = await deploy.init(config)
165
- if (!initialized.success)
166
- return initialized
167
- try {
168
- return await deploy.deployApp('./packages/my-app-serv', {
169
- environment: 'prod',
170
- envDir: '.',
171
- skipProvision: true,
172
- })
173
- }
174
- finally {
175
- await deploy.close()
176
- }
102
+ const initialized = await deploy.init({ provider: { type: 'docker-ssh', expose: { hostPort: 18080 } } })
103
+ if (!initialized.success)
104
+ throw new Error(initialized.error.message)
105
+ try {
106
+ const result = await deploy.deployApp('./packages/demo-serv', {
107
+ environment: 'prod',
108
+ envDir: '.',
109
+ bundleOnly: true,
110
+ artifactDir: './.hai/build/docker/<buildId>',
111
+ runtime: 'auto',
112
+ })
113
+ if (!result.success)
114
+ throw new Error(result.error.message)
115
+ // result.data.bundlePath / instructions; packaged does not mean server ready.
116
+ }
117
+ finally {
118
+ await deploy.close()
177
119
  }
178
120
  ```
179
121
 
180
- Check `result.success` before reading `error.code/message` or `data.url/healthCheck`. `deploy.scan()` and `deploy.credentials.*()` require no initialization. `deployApp()` includes provisioning, so do not also call `provisionAll()` beforehand. Check results for manual provisioning too. SDK `skipProvision` has the CLI's skip-middleware semantics.
122
+ `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.
181
123
 
182
- Cloud provisioners return whole-object `HAI_DB`, `HAI_CACHE`, `HAI_STORAGE` or `HAI_REACH_PROVIDERS`; applications must load their YAML and initialize the modules. `getDeployRecovery(result.error)` returns stage/resource IDs; verify `unknown` outcomes in the platform before retrying. Same-name retries reuse resources without automatic deletion. Types, configuration and error codes are available through the [public entry](src/index.ts).
124
+ ## Development and testing
183
125
 
184
- ## Testing and development
185
-
186
- After installing dependencies, run from the framework root (Windows: `pnpm.cmd`):
187
-
188
- ```powershell
189
- pnpm.cmd --filter @h-ai/deploy typecheck
190
- pnpm.cmd --filter @h-ai/deploy lint
191
- pnpm.cmd --filter @h-ai/deploy build
192
- pnpm.cmd --filter @h-ai/deploy test
193
- pnpm.cmd check:skills
126
+ ```sh
127
+ pnpm --filter @h-ai/deploy typecheck
128
+ pnpm --filter @h-ai/deploy lint
129
+ pnpm --filter @h-ai/deploy build
130
+ pnpm --filter @h-ai/deploy test
131
+ pnpm --filter @h-ai/cli test:scaffold-gates
132
+ pnpm --filter @h-ai/cli test:deploy-gates
194
133
  ```
195
134
 
196
- `src/deploy-scanner.ts` handles lockfile traversal, `deploy-middleware.ts` connection fields, `container/` engines/SSH/Compose, `providers/` deployment targets and `provisioners/` cloud resources. CLI prompts live in `../cli/src/commands/cli-deploy*.ts`. Changes to backends/configuration must update consumers, environment examples, tests and the [deployment skill](../cli/templates/skills/hai-deploy/SKILL.md).
197
-
198
- For deployment changes, also run CLI typecheck/lint/build/test and `pnpm.cmd --filter @h-ai/cli test:deploy-gates`: current package archives → generated fullstack → Podman/SSH → health, environment, login and repeat deployment. This needs a local engine and OpenSSH; first fixture setup downloads images and OS/Node dependencies, so it is not an offline acceptance test. Template changes also require `pnpm.cmd --filter @h-ai/cli test:scaffold-gates`. Unit tests do not prove cloud resource creation; validate paid cloud operations separately. Keep logs/screenshots/reports in Git-ignored `tmp/` or `test-results/`.
135
+ 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.
199
136
 
200
137
  ## License
201
138