@h-ai/cli 0.1.0-alpha.58 → 0.1.0-alpha.60
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 +43 -20
- package/README.ja.md +43 -20
- package/README.md +43 -20
- package/dist/{chunk-WUSFJFW5.js → chunk-P6X63D3I.js} +64 -6
- package/dist/chunk-P6X63D3I.js.map +1 -0
- package/dist/{chunk-F4IBPVZ5.js → chunk-WWG3U5ZD.js} +20 -2
- package/dist/chunk-WWG3U5ZD.js.map +1 -0
- package/dist/cli-config-templates-EFABFSCY.js +5 -0
- package/dist/{cli-config-templates-6XA7V6CC.js.map → cli-config-templates-EFABFSCY.js.map} +1 -1
- package/dist/{cli-skill-templates-45CK4RQ2.js → cli-skill-templates-2KDUACT6.js} +3 -3
- package/dist/{cli-skill-templates-45CK4RQ2.js.map → cli-skill-templates-2KDUACT6.js.map} +1 -1
- package/dist/index.js +96 -73
- package/dist/index.js.map +1 -1
- package/package.json +9 -7
- package/templates/README.md +8 -0
- package/templates/apps/api/apps/{{projectName}}-service/README.md.hbs +12 -0
- package/templates/apps/api/apps/{{projectName}}-service/src/app.ts.hbs +4 -7
- package/templates/apps/api/apps/{{projectName}}-service/src/lib/server/init.ts.hbs +11 -1
- package/templates/apps/api/apps/{{projectName}}-service/tests/service.test.ts.hbs +2 -1
- package/templates/apps/api/e2e/api-service.spec.ts.hbs +72 -6
- package/templates/apps/api/package.json.hbs +4 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/README.md.hbs +10 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/project.inlang/settings.json.hbs +1 -1
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/README.md.hbs +10 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/project.inlang/settings.json.hbs +1 -1
- package/templates/apps/fullstack/apps/{{projectName}}-miniapp/README.md.hbs +2 -0
- package/templates/apps/fullstack/apps/{{projectName}}-miniapp/project.inlang/settings.json.hbs +1 -1
- package/templates/apps/fullstack/apps/{{projectName}}-web/README.md.hbs +10 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/project.inlang/settings.json.hbs +1 -1
- package/templates/apps/fullstack/e2e/fullstack.spec.ts.hbs +63 -1
- package/templates/apps/fullstack/packages/{{projectName}}-contract/README.md.hbs +1 -1
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/admin-contract.ts.hbs +8 -1
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/admin-schemas.ts.hbs +1 -1
- package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +10 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_iam.yml.hbs +46 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_reach.yml.hbs +21 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/admin-service.ts.hbs +1 -1
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/admin-procedures.ts.hbs +2 -2
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/runtime.ts.hbs +7 -3
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/app-server.test.ts.hbs +11 -4
- package/templates/apps/fullstack/packages/{{projectName}}-shared/README.md.hbs +12 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/en-US.json.hbs +2 -2
- package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/zh-CN.json.hbs +2 -2
- package/templates/apps/fullstack/packages/{{projectName}}-shared/package.json.hbs +1 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/project.inlang/settings.json.hbs +1 -1
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/api-client.ts.hbs +3 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AdminWorkspace.svelte.hbs +32 -23
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/ProfileSettings.svelte.hbs +24 -24
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/UserManagement.svelte.hbs +1 -1
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/management-store.svelte.ts.hbs +20 -20
- package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/management-store.test.ts.hbs +7 -8
- package/templates/apps/mobile-app/src/App.svelte.hbs +43 -0
- package/templates/base/e2e/app.spec.ts.hbs +105 -0
- package/templates/base/package.json.hbs +1 -1
- package/templates/base/src/hooks.server.ts.hbs +2 -2
- package/templates/base/src/lib/server/init.ts.hbs +1 -1
- package/templates/base/src/routes/+layout.server.ts.hbs +6 -0
- package/templates/base/tests/scaffold.test.ts.hbs +3 -0
- package/templates/base/vite.config.ts.hbs +1 -0
- package/templates/features/iam/routes-admin/(auth)/+layout.svelte.hbs +2 -16
- package/templates/features/iam/routes-admin/(auth)/auth/forgot-password/+page.svelte.hbs +10 -0
- package/templates/features/iam/routes-admin/(auth)/auth/login/+page.svelte.hbs +6 -95
- package/templates/features/iam/routes-admin/(auth)/auth/register/+page.svelte.hbs +6 -117
- package/templates/features/iam/routes-admin/(auth)/auth/reset-password/+page.svelte.hbs +10 -0
- package/templates/features/iam/routes-h5/auth/forgot-password/+page.svelte.hbs +10 -0
- package/templates/features/iam/routes-h5/auth/login/+page.svelte.hbs +6 -97
- package/templates/features/iam/routes-h5/auth/register/+page.svelte.hbs +6 -112
- package/templates/features/iam/routes-h5/auth/reset-password/+page.svelte.hbs +10 -0
- package/templates/features/iam/routes-shared/api/auth/config/+server.ts +4 -0
- package/templates/features/iam/routes-shared/api/auth/login/+server.ts +1 -33
- package/templates/features/iam/routes-shared/api/auth/login/ldap/+server.ts +4 -0
- package/templates/features/iam/routes-shared/api/auth/login/otp/+server.ts +4 -0
- package/templates/features/iam/routes-shared/api/auth/otp/send/+server.ts +4 -0
- package/templates/features/iam/routes-shared/api/auth/password-reset/confirm/+server.ts +4 -0
- package/templates/features/iam/routes-shared/api/auth/password-reset/request/+server.ts +4 -0
- package/templates/features/iam/routes-shared/api/auth/register/+server.ts +1 -23
- package/templates/features/iam/routes-website/auth/forgot-password/+page.svelte.hbs +10 -0
- package/templates/features/iam/routes-website/auth/login/+page.svelte.hbs +11 -0
- package/templates/features/iam/routes-website/auth/register/+page.svelte.hbs +11 -0
- package/templates/features/iam/routes-website/auth/reset-password/+page.svelte.hbs +10 -0
- package/templates/skills/hai-api-client/SKILL.md +5 -0
- package/templates/skills/hai-app-create/SKILL.md +2 -0
- package/templates/skills/hai-app-create/development.md +15 -0
- package/templates/skills/hai-deploy/SKILL.md +2 -0
- package/templates/skills/hai-framework-sync/SKILL.md +4 -0
- package/templates/skills/hai-iam/SKILL.md +9 -2
- package/templates/skills/hai-iam/reference.md +76 -11
- package/templates/skills/hai-reach/SKILL.md +2 -0
- package/templates/skills/hai-ui/reference.md +45 -0
- package/dist/chunk-F4IBPVZ5.js.map +0 -1
- package/dist/chunk-WUSFJFW5.js.map +0 -1
- package/dist/cli-config-templates-6XA7V6CC.js +0 -5
package/README.en.md
CHANGED
|
@@ -41,15 +41,30 @@ Delivery checks cover both the package archive and generated projects. Source `.
|
|
|
41
41
|
|
|
42
42
|
Requires Node.js 22.22.2+ / 24.15.0+ / 26+; generated root projects and workspace packages declare the same minimum.
|
|
43
43
|
|
|
44
|
+
### Install the CLI
|
|
45
|
+
|
|
46
|
+
First install `@h-ai/cli` globally. It provides the `hai` command; the quick-start examples below assume this installation is complete.
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pnpm add -g @h-ai/cli
|
|
50
|
+
hai --version
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
In PowerShell, use `pnpm.cmd add -g @h-ai/cli`. To update an installed CLI to the current published version, run the same installation command. Check available commands with `hai --help`. For unpublished templates, follow the local development section below to build and run the CLI from this repository.
|
|
54
|
+
|
|
44
55
|
### Create a project
|
|
45
56
|
|
|
57
|
+
Generated `@h-ai/*` dependencies are pinned to the CLI version; pnpm references that exact version through `catalog:`. Upgrade framework packages together and verify the versions resolved in the lockfile.
|
|
58
|
+
|
|
59
|
+
Creation messages are written directly to the terminal. Installation failures display the package manager command, exit code and stdout/stderr, and retain generated files for a retry from the project directory. The `prebuild-install@7.1.3` deprecation warning comes from the upstream `better-sqlite3` installer dependency. That warning alone does not fail installation; do not override or remove the native installer to hide it.
|
|
60
|
+
|
|
46
61
|
```bash
|
|
47
62
|
# 交互式创建(推荐)
|
|
48
|
-
|
|
63
|
+
hai create my-admin-app
|
|
49
64
|
|
|
50
65
|
# 指定模板与功能
|
|
51
|
-
|
|
52
|
-
|
|
66
|
+
hai create my-app -t full
|
|
67
|
+
hai create my-app -t custom -f iam,db,ai
|
|
53
68
|
```
|
|
54
69
|
|
|
55
70
|
Interactive steps:
|
|
@@ -66,11 +81,11 @@ Interactive steps:
|
|
|
66
81
|
|
|
67
82
|
```bash
|
|
68
83
|
# 交互式选择
|
|
69
|
-
|
|
84
|
+
hai add
|
|
70
85
|
|
|
71
86
|
# 指定模块
|
|
72
|
-
|
|
73
|
-
|
|
87
|
+
hai add iam
|
|
88
|
+
hai add storage
|
|
74
89
|
```
|
|
75
90
|
|
|
76
91
|
Add modules incrementally to an existing project. The CLI updates `package.json`, creates configuration, and resolves dependencies.
|
|
@@ -79,10 +94,10 @@ Add modules incrementally to an existing project. The CLI updates `package.json`
|
|
|
79
94
|
|
|
80
95
|
```bash
|
|
81
96
|
# 校验配置完整性,补全缺失配置
|
|
82
|
-
|
|
97
|
+
hai init
|
|
83
98
|
|
|
84
99
|
# 强制重新生成所有配置
|
|
85
|
-
|
|
100
|
+
hai init --force
|
|
86
101
|
```
|
|
87
102
|
|
|
88
103
|
### Code generation
|
|
@@ -93,20 +108,20 @@ Page/API generators target SvelteKit; components use Svelte 5 children snippets.
|
|
|
93
108
|
|
|
94
109
|
```bash
|
|
95
110
|
# 交互式生成
|
|
96
|
-
|
|
111
|
+
hai generate
|
|
97
112
|
|
|
98
113
|
# 指定类型
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
114
|
+
hai generate page users
|
|
115
|
+
hai generate component UserCard
|
|
116
|
+
hai generate api users
|
|
117
|
+
hai generate model user
|
|
118
|
+
hai generate migration add-users
|
|
104
119
|
|
|
105
120
|
# 快捷命令
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
121
|
+
hai g:page dashboard
|
|
122
|
+
hai g:component StatusBadge
|
|
123
|
+
hai g:api orders
|
|
124
|
+
hai g:model order
|
|
110
125
|
```
|
|
111
126
|
|
|
112
127
|
## Project templates
|
|
@@ -123,7 +138,7 @@ npx hai g:model order
|
|
|
123
138
|
`--type fullstack` generates an administration workspace with IAM, reldb, cache, audit, storage and crypto by default. The required management modules remain enabled even with the minimal preset. `--frontends` selects Web, Capacitor App and Tauri Desktop; miniapp remains a documentation placeholder excluded from runtime and builds.
|
|
124
139
|
|
|
125
140
|
```powershell
|
|
126
|
-
|
|
141
|
+
hai create mini-admin --type fullstack --frontends web,app,desktop
|
|
127
142
|
cd mini-admin
|
|
128
143
|
pnpm.cmd install
|
|
129
144
|
pnpm.cmd dev
|
|
@@ -212,7 +227,15 @@ Projects in `apps/*` reference local packages through `workspace:*` and can use
|
|
|
212
227
|
node packages/cli/dist/index.js create ../my-new-project
|
|
213
228
|
```
|
|
214
229
|
|
|
215
|
-
|
|
230
|
+
## 5. Configuration driven authentication
|
|
231
|
+
|
|
232
|
+
Agreements support configuration-loaded userAgreementMarkdown/privacyPolicyMarkdown and URLs. Markdown takes priority for the same agreement and is safely rendered in a modal.
|
|
233
|
+
|
|
234
|
+
Admin/H5/website templates with IAM include AuthPanel and standard routes; mobile and fullstack clients share API actions. Server config/_iam.yml controls methods, registration, recovery, agreement modals and branding. LDAP/Reach are optional: install ldapts only for the default LDAP client, then enable login.ldap and set connection settings. Email/SMS use Reach templates or custom callbacks. Forms expose header/extraFields/footer snippets and AuthPanel forwards login*/register* snippets. Multiple nodes share a database and Redis.
|
|
235
|
+
|
|
236
|
+
[完整 IAM 配置 / IAM configuration](../iam/README.en.md)
|
|
237
|
+
|
|
238
|
+
### 6. Run tests
|
|
216
239
|
|
|
217
240
|
```bash
|
|
218
241
|
# 单元测试 + E2E 模板生成测试
|
package/README.ja.md
CHANGED
|
@@ -41,15 +41,30 @@ AI ファイルの書き込み前に既存のファイル・ディレクトリ
|
|
|
41
41
|
|
|
42
42
|
Node.js 22.22.2+ / 24.15.0+ / 26+ が必要です。生成するルートプロジェクトと各 workspace パッケージも同じ最低バージョンを宣言します。
|
|
43
43
|
|
|
44
|
+
### CLI のインストール
|
|
45
|
+
|
|
46
|
+
まず `@h-ai/cli` をグローバルにインストールします。このパッケージが `hai` コマンドを提供します。以下のクイックスタートの例はインストール完了を前提としています。
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pnpm add -g @h-ai/cli
|
|
50
|
+
hai --version
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
PowerShell では `pnpm.cmd add -g @h-ai/cli` を使用してください。同じインストールコマンドで、既存の CLI を現在公開されているバージョンに更新できます。利用可能なコマンドは `hai --help` で確認します。未公開のテンプレートは、後述のローカル開発手順に従って本リポジトリーの CLI をビルドして実行してください。
|
|
54
|
+
|
|
44
55
|
### プロジェクトの作成
|
|
45
56
|
|
|
57
|
+
生成する `@h-ai/*` 依存は CLI と同じバージョンに固定し、pnpm は `catalog:` からその完全なバージョンを参照します。更新時はフレームワークのパッケージをまとめて更新し、lockfile の実際の解決バージョンを確認してください。
|
|
58
|
+
|
|
59
|
+
作成メッセージは端末へ直接出力します。依存のインストールが失敗した場合は、コマンド、終了コード、stdout/stderr を表示し、生成したファイルを残します。プロジェクト内でインストールを再実行できます。`prebuild-install@7.1.3` の非推奨警告は `better-sqlite3` の上流インストーラー依存によるものです。この警告だけではインストールは失敗しません。警告を隠すためにネイティブインストーラーを上書き・削除しないでください。
|
|
60
|
+
|
|
46
61
|
```bash
|
|
47
62
|
# 交互式创建(推荐)
|
|
48
|
-
|
|
63
|
+
hai create my-admin-app
|
|
49
64
|
|
|
50
65
|
# 指定模板与功能
|
|
51
|
-
|
|
52
|
-
|
|
66
|
+
hai create my-app -t full
|
|
67
|
+
hai create my-app -t custom -f iam,db,ai
|
|
53
68
|
```
|
|
54
69
|
|
|
55
70
|
対話式の手順:
|
|
@@ -66,11 +81,11 @@ npx hai create my-app -t custom -f iam,db,ai
|
|
|
66
81
|
|
|
67
82
|
```bash
|
|
68
83
|
# 交互式选择
|
|
69
|
-
|
|
84
|
+
hai add
|
|
70
85
|
|
|
71
86
|
# 指定模块
|
|
72
|
-
|
|
73
|
-
|
|
87
|
+
hai add iam
|
|
88
|
+
hai add storage
|
|
74
89
|
```
|
|
75
90
|
|
|
76
91
|
既存プロジェクトにモジュールを追加します。`package.json` の更新、設定生成、依存解決を自動実行します。
|
|
@@ -79,10 +94,10 @@ npx hai add storage
|
|
|
79
94
|
|
|
80
95
|
```bash
|
|
81
96
|
# 校验配置完整性,补全缺失配置
|
|
82
|
-
|
|
97
|
+
hai init
|
|
83
98
|
|
|
84
99
|
# 强制重新生成所有配置
|
|
85
|
-
|
|
100
|
+
hai init --force
|
|
86
101
|
```
|
|
87
102
|
|
|
88
103
|
### コード生成
|
|
@@ -93,20 +108,20 @@ npx hai init --force
|
|
|
93
108
|
|
|
94
109
|
```bash
|
|
95
110
|
# 交互式生成
|
|
96
|
-
|
|
111
|
+
hai generate
|
|
97
112
|
|
|
98
113
|
# 指定类型
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
114
|
+
hai generate page users
|
|
115
|
+
hai generate component UserCard
|
|
116
|
+
hai generate api users
|
|
117
|
+
hai generate model user
|
|
118
|
+
hai generate migration add-users
|
|
104
119
|
|
|
105
120
|
# 快捷命令
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
121
|
+
hai g:page dashboard
|
|
122
|
+
hai g:component StatusBadge
|
|
123
|
+
hai g:api orders
|
|
124
|
+
hai g:model order
|
|
110
125
|
```
|
|
111
126
|
|
|
112
127
|
## プロジェクトテンプレート
|
|
@@ -123,7 +138,7 @@ npx hai g:model order
|
|
|
123
138
|
`--type fullstack` は IAM、reldb、cache、audit、storage、crypto を含む管理 workspace を既定で生成します。minimal を選んでも管理に必要なモジュールは有効です。`--frontends` で Web、Capacitor App、Tauri Desktop を選択します。miniapp は説明用のプレースホルダーで、実行・ビルド対象には含まれません。
|
|
124
139
|
|
|
125
140
|
```powershell
|
|
126
|
-
|
|
141
|
+
hai create mini-admin --type fullstack --frontends web,app,desktop
|
|
127
142
|
cd mini-admin
|
|
128
143
|
pnpm.cmd install
|
|
129
144
|
pnpm.cmd dev
|
|
@@ -212,7 +227,15 @@ hai create my-app
|
|
|
212
227
|
node packages/cli/dist/index.js create ../my-new-project
|
|
213
228
|
```
|
|
214
229
|
|
|
215
|
-
|
|
230
|
+
## 5. 設定による認証画面
|
|
231
|
+
|
|
232
|
+
規約は設定の userAgreementMarkdown/privacyPolicyMarkdown または URL を使用できます。同じ規約は Markdown 本文を優先して安全な Modal で描画します。
|
|
233
|
+
|
|
234
|
+
IAM を選択した admin/h5/website は AuthPanel と標準 route を生成し、mobile と fullstack は API actions を共用します。サーバーの _iam.yml で認証方式、登録、復旧、規約 Modal、ブランドを設定します。LDAP/Reach は任意です。既定 LDAP クライアントを使用する時だけ ldapts をインストールし、login.ldap と接続設定を指定します。メール/SMS は Reach テンプレートまたは独自コールバックを使用します。フォームは header/extraFields/footer、AuthPanel は login*/register* snippet を提供します。複数ノードは DB と Redis を共有します。
|
|
235
|
+
|
|
236
|
+
[完整 IAM 配置 / IAM configuration](../iam/README.ja.md)
|
|
237
|
+
|
|
238
|
+
### 6. テスト実行
|
|
216
239
|
|
|
217
240
|
```bash
|
|
218
241
|
# 单元测试 + E2E 模板生成测试
|
package/README.md
CHANGED
|
@@ -41,15 +41,30 @@ AI 文件写入前会解析已有文件和目录链接;共享技能与项目
|
|
|
41
41
|
|
|
42
42
|
要求 Node.js 22.22.2+ / 24.15.0+ / 26+;生成的根项目和工作区包均声明相同最低版本。
|
|
43
43
|
|
|
44
|
+
### 安装 CLI
|
|
45
|
+
|
|
46
|
+
先全局安装 `@h-ai/cli`,它提供 `hai` 命令;以下快速开始示例均以完成安装为前提。
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
pnpm add -g @h-ai/cli
|
|
50
|
+
hai --version
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
PowerShell 中使用 `pnpm.cmd add -g @h-ai/cli`。已安装 CLI 时,执行相同安装命令可更新到当前发布版本;使用 `hai --help` 核对可用命令。仓库内未发布的模板按下方“开发阶段本地使用”构建并运行。
|
|
54
|
+
|
|
44
55
|
### 创建项目
|
|
45
56
|
|
|
57
|
+
生成项目的 `@h-ai/*` 依赖固定为 CLI 对应版本;pnpm 通过 `catalog:` 引用该精确版本。升级时统一更新框架包并验证 lockfile 中实际解析的版本。
|
|
58
|
+
|
|
59
|
+
创建提示直接输出到终端;安装失败会显示包管理器命令、退出码和 stdout/stderr,已生成文件保留,可进入目录重试安装。`prebuild-install@7.1.3` 的弃用警告来自 `better-sqlite3` 的上游安装依赖,单独的警告不会令安装失败;不要为隐藏警告覆盖或删除原生安装器。
|
|
60
|
+
|
|
46
61
|
```bash
|
|
47
62
|
# 交互式创建(推荐)
|
|
48
|
-
|
|
63
|
+
hai create my-admin-app
|
|
49
64
|
|
|
50
65
|
# 指定模板与功能
|
|
51
|
-
|
|
52
|
-
|
|
66
|
+
hai create my-app -t full
|
|
67
|
+
hai create my-app -t custom -f iam,db,ai
|
|
53
68
|
```
|
|
54
69
|
|
|
55
70
|
交互流程:
|
|
@@ -66,11 +81,11 @@ npx hai create my-app -t custom -f iam,db,ai
|
|
|
66
81
|
|
|
67
82
|
```bash
|
|
68
83
|
# 交互式选择
|
|
69
|
-
|
|
84
|
+
hai add
|
|
70
85
|
|
|
71
86
|
# 指定模块
|
|
72
|
-
|
|
73
|
-
|
|
87
|
+
hai add iam
|
|
88
|
+
hai add storage
|
|
74
89
|
```
|
|
75
90
|
|
|
76
91
|
向现有项目增量添加模块。自动更新 `package.json`、生成配置文件、解析依赖。
|
|
@@ -79,10 +94,10 @@ npx hai add storage
|
|
|
79
94
|
|
|
80
95
|
```bash
|
|
81
96
|
# 校验配置完整性,补全缺失配置
|
|
82
|
-
|
|
97
|
+
hai init
|
|
83
98
|
|
|
84
99
|
# 强制重新生成所有配置
|
|
85
|
-
|
|
100
|
+
hai init --force
|
|
86
101
|
```
|
|
87
102
|
|
|
88
103
|
### 代码生成
|
|
@@ -93,20 +108,20 @@ npx hai init --force
|
|
|
93
108
|
|
|
94
109
|
```bash
|
|
95
110
|
# 交互式生成
|
|
96
|
-
|
|
111
|
+
hai generate
|
|
97
112
|
|
|
98
113
|
# 指定类型
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
114
|
+
hai generate page users
|
|
115
|
+
hai generate component UserCard
|
|
116
|
+
hai generate api users
|
|
117
|
+
hai generate model user
|
|
118
|
+
hai generate migration add-users
|
|
104
119
|
|
|
105
120
|
# 快捷命令
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
121
|
+
hai g:page dashboard
|
|
122
|
+
hai g:component StatusBadge
|
|
123
|
+
hai g:api orders
|
|
124
|
+
hai g:model order
|
|
110
125
|
```
|
|
111
126
|
|
|
112
127
|
## 项目模板
|
|
@@ -123,7 +138,7 @@ npx hai g:model order
|
|
|
123
138
|
`--type fullstack` 默认生成包含 IAM、reldb、cache、audit、storage、crypto 的管理工程;即使选择 minimal,管理所需模块也会保留。`--frontends` 选择 Web、Capacitor App 和 Tauri Desktop;miniapp 仍是说明占位,不参与运行或构建。
|
|
124
139
|
|
|
125
140
|
```powershell
|
|
126
|
-
|
|
141
|
+
hai create mini-admin --type fullstack --frontends web,app,desktop
|
|
127
142
|
cd mini-admin
|
|
128
143
|
pnpm.cmd install
|
|
129
144
|
pnpm.cmd dev
|
|
@@ -212,7 +227,15 @@ monorepo 内的 `apps/*` 项目已通过 `workspace:*` 协议引用本地包,
|
|
|
212
227
|
node packages/cli/dist/index.js create ../my-new-project
|
|
213
228
|
```
|
|
214
229
|
|
|
215
|
-
|
|
230
|
+
## 5. 配置驱动认证页面
|
|
231
|
+
|
|
232
|
+
协议支持配置中的 userAgreementMarkdown/privacyPolicyMarkdown 正文及 URL;同主题优先 Markdown,由安全渲染器在弹窗显示。
|
|
233
|
+
|
|
234
|
+
选用 IAM 的 admin/h5/website 模板提供 AuthPanel 和标准认证路由;mobile-app 与 fullstack Web/App/Desktop 使用 API 客户端共享动作。修改服务端 config/_iam.yml 控制登录方式、注册、重置、协议弹窗和品牌。LDAP/Reach 均可选:默认 LDAP 客户端需要应用安装 ldapts,再启用 login.ldap 并配置连接;短信/邮件可选择 Reach 模板或自定义发送回调。表单预留 header/extraFields/footer,AuthPanel 透传 login*/register* snippet。分布式部署使用共享数据库与 Redis。
|
|
235
|
+
|
|
236
|
+
[完整 IAM 配置 / IAM configuration](../iam/README.md)
|
|
237
|
+
|
|
238
|
+
### 6. 运行测试
|
|
216
239
|
|
|
217
240
|
```bash
|
|
218
241
|
# 单元测试 + E2E 模板生成测试
|
|
@@ -170,6 +170,52 @@ login:
|
|
|
170
170
|
otp: ${loginOtp}
|
|
171
171
|
ldap: false
|
|
172
172
|
|
|
173
|
+
# \u6CE8\u518C\u4E0E\u767B\u5F55\u5B89\u5168
|
|
174
|
+
register:
|
|
175
|
+
enabled: true
|
|
176
|
+
defaultEnabled: true
|
|
177
|
+
security:
|
|
178
|
+
maxLoginAttempts: 5
|
|
179
|
+
lockoutDuration: 900
|
|
180
|
+
|
|
181
|
+
# LDAP \u53EF\u9009\uFF1A\u5B89\u88C5 ldapts \u540E\u5F00\u542F login.ldap\uFF0C\u5E76\u58F0\u660E ldap \u8FDE\u63A5\u914D\u7F6E\uFF1B\u4E5F\u53EF\u6CE8\u5165\u5DE5\u5382\u3002
|
|
182
|
+
# OTP \u9700\u542F\u7528 login.otp\uFF0C\u5E76\u9009\u62E9 Reach \u6807\u51C6\u6A21\u677F\u6216\u81EA\u5B9A\u4E49\u53D1\u9001\u56DE\u8C03\u3002
|
|
183
|
+
otp:
|
|
184
|
+
email: true
|
|
185
|
+
sms: true
|
|
186
|
+
length: 6
|
|
187
|
+
expiresIn: 300
|
|
188
|
+
maxAttempts: 3
|
|
189
|
+
resendInterval: 60
|
|
190
|
+
passwordReset:
|
|
191
|
+
enabled: true
|
|
192
|
+
mode: email # phone \u4F7F\u7528 password_reset_sms \u6A21\u677F
|
|
193
|
+
tokenExpiresIn: 3600
|
|
194
|
+
maxAttempts: 3
|
|
195
|
+
# resetUrl: https://example.com/auth/reset-password
|
|
196
|
+
agreements:
|
|
197
|
+
showOnRegister: true
|
|
198
|
+
showOnLogin: false
|
|
199
|
+
# \u7528 | \u914D\u7F6E Markdown \u6B63\u6587\uFF1B\u540C\u4E3B\u9898\u540C\u65F6\u63D0\u4F9B URL \u65F6\u4F18\u5148\u663E\u793A\u6B63\u6587\u3002
|
|
200
|
+
userAgreementMarkdown: |
|
|
201
|
+
# \u7528\u6237\u534F\u8BAE\u793A\u4F8B
|
|
202
|
+
|
|
203
|
+
\u8BF7\u59A5\u5584\u4FDD\u7BA1\u8D26\u6237\u51ED\u636E\uFF0C\u5E76\u6309\u5E94\u7528\u63D0\u4F9B\u7684\u529F\u80FD\u4F7F\u7528\u670D\u52A1\u3002
|
|
204
|
+
privacyPolicyMarkdown: |
|
|
205
|
+
# \u9690\u79C1\u653F\u7B56\u793A\u4F8B
|
|
206
|
+
|
|
207
|
+
\u6CE8\u518C\u8D44\u6599\u7528\u4E8E\u8D26\u6237\u7BA1\u7406\uFF0C\u4F1A\u8BDD\u4FE1\u606F\u7528\u4E8E\u8EAB\u4EFD\u8BA4\u8BC1\u3002
|
|
208
|
+
# userAgreementUrl: https://example.com/terms
|
|
209
|
+
# privacyPolicyUrl: https://example.com/privacy
|
|
210
|
+
ui:
|
|
211
|
+
variant: card
|
|
212
|
+
# title: Account center
|
|
213
|
+
# subtitle: Welcome back
|
|
214
|
+
# brandTitle: Your application
|
|
215
|
+
# brandText: Sign in securely
|
|
216
|
+
# logoUrl: /logo.svg
|
|
217
|
+
# illustrationUrl: /auth-illustration.svg
|
|
218
|
+
|
|
173
219
|
# \u5BC6\u7801\u7B56\u7565
|
|
174
220
|
password:
|
|
175
221
|
minLength: 8
|
|
@@ -594,12 +640,24 @@ providers:
|
|
|
594
640
|
# accessKeySecret: \${HAI_REACH_SMS_SECRET_KEY}
|
|
595
641
|
# signName: MyApp
|
|
596
642
|
|
|
597
|
-
# \u6A21\u677F\
|
|
643
|
+
# IAM \u6807\u51C6\u6A21\u677F\uFF1A\u4FDD\u7559\u7A7A\u6570\u7EC4\u4EE5\u652F\u6301 HAI_REACH_TEMPLATES \u6574\u4F53\u8986\u76D6\u3002
|
|
644
|
+
templates: []
|
|
645
|
+
# \u5F00\u542F\u5BF9\u5E94 Provider \u540E\uFF0C\u5C06\u7A7A\u6570\u7EC4\u66FF\u6362\u4E3A\u9700\u8981\u7684\u6A21\u677F\u5217\u8868\uFF0C\u4F8B\u5982\uFF1A
|
|
598
646
|
# templates:
|
|
599
|
-
# - name:
|
|
647
|
+
# - name: otp_email
|
|
648
|
+
# provider: email
|
|
649
|
+
# subject: "Verification code"
|
|
650
|
+
# body: "Your verification code is {code}."
|
|
651
|
+
# - name: otp_sms
|
|
652
|
+
# provider: sms
|
|
653
|
+
# body: "Your verification code is {code}."
|
|
654
|
+
# - name: password_reset
|
|
600
655
|
# provider: email
|
|
601
|
-
# subject: "
|
|
602
|
-
# body: "
|
|
656
|
+
# subject: "Password reset"
|
|
657
|
+
# body: "Reset your password: {resetUrl}. Expires at {expiresAt}."
|
|
658
|
+
# - name: password_reset_sms
|
|
659
|
+
# provider: sms
|
|
660
|
+
# body: "Reset your password: {resetUrl}. Expires at {expiresAt}."
|
|
603
661
|
|
|
604
662
|
# \u514D\u6253\u6270\uFF08\u53EF\u9009\uFF09
|
|
605
663
|
# dnd:
|
|
@@ -677,5 +735,5 @@ function generatePaymentConfig() {
|
|
|
677
735
|
}
|
|
678
736
|
|
|
679
737
|
export { generateConfigFile, generateEnvExample };
|
|
680
|
-
//# sourceMappingURL=chunk-
|
|
681
|
-
//# sourceMappingURL=chunk-
|
|
738
|
+
//# sourceMappingURL=chunk-P6X63D3I.js.map
|
|
739
|
+
//# sourceMappingURL=chunk-P6X63D3I.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/cli-config-templates.ts"],"names":[],"mappings":"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","file":"chunk-P6X63D3I.js","sourcesContent":["/**\n * @h-ai/cli — 配置文件模板\n *\n * 为各模块生成默认配置文件内容。\n * @module cli-config-templates\n */\n\nimport type { AiModuleConfig, CacheModuleConfig, CoreModuleConfig, DbModuleConfig, FeatureId, IamModuleConfig, ModuleConfigs, StorageModuleConfig } from '../cli-types.js'\nimport { stringify } from 'yaml'\n\n/**\n * 生成模块配置文件内容\n *\n * @param moduleKey - 模块标识(core/serv/db/cache/iam/storage/ai)\n * @param configs - 用户自定义配置值\n * @returns YAML 格式的配置内容\n */\nexport function generateConfigFile(moduleKey: string, configs?: ModuleConfigs): string {\n switch (moduleKey) {\n case 'core':\n return generateCoreConfig(configs?.core)\n case 'serv':\n return generateServConfig()\n case 'db':\n return generateDbConfig(configs?.db)\n case 'cache':\n return generateCacheConfig(configs?.cache)\n case 'iam':\n return generateIamConfig(configs?.iam)\n case 'storage':\n return generateStorageConfig(configs?.storage)\n case 'ai':\n return generateAiConfig(configs?.ai)\n case 'deploy':\n return generateDeployConfig()\n case 'vecdb':\n return generateVecdbConfig()\n case 'reach':\n return generateReachConfig()\n case 'scheduler':\n return generateSchedulerConfig()\n case 'audit':\n return generateAuditConfig()\n case 'payment':\n return generatePaymentConfig()\n default:\n return `# ${moduleKey} 配置\\n`\n }\n}\n\nfunction generateCoreConfig(cfg?: CoreModuleConfig): string {\n const name = cfg?.name ?? 'my-app'\n const locale = cfg?.defaultLocale ?? 'zh-CN'\n const supportedLocales = locale === 'en-US'\n ? ` - en-US\\n - zh-CN`\n : ` - zh-CN\\n - en-US`\n\n return `# =============================================================================\n# 应用配置\n# =============================================================================\n\n${stringify({ name }).trim()}\nversion: 0.1.0\nenv: development\ndebug: false\n\nlogging:\n level: info\n format: json\n redact:\n - password\n - token\n - secret\n\ndefaultLocale: ${locale}\nsupportedLocales:\n${supportedLocales}\n`\n}\n\nfunction generateServConfig(): string {\n return `# =============================================================================\n# Service / HTTP 入口配置\n# =============================================================================\n\nhttp:\n apiPrefix: /api/v1\n openapi:\n path: /openapi.json\n docs:\n path: /docs\n health:\n path: /health\n readyPath: /ready\n rpc: false\n\n# 开发期默认关闭 transport;启用 @h-ai/crypto 后可按需改为对象配置\ntransport: false\n`\n}\n\nfunction generateDbConfig(cfg?: DbModuleConfig): string {\n const dbType = cfg?.type ?? 'sqlite'\n const database = cfg?.database ?? (dbType === 'sqlite' ? './data/app.db' : 'hai')\n const host = cfg?.host ?? 'localhost'\n const port = cfg?.port ?? (dbType === 'postgresql' ? 5432 : 3306)\n\n if (dbType === 'sqlite') {\n return `# =============================================================================\n# 数据库配置\n# =============================================================================\n\n# 数据库类型: sqlite | postgresql | mysql\ntype: sqlite\n\n# SQLite 数据库路径\ndatabase: ${database}\n\n# PostgreSQL/MySQL 配置(可选)\n# host: localhost\n# port: 5432\n# user: postgres\n# password: ''\n`\n }\n\n const user = dbType === 'postgresql' ? 'postgres' : 'root'\n\n return `# =============================================================================\n# 数据库配置\n# =============================================================================\n\n# 数据库类型: sqlite | postgresql | mysql\ntype: ${dbType}\n\n# 数据库名称\ndatabase: ${database}\n\n# 连接配置\nhost: ${host}\nport: ${port}\nuser: ${user}\npassword: ''\n`\n}\n\nfunction generateCacheConfig(cfg?: CacheModuleConfig): string {\n const cacheType = cfg?.type ?? 'memory'\n\n if (cacheType === 'memory') {\n return `# =============================================================================\n# 缓存配置\n# =============================================================================\n\n# 缓存类型: memory | redis\ntype: memory\n\n# Redis 配置(当 type 为 redis 时使用)\n# url: redis://localhost:6379/0\n# host: localhost\n# port: 6379\n# password: ''\n# keyPrefix: 'hai:'\n`\n }\n\n const host = cfg?.host ?? 'localhost'\n const port = cfg?.port ?? 6379\n\n return `# =============================================================================\n# 缓存配置\n# =============================================================================\n\n# 缓存类型: memory | redis\ntype: redis\n\n# Redis 配置\nhost: ${host}\nport: ${port}\npassword: ''\nkeyPrefix: 'hai:'\n`\n}\n\nfunction generateIamConfig(cfg?: IamModuleConfig): string {\n const loginPassword = cfg?.loginPassword ?? true\n const loginOtp = cfg?.loginOtp ?? false\n\n return `# =============================================================================\n# IAM 配置\n# =============================================================================\n\n# 登录配置\nlogin:\n password: ${loginPassword}\n otp: ${loginOtp}\n ldap: false\n\n# 注册与登录安全\nregister:\n enabled: true\n defaultEnabled: true\nsecurity:\n maxLoginAttempts: 5\n lockoutDuration: 900\n\n# LDAP 可选:安装 ldapts 后开启 login.ldap,并声明 ldap 连接配置;也可注入工厂。\n# OTP 需启用 login.otp,并选择 Reach 标准模板或自定义发送回调。\notp:\n email: true\n sms: true\n length: 6\n expiresIn: 300\n maxAttempts: 3\n resendInterval: 60\npasswordReset:\n enabled: true\n mode: email # phone 使用 password_reset_sms 模板\n tokenExpiresIn: 3600\n maxAttempts: 3\n # resetUrl: https://example.com/auth/reset-password\nagreements:\n showOnRegister: true\n showOnLogin: false\n # 用 | 配置 Markdown 正文;同主题同时提供 URL 时优先显示正文。\n userAgreementMarkdown: |\n # 用户协议示例\n\n 请妥善保管账户凭据,并按应用提供的功能使用服务。\n privacyPolicyMarkdown: |\n # 隐私政策示例\n\n 注册资料用于账户管理,会话信息用于身份认证。\n # userAgreementUrl: https://example.com/terms\n # privacyPolicyUrl: https://example.com/privacy\nui:\n variant: card\n # title: Account center\n # subtitle: Welcome back\n # brandTitle: Your application\n # brandText: Sign in securely\n # logoUrl: /logo.svg\n # illustrationUrl: /auth-illustration.svg\n\n# 密码策略\npassword:\n minLength: 8\n maxLength: 128\n requireUppercase: false\n requireLowercase: false\n requireNumber: false\n requireSpecialChar: false\n\n# 会话配置\nsession:\n maxAge: 86400 # 会话超时(秒),默认 24 小时\n sliding: true # 滑动窗口(每次请求刷新过期时间)\n singleDevice: false # 单设备登录\n refreshTokenMaxAge: 604800 # refreshToken 过期(秒),默认 7 天\n\n# RBAC 配置\nrbac:\n defaultRole: user\n\n# 是否自动创建默认数据\nseedDefaultData: true\n`\n}\n\nfunction generateStorageConfig(cfg?: StorageModuleConfig): string {\n if ((cfg?.type ?? 'local') === 'local') {\n return `# 存储配置;HAI_STORAGE 可整体替换为 S3 配置。\ntype: local\nroot: ${cfg?.localPath ?? './data/uploads'}\n`\n }\n return `# S3 存储配置\ntype: s3\nbucket: ''\nregion: us-east-1\naccessKeyId: ''\nsecretAccessKey: ''\nendpoint: https://s3.amazonaws.com\nforcePathStyle: false\n`\n}\n\nfunction generateAiConfig(cfg?: AiModuleConfig): string {\n const model = cfg?.model ?? 'gpt-4o-mini'\n\n // AIConfigSchema 结构:llm(必填)+ 可选子模块\n // LLMConfigSchema 支持顶层 apiKey/model,以及多模型 models 数组\n return `# =============================================================================\n# AI 配置\n# =============================================================================\n\n# LLM 配置(必填)\nllm:\n # API Key(约定环境变量 HAI_AI_LLM_APIKEY 优先)\n apiKey: ''\n # Base URL(约定环境变量 HAI_AI_LLM_BASEURL 优先)\n # baseUrl: https://api.openai.com/v1\n # 默认模型\n model: ${model}\n # 全局最大 Token 数(默认 4096)\n # maxTokens: 4096\n # 采样温度(0-2,默认 0.7)\n # temperature: 0.7\n # 请求超时(毫秒,默认 60000)\n # timeout: 60000\n\n # 多模型配置(可选,用于场景路由)\n # models:\n # - id: fast\n # model: gpt-4o-mini\n # - id: smart\n # model: gpt-4o\n # apiKey: ''\n\n # 场景模型映射(可选)\n # scenarios:\n # default: fast\n # analysis: smart\n`\n}\n\n/**\n * 根据选中的功能模块生成 .env.example 内容\n *\n * @param features - 选中的功能模块列表\n * @param configs - 用户自定义配置值\n * @returns .env.example 文件内容\n */\nexport function generateEnvExample(features: FeatureId[], configs?: ModuleConfigs): string {\n const sections: string[] = []\n\n // 文件头\n sections.push(`# =============================================================================\n# Environment Variables\n# =============================================================================\n#\n# Copy this file to .env and fill in actual values.\n# Config files use literal defaults; matching HAI variables override YAML leaves.\n#\n# Naming convention: HAI_<config name>_<YAML path>\n# =============================================================================`)\n\n // 应用基础(始终生成)\n sections.push(`\n# =============================================================================\n# Application\n# =============================================================================\n# Environment: development | production | test\nHAI_CORE_ENV=development\n# Enable debug mode\nHAI_CORE_DEBUG=false`)\n\n // 数据库\n if (features.includes('db')) {\n const dbType = configs?.db?.type ?? 'sqlite'\n const dbDatabase = configs?.db?.database ?? (dbType === 'sqlite' ? './data/app.db' : 'hai')\n const isSqlite = dbType === 'sqlite'\n sections.push(`\n# =============================================================================\n# Database (@h-ai/reldb)\n# =============================================================================\n# Database type: sqlite | postgresql | mysql\nHAI_DB_TYPE=${dbType}\n# SQLite: file path; PostgreSQL/MySQL: database name\nHAI_DB_DATABASE=${dbDatabase}${isSqlite\n ? `\n# PostgreSQL/MySQL connection (uncomment when not using sqlite)\n# HAI_DB_HOST=localhost\n# HAI_DB_PORT=5432\n# HAI_DB_USER=postgres\n# HAI_DB_PASSWORD=`\n : `\n# Connection\nHAI_DB_HOST=${configs?.db?.host ?? 'localhost'}\nHAI_DB_PORT=${configs?.db?.port ?? (dbType === 'postgresql' ? 5432 : 3306)}\nHAI_DB_USER=${dbType === 'postgresql' ? 'postgres' : 'root'}\nHAI_DB_PASSWORD=`}`)\n }\n\n // IAM / Session\n if (features.includes('iam')) {\n sections.push(`\n# =============================================================================\n# IAM (@h-ai/iam)\n# =============================================================================\n# HAI_IAM_PASSWORD_MINLENGTH=8\n# HAI_IAM_SESSION_MAXAGE=86400\n# HAI_IAM_SESSION_REFRESHTOKENMAXAGE=604800\n# HAI_KIT_COOKIE_KEY= # 32-char hex for SM4-CBC cookie encryption\n`)\n }\n\n // 缓存\n if (features.includes('cache')) {\n const cacheType = configs?.cache?.type ?? 'memory'\n if (cacheType === 'redis') {\n sections.push(`\n# =============================================================================\n# Cache (@h-ai/cache)\n# =============================================================================\n# Cache type: memory | redis\nHAI_CACHE_TYPE=redis\n# Redis connection\nHAI_CACHE_HOST=${configs?.cache?.host ?? 'localhost'}\nHAI_CACHE_PORT=${configs?.cache?.port ?? 6379}\nHAI_CACHE_PASSWORD=\n# HAI_CACHE_URL=redis://localhost:6379/0\n# HAI_CACHE_DB=0\n# HAI_CACHE_CONNECT_TIMEOUT=10000\n# HAI_CACHE_COMMAND_TIMEOUT=5000\n# HAI_CACHE_KEY_PREFIX=hai:`)\n }\n else {\n sections.push(`\n# =============================================================================\n# Cache (@h-ai/cache)\n# =============================================================================\n# Cache type: memory | redis\nHAI_CACHE_TYPE=memory\n# Redis connection (uncomment when type=redis)\n# HAI_CACHE_URL=redis://localhost:6379/0\n# HAI_CACHE_HOST=localhost\n# HAI_CACHE_PORT=6379\n# HAI_CACHE_PASSWORD=\n# HAI_CACHE_DB=0\n# HAI_CACHE_CONNECT_TIMEOUT=10000\n# HAI_CACHE_COMMAND_TIMEOUT=5000\n# HAI_CACHE_KEY_PREFIX=hai:`)\n }\n }\n\n // 存储\n if (features.includes('storage')) {\n const storageType = configs?.storage?.type ?? 'local'\n if (storageType === 's3') {\n sections.push(`\n# =============================================================================\n# Storage (@h-ai/storage)\n# =============================================================================\n# Default storage provider: local | s3\nHAI_STORAGE_TYPE=s3\n# S3 / S3-compatible\nHAI_STORAGE_BUCKET=\nHAI_STORAGE_REGION=us-east-1\nHAI_STORAGE_ACCESSKEYID=\nHAI_STORAGE_SECRETACCESSKEY=\n# HAI_STORAGE_ENDPOINT= # Custom endpoint for MinIO / Aliyun OSS etc.\n# HAI_STORAGE_FORCEPATHSTYLE=false\n# Local storage (uncomment when type=local)\n# HAI_STORAGE_ROOT=./data/uploads`)\n }\n else {\n sections.push(`\n# =============================================================================\n# Storage (@h-ai/storage)\n# =============================================================================\n# Default storage provider: local | s3\nHAI_STORAGE_TYPE=local\n# Local storage root path\nHAI_STORAGE_ROOT=${configs?.storage?.localPath ?? './data/uploads'}\n# S3 / S3-compatible (uncomment when type=s3)\n# HAI_STORAGE_BUCKET=\n# HAI_STORAGE_REGION=us-east-1\n# HAI_STORAGE_ACCESSKEYID=\n# HAI_STORAGE_SECRETACCESSKEY=\n# HAI_STORAGE_ENDPOINT= # Custom endpoint for MinIO / Aliyun OSS etc.\n# HAI_STORAGE_FORCEPATHSTYLE=false`)\n }\n }\n\n // AI\n if (features.includes('ai')) {\n const provider = configs?.ai?.defaultProvider ?? 'openai'\n if (provider === 'anthropic') {\n sections.push(`\n# =============================================================================\n# AI (@h-ai/ai)\n# =============================================================================\n# OpenAI-compatible API Key (Anthropic models via OpenAI-compatible proxy)\nHAI_AI_LLM_APIKEY=\n# HAI_AI_LLM_BASEURL= # Custom base URL\n# Optional compatibility fallback\n# OPENAI_API_KEY=`)\n }\n else if (provider === 'openai') {\n sections.push(`\n# =============================================================================\n# AI (@h-ai/ai)\n# =============================================================================\n# OpenAI / OpenAI-compatible\nHAI_AI_LLM_APIKEY=\n# HAI_AI_LLM_BASEURL= # Custom base URL (e.g. local proxy, Azure)\n# Optional compatibility fallback\n# OPENAI_API_KEY=`)\n }\n else {\n sections.push(`\n# =============================================================================\n# AI (@h-ai/ai)\n# =============================================================================\n# OpenAI-compatible provider\nHAI_AI_LLM_APIKEY=\n# HAI_AI_LLM_BASEURL= # Custom base URL\n# Optional compatibility fallback\n# OPENAI_API_KEY=`)\n }\n }\n\n // VecDB\n if (features.includes('vecdb')) {\n sections.push(`\n# =============================================================================\n# Vector Database (@h-ai/vecdb)\n# =============================================================================\n# Backend type: lancedb | pgvector | qdrant\nHAI_VECDB_TYPE=lancedb\n# LanceDB data path\nHAI_VECDB_PATH=./data/vecdb\n# Qdrant (uncomment when type=qdrant)\n# HAI_VECDB_URL=http://localhost:6333\n# HAI_VECDB_APIKEY=\n`)\n }\n\n // Reach\n if (features.includes('reach')) {\n sections.push(`\n# =============================================================================\n# Reach (@h-ai/reach)\n# =============================================================================\n# SMTP (uncomment when enabling email provider)\n# HAI_REACH_SMTP_HOST=smtp.example.com\n# HAI_REACH_SMTP_PORT=465\n# HAI_REACH_SMTP_USER=\n# HAI_REACH_SMTP_PASS=\n# HAI_REACH_SMTP_FROM=noreply@example.com\n`)\n }\n\n // Payment\n if (features.includes('payment')) {\n sections.push(`\n# =============================================================================\n# Payment (@h-ai/payment)\n# =============================================================================\n# WeChat Pay\n# HAI_PAYMENT_WECHAT_MCHID=\n# HAI_PAYMENT_WECHAT_APIV3KEY=\n# HAI_PAYMENT_WECHAT_SERIALNO=\n# HAI_PAYMENT_WECHAT_PRIVATEKEY=\n# HAI_PAYMENT_WECHAT_APPID=\n# Alipay\n# HAI_PAYMENT_ALIPAY_APPID=\n# HAI_PAYMENT_ALIPAY_PRIVATEKEY=\n# HAI_PAYMENT_ALIPAY_ALIPAYPUBLICKEY=\n# Stripe\n# HAI_PAYMENT_STRIPE_SECRETKEY=\n# HAI_PAYMENT_STRIPE_WEBHOOKSECRET=\n`)\n }\n\n // 测试(始终生成)\n sections.push(`\n# =============================================================================\n# Testing\n# =============================================================================\n# E2E test mode (relaxes rate limiting etc.)\n# HAI_E2E=1\n`)\n\n return sections.join('\\n')\n}\n\nfunction generateDeployConfig(): string {\n return `# =============================================================================\n# 部署配置 (@h-ai/deploy)\n# =============================================================================\n# 部署平台凭证通过 ~/.hai/credentials.yml 管理\n# 环境变量引用格式: \\${VAR_NAME:default_value}\n\n# 部署平台\nprovider:\n type: vercel\n token: \\${HAI_DEPLOY_VERCEL_TOKEN}\n\n# ---------------------------------------------------------------------------\n# 方式二:docker-ssh — 将应用容器化后通过 SSH 部署到任意 Linux 主机\n# 远程主机只需具备 SSH + docker/podman + compose,本地需 docker 或 podman\n# 切换时用下方 provider 替换上面的 vercel provider\n# ---------------------------------------------------------------------------\n# provider:\n# type: docker-ssh\n# ssh:\n# host: \\${HAI_DEPLOY_SSH_HOST}\n# port: 22\n# username: deploy\n# identityFile: \\${HAI_DEPLOY_SSH_KEY} # 私钥文件路径(省略则用 ssh-agent)\n# remote:\n# baseDir: /opt/hai/apps\n# runtime: auto # auto 优先 podman,其次 docker\n# expose:\n# type: port\n# containerPort: 3000\n# hostPort: 18080 # 访问地址 http://<host>:18080\n\n# 本地构建运行时(docker-ssh 使用;auto 优先 podman)\n# container:\n# runtime: auto\n\n# 基础设施服务(按需开启)\nservices:\n # PostgreSQL 数据库 (Neon)\n # db:\n # provisioner: neon\n # apiKey: \\${HAI_DEPLOY_NEON_API_KEY}\n\n # Redis 缓存 (Upstash)\n # cache:\n # provisioner: upstash\n # email: \\${HAI_DEPLOY_UPSTASH_EMAIL}\n # apiKey: \\${HAI_DEPLOY_UPSTASH_API_KEY}\n\n # S3 存储 (Cloudflare R2)\n # storage:\n # provisioner: cloudflare-r2\n # accountId: \\${HAI_DEPLOY_CF_ACCOUNT_ID}\n # apiToken: \\${HAI_DEPLOY_CF_API_TOKEN}\n # accessKeyId: \\${HAI_DEPLOY_R2_ACCESS_KEY_ID}\n # secretAccessKey: \\${HAI_DEPLOY_R2_SECRET_ACCESS_KEY}\n\n # 邮件 (Resend)\n # email:\n # provisioner: resend\n # apiKey: \\${HAI_DEPLOY_RESEND_API_KEY}\n # from: \\${HAI_DEPLOY_RESEND_FROM}\n\n # 短信 (阿里云)\n # sms:\n # provisioner: aliyun\n # accessKeyId: \\${HAI_DEPLOY_ALIYUN_ACCESS_KEY_ID}\n # accessKeySecret: \\${HAI_DEPLOY_ALIYUN_ACCESS_KEY_SECRET}\n # signName: \\${HAI_DEPLOY_ALIYUN_SIGN_NAME}\n\n# docker-ssh 说明:\n# - 应用镜像使用工程自带的 Dockerfile(adapter-node),本地构建后经 SSH 传输并 load\n# - compose 会按上方启用的 db/cache/storage 自动追加 postgres/redis/minio sidecar\n# - 若同时配置了对应云 Provisioner,则优先使用云资源,不再自建 sidecar\n`\n}\n\nfunction generateVecdbConfig(): string {\n return `# =============================================================================\n# 向量数据库配置 (@h-ai/vecdb)\n# =============================================================================\n\n# 数据库类型: lancedb | pgvector | qdrant\ntype: lancedb\n\n# LanceDB 数据目录\npath: ./data/vecdb\n\n# 距离度量: cosine | euclidean | dot\n# metric: cosine\n\n# pgvector 配置(当 type 为 pgvector 时使用)\n# type: pgvector\n# host: localhost\n# port: 5432\n# database: hai\n# user: postgres\n# password: ''\n# indexType: hnsw\n# tablePrefix: vec_\n\n# Qdrant 配置(当 type 为 qdrant 时使用)\n# type: qdrant\n# url: http://localhost:6333\n# apiKey: ''\n`\n}\n\nfunction generateReachConfig(): string {\n return `# =============================================================================\n# 消息推送配置 (@h-ai/reach)\n# =============================================================================\n\nproviders:\n # 控制台输出(开发/测试用)\n - name: console_dev\n type: console\n\n # SMTP 邮件(按需开启)\n # - name: email\n # type: smtp\n # host: \\${HAI_REACH_SMTP_HOST:smtp.example.com}\n # port: \\${HAI_REACH_SMTP_PORT:465}\n # secure: true\n # user: \\${HAI_REACH_SMTP_USER:}\n # pass: \\${HAI_REACH_SMTP_PASS:}\n # from: \\${HAI_REACH_SMTP_FROM:noreply@example.com}\n\n # 阿里云短信(按需开启)\n # - name: sms\n # type: aliyun-sms\n # accessKeyId: \\${HAI_REACH_SMS_ACCESS_KEY}\n # accessKeySecret: \\${HAI_REACH_SMS_SECRET_KEY}\n # signName: MyApp\n\n# IAM 标准模板:保留空数组以支持 HAI_REACH_TEMPLATES 整体覆盖。\ntemplates: []\n# 开启对应 Provider 后,将空数组替换为需要的模板列表,例如:\n# templates:\n# - name: otp_email\n# provider: email\n# subject: \"Verification code\"\n# body: \"Your verification code is {code}.\"\n# - name: otp_sms\n# provider: sms\n# body: \"Your verification code is {code}.\"\n# - name: password_reset\n# provider: email\n# subject: \"Password reset\"\n# body: \"Reset your password: {resetUrl}. Expires at {expiresAt}.\"\n# - name: password_reset_sms\n# provider: sms\n# body: \"Reset your password: {resetUrl}. Expires at {expiresAt}.\"\n\n# 免打扰(可选)\n# dnd:\n# enabled: true\n# strategy: delay\n# start: \"22:00\"\n# end: \"08:00\"\n`\n}\n\nfunction generateSchedulerConfig(): string {\n return `# =============================================================================\n# 任务调度配置 (@h-ai/scheduler)\n# =============================================================================\n\n# 是否启用数据库日志(需要 @h-ai/reldb)\nenableDb: true\n\n# 执行日志表名\ntableName: hai_scheduler_logs\n\n# 任务定义表名\ntaskTableName: hai_scheduler_tasks\n\n# 分布式锁表名\nlockTableName: hai_scheduler_locks\n\n# 检查间隔(毫秒)\ntickInterval: 1000\n\n# 锁过期时间(毫秒)\nlockExpireMs: 300000\n`\n}\n\nfunction generateAuditConfig(): string {\n return `# =============================================================================\n# 审计日志配置 (@h-ai/audit)\n# =============================================================================\n\n# 用户表名(用于 JOIN 查询)\nuserTable: hai_iam_users\n\n# 用户表主键列名\nuserIdColumn: id\n\n# 用户名列名\nuserNameColumn: username\n`\n}\n\nfunction generatePaymentConfig(): string {\n return `# =============================================================================\n# 支付配置 (@h-ai/payment)\n# =============================================================================\n\n# 微信支付(按需开启)\n# wechat:\n# mchId: ''\n# apiV3Key: ''\n# serialNo: ''\n# privateKey: ''\n# appId: ''\n\n# 支付宝(按需开启)\n# alipay:\n# appId: ''\n# privateKey: ''\n# alipayPublicKey: ''\n# signType: RSA2\n# sandbox: false\n\n# Stripe(按需开启)\n# stripe:\n# secretKey: ''\n# webhookSecret: ''\n`\n}\n"]}
|
|
@@ -7,6 +7,15 @@ import { core } from '@h-ai/core';
|
|
|
7
7
|
|
|
8
8
|
// messages/en-US.json
|
|
9
9
|
var en_US_default = {
|
|
10
|
+
cli_createFailed: "Failed to create project:",
|
|
11
|
+
cli_installFailed: "Dependency installation failed ({pm}).",
|
|
12
|
+
cli_commandLabel: "Command: {command}",
|
|
13
|
+
cli_exitCode: "Exit code: {code}",
|
|
14
|
+
cli_signal: "Signal: {signal}",
|
|
15
|
+
cli_selectHint: "- \u2191/\u2193 select, Enter confirm",
|
|
16
|
+
cli_multiselectHint: "- Space select, Enter confirm",
|
|
17
|
+
cli_featuresPrompt: "Select features:",
|
|
18
|
+
cli_frontendsPrompt: "Select frontend targets:",
|
|
10
19
|
cli_invalidGenerateName: "Use a name starting with a letter, with only letters, digits, hyphens or underscores",
|
|
11
20
|
cli_generateOutsideWorkspace: "Generated files must remain inside the workspace, including symbolic link targets",
|
|
12
21
|
cli_generateExists: "File already exists: {path}. Use --force to overwrite it",
|
|
@@ -37,6 +46,15 @@ var en_US_default = {
|
|
|
37
46
|
|
|
38
47
|
// messages/zh-CN.json
|
|
39
48
|
var zh_CN_default = {
|
|
49
|
+
cli_createFailed: "\u521B\u5EFA\u9879\u76EE\u5931\u8D25:",
|
|
50
|
+
cli_installFailed: "\u5B89\u88C5\u4F9D\u8D56\u5931\u8D25\uFF08{pm}\uFF09\u3002",
|
|
51
|
+
cli_commandLabel: "\u547D\u4EE4: {command}",
|
|
52
|
+
cli_exitCode: "\u9000\u51FA\u7801: {code}",
|
|
53
|
+
cli_signal: "\u4FE1\u53F7: {signal}",
|
|
54
|
+
cli_selectHint: "- \u2191/\u2193 \u9009\u62E9\uFF0C\u56DE\u8F66\u786E\u8BA4",
|
|
55
|
+
cli_multiselectHint: "- \u7A7A\u683C\u9009\u62E9\uFF0C\u56DE\u8F66\u786E\u8BA4",
|
|
56
|
+
cli_featuresPrompt: "\u9009\u62E9\u529F\u80FD:",
|
|
57
|
+
cli_frontendsPrompt: "\u9009\u62E9\u524D\u7AEF\u76EE\u6807:",
|
|
40
58
|
cli_invalidGenerateName: "\u540D\u79F0\u5FC5\u987B\u4EE5\u5B57\u6BCD\u5F00\u5934\uFF0C\u4E14\u4EC5\u5305\u542B\u5B57\u6BCD\u3001\u6570\u5B57\u3001\u77ED\u6A2A\u7EBF\u6216\u4E0B\u5212\u7EBF",
|
|
41
59
|
cli_generateOutsideWorkspace: "\u751F\u6210\u6587\u4EF6\u5FC5\u987B\u4F4D\u4E8E\u5DE5\u4F5C\u76EE\u5F55\u5185\uFF0C\u7B26\u53F7\u94FE\u63A5\u76EE\u6807\u4E5F\u4E0D\u5F97\u8D8A\u754C",
|
|
42
60
|
cli_generateExists: "\u6587\u4EF6\u5DF2\u5B58\u5728\uFF1A{path}\u3002\u4F7F\u7528 --force \u624D\u53EF\u8986\u76D6",
|
|
@@ -351,5 +369,5 @@ async function generateProjectAiSupport(projectPath, skillNames, options = {}) {
|
|
|
351
369
|
}
|
|
352
370
|
|
|
353
371
|
export { cliM, generateModuleSkillFile, generateProjectAiSupport, generateSkillFiles, resolveCompatibleSkillNames, resolveSkillNamesForPackages };
|
|
354
|
-
//# sourceMappingURL=chunk-
|
|
355
|
-
//# sourceMappingURL=chunk-
|
|
372
|
+
//# sourceMappingURL=chunk-WWG3U5ZD.js.map
|
|
373
|
+
//# sourceMappingURL=chunk-WWG3U5ZD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../messages/en-US.json","../messages/zh-CN.json","../src/cli-i18n.ts","../src/commands/cli-skill-templates.ts"],"names":[],"mappings":";;;;;;;;AAAA,IAAA,aAAA,GAAA;AAAA,EACE,gBAAA,EAAoB,2BAAA;AAAA,EACpB,iBAAA,EAAqB,wCAAA;AAAA,EACrB,gBAAA,EAAoB,oBAAA;AAAA,EACpB,YAAA,EAAgB,mBAAA;AAAA,EAChB,UAAA,EAAc,kBAAA;AAAA,EACd,cAAA,EAAkB,uCAAA;AAAA,EAClB,mBAAA,EAAuB,+BAAA;AAAA,EACvB,kBAAA,EAAsB,kBAAA;AAAA,EACtB,mBAAA,EAAuB,0BAAA;AAAA,EACvB,uBAAA,EAA2B,sFAAA;AAAA,EAC3B,4BAAA,EAAgC,mFAAA;AAAA,EAChC,kBAAA,EAAsB,0DAAA;AAAA,EACtB,yBAAA,EAA6B,sDAAA;AAAA,EAC7B,2BAAA,EAA+B,wBAAA;AAAA,EAC/B,6BAAA,EAAiC,uCAAA;AAAA,EACjC,6BAAA,EAAiC,4BAAA;AAAA,EACjC,sBAAA,EAA0B,0BAAA;AAAA,EAC1B,yBAAA,EAA6B,iCAAA;AAAA,EAC7B,sBAAA,EAA0B,iDAAA;AAAA,EAC1B,wBAAA,EAA4B,sBAAA;AAAA,EAC5B,mBAAA,EAAuB,yBAAA;AAAA,EACvB,sBAAA,EAA0B,wBAAA;AAAA,EAC1B,kBAAA,EAAsB,gEAAA;AAAA,EACtB,eAAA,EAAmB,MAAA;AAAA,EACnB,uBAAA,EAA2B,+BAAA;AAAA,EAC3B,sBAAA,EAA0B,wBAAA;AAAA,EAC1B,sBAAA,EAA0B,2BAAA;AAAA,EAC1B,oBAAA,EAAwB,0BAAA;AAAA,EACxB,iBAAA,EAAqB,0BAAA;AAAA,EACrB,kBAAA,EAAsB,wBAAA;AAAA,EACtB,cAAA,EAAkB,cAAA;AAAA,EAClB,aAAA,EAAiB,YAAA;AAAA,EACjB,cAAA,EAAkB,gBAAA;AAAA,EAClB,yBAAA,EAA6B,uBAAA;AAAA,EAC7B,sBAAA,EAA0B;AAC5B,CAAA;;;ACpCA,IAAA,aAAA,GAAA;AAAA,EACE,gBAAA,EAAoB,uCAAA;AAAA,EACpB,iBAAA,EAAqB,4DAAA;AAAA,EACrB,gBAAA,EAAoB,yBAAA;AAAA,EACpB,YAAA,EAAgB,4BAAA;AAAA,EAChB,UAAA,EAAc,wBAAA;AAAA,EACd,cAAA,EAAkB,4DAAA;AAAA,EAClB,mBAAA,EAAuB,0DAAA;AAAA,EACvB,kBAAA,EAAsB,2BAAA;AAAA,EACtB,mBAAA,EAAuB,uCAAA;AAAA,EACvB,uBAAA,EAA2B,oKAAA;AAAA,EAC3B,4BAAA,EAAgC,wJAAA;AAAA,EAChC,kBAAA,EAAsB,+FAAA;AAAA,EACtB,yBAAA,EAA6B,6FAAA;AAAA,EAC7B,2BAAA,EAA+B,4CAAA;AAAA,EAC/B,6BAAA,EAAiC,qDAAA;AAAA,EACjC,6BAAA,EAAiC,+CAAA;AAAA,EACjC,sBAAA,EAA0B,wDAAA;AAAA,EAC1B,yBAAA,EAA6B,wDAAA;AAAA,EAC7B,sBAAA,EAA0B,8EAAA;AAAA,EAC1B,wBAAA,EAA4B,4CAAA;AAAA,EAC5B,mBAAA,EAAuB,4CAAA;AAAA,EACvB,sBAAA,EAA0B,yCAAA;AAAA,EAC1B,kBAAA,EAAsB,wGAAA;AAAA,EACtB,eAAA,EAAmB,QAAA;AAAA,EACnB,uBAAA,EAA2B,8DAAA;AAAA,EAC3B,sBAAA,EAA0B,+CAAA;AAAA,EAC1B,sBAAA,EAA0B,kDAAA;AAAA,EAC1B,oBAAA,EAAwB,4CAAA;AAAA,EACxB,iBAAA,EAAqB,yCAAA;AAAA,EACrB,kBAAA,EAAsB,gCAAA;AAAA,EACtB,cAAA,EAAkB,2BAAA;AAAA,EAClB,aAAA,EAAiB,0BAAA;AAAA,EACjB,cAAA,EAAkB,yCAAA;AAAA,EAClB,yBAAA,EAA6B,sCAAA;AAAA,EAC7B,sBAAA,EAA0B;AAC5B,CAAA;;;AC/BO,IAAM,IAAA,GAAO,KAAK,IAAA,CAAK,mBAAA,CAAuC,EAAE,OAAA,EAAS,aAAA,EAAM,OAAA,EAAS,aAAA,EAAM;;;ACYrG,IAAM,gBAAA,GAA2C;AAAA,EAC/C,IAAA,EAAM,WAAA;AAAA,EACN,OAAA,EAAS,WAAA;AAAA,EACT,OAAA,EAAS,WAAA;AAAA,EACT,KAAA,EAAO,SAAA;AAAA,EACP,SAAA,EAAW,aAAA;AAAA,EACX,IAAA,EAAM,QAAA;AAAA,EACN,QAAA,EAAU,YAAA;AAAA,EACV,SAAA,EAAW,aAAA;AAAA,EACX,OAAA,EAAS,WAAA;AAAA,EACT,UAAA,EAAY,cAAA;AAAA,EACZ,OAAA,EAAS,WAAA;AAAA,EACT,WAAA,EAAa,eAAA;AAAA,EACb,OAAA,EAAS,WAAA;AAAA,EACT,QAAA,EAAU,YAAA;AAAA,EACV,KAAA,EAAO,SAAA;AAAA,EACP,IAAA,EAAM,QAAA;AAAA,EACN,YAAA,EAAc,gBAAA;AAAA,EACd,WAAA,EAAa;AACf,CAAA;AAQA,IAAM,4BAAA,GAAmE;AAAA,EACvE,OAAA,EAAS,CAAC,UAAA,EAAY,kBAAA,EAAoB,kBAAkB,eAAe,CAAA;AAAA,EAC3E,SAAA,EAAW,CAAC,UAAA,EAAY,kBAAA,EAAoB,kBAAkB,eAAe,CAAA;AAAA,EAC7E,IAAA,EAAM,CAAC,UAAA,EAAY,kBAAA,EAAoB,kBAAkB,eAAe,CAAA;AAAA,EACxE,KAAA,EAAO,CAAC,QAAA,EAAU,SAAA,EAAW,eAAe,CAAA;AAAA,EAC5C,YAAA,EAAc,CAAC,UAAA,EAAY,SAAA,EAAW,YAAY,kBAAkB,CAAA;AAAA,EACpE,WAAA,EAAa,CAAC,SAAS;AACzB,CAAA;AAEA,IAAM,eAAA,GAAkB;AAAA,EACtB,WAAA;AAAA,EACA,gBAAA;AAAA,EACA,gBAAA;AAAA,EACA;AACF,CAAA;AAEA,IAAM,iBAAA,GAA4C;AAAA,EAChD,oBAAA,EAAsB,kBAAA;AAAA,EACtB,kBAAA,EAAoB,gBAAA;AAAA,EACpB,YAAA,EAAc,UAAA;AAAA,EACd,YAAA,EAAc,UAAA;AAAA,EACd,WAAA,EAAa,SAAA;AAAA,EACb,UAAA,EAAY,QAAA;AAAA,EACZ,aAAA,EAAe,WAAA;AAAA,EACf,aAAA,EAAe,WAAA;AAAA,EACf,WAAA,EAAa,SAAA;AAAA,EACb,eAAA,EAAiB,aAAA;AAAA,EACjB,UAAA,EAAY,QAAA;AAAA,EACZ,cAAA,EAAgB,YAAA;AAAA,EAChB,eAAA,EAAiB,aAAA;AAAA,EACjB,aAAA,EAAe,WAAA;AAAA,EACf,gBAAA,EAAkB,cAAA;AAAA,EAClB,aAAA,EAAe,WAAA;AAAA,EACf,iBAAA,EAAmB,eAAA;AAAA,EACnB,aAAA,EAAe,WAAA;AAAA,EACf,cAAA,EAAgB,YAAA;AAAA,EAChB,iBAAA,EAAmB;AACrB,CAAA;AAEA,IAAM,iBAAA,GAAoB,CAAC,gBAAgB,CAAA;AAE3C,IAAM,YAAA,GAAe;AAAA,EACnB;AAAA,IACE,MAAA,EAAQ,yBAAA;AAAA,IACR,WAAA,EAAa;AAAA,GACf;AAAA,EACA;AAAA,IACE,MAAA,EAAQ,WAAA;AAAA,IACR,WAAA,EAAa;AAAA,GACf;AAAA,EACA;AAAA,IACE,MAAA,EAAQ,WAAA;AAAA,IACR,WAAA,EAAa;AAAA,GACf;AAAA,EACA;AAAA,IACE,MAAA,EAAQ,eAAA;AAAA,IACR,WAAA,EAAa;AAAA;AAEjB,CAAA;AAEA,IAAM,oBAAA,GAAuB,cAAA;AAG7B,eAAe,oBAAoB,WAAA,EAA2E;AAC5G,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,IAAA,CAAK,WAAA,EAAa,cAAc,CAAA;AACzD,EAAA,IAAI,CAAE,MAAM,GAAA,CAAI,UAAA,CAAW,WAAW,CAAA,EAAI;AACxC,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,IAAI,QAAA;AACJ,EAAA,IAAI;AACF,IAAA,QAAA,GAAW,MAAM,GAAA,CAAI,QAAA,CAAS,WAAW,CAAA;AAAA,EAC3C,CAAA,CAAA,MACM;AACJ,IAAA,OAAO,EAAC;AAAA,EACV;AACA,EAAA,IAAI,CAAC,QAAA,IAAY,OAAO,QAAA,KAAa,QAAA,IAAY,EAAE,MAAA,IAAU,QAAA,CAAA,IACxD,OAAO,QAAA,CAAS,SAAS,QAAA,IAAY,CAAC,qBAAqB,IAAA,CAAK,QAAA,CAAS,IAAI,CAAA,EAAG;AACnF,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,MAAM,cAAc,QAAA,CAAS,IAAA;AAC7B,EAAA,KAAA,MAAW,CAAC,OAAA,EAAS,SAAA,EAAW,QAAQ,CAAA,IAAK;AAAA,IAC3C,CAAC,WAAA,EAAa,UAAA,EAAY,CAAC,UAAA,EAAY,MAAA,EAAQ,QAAQ,CAAC,CAAA;AAAA,IACxD,CAAC,KAAA,EAAO,MAAA,EAAQ,CAAC,UAAA,EAAY,SAAS,CAAC;AAAA,GACzC,EAAY;AACV,IAAA,MAAM,YAAY,MAAM,OAAA,CAAQ,IAAI,QAAA,CAAS,GAAA,CAAI,YAAU,GAAA,CAAI,UAAA;AAAA,MAC7D,IAAA,CAAK,KAAK,WAAA,EAAa,SAAA,EAAW,GAAG,WAAW,CAAA,CAAA,EAAI,MAAM,CAAA,CAAA,EAAI,cAAc;AAAA,KAC7E,CAAC,CAAA;AACF,IAAA,IAAI,SAAA,CAAU,KAAA,CAAM,OAAO,CAAA,EAAG;AAC5B,MAAA,OAAO,EAAE,SAAS,WAAA,EAAY;AAAA,IAChC;AAAA,EACF;AAEA,EAAA,IAAI,UAAA,IAAc,QAAA,IAAY,KAAA,CAAM,OAAA,CAAQ,QAAA,CAAS,QAAQ,CAAA,IAAK,QAAA,CAAS,QAAA,CAAS,QAAA,CAAS,KAAK,CAAA,EAAG;AACnG,IAAA,KAAA,MAAW,WAAW,CAAC,OAAA,EAAS,SAAA,EAAW,IAAA,EAAM,YAAY,CAAA,EAAY;AACvE,MAAA,IAAI,QAAA,CAAS,QAAA,CAAS,QAAA,CAAS,OAAO,CAAA,EAAG;AACvC,QAAA,OAAO,EAAE,SAAS,WAAA,EAAY;AAAA,MAChC;AAAA,IACF;AAAA,EACF;AACA,EAAA,OAAO,EAAE,WAAA,EAAY;AACvB;AAEA,eAAe,uBAAuB,YAAA,EAAyC;AAC7E,EAAA,MAAM,OAAA,GAAU,MAAM,GAAA,CAAI,OAAA,CAAQ,cAAc,EAAE,aAAA,EAAe,MAAM,CAAA;AACvE,EAAA,MAAM,aAAuB,EAAC;AAE9B,EAAA,KAAA,MAAW,SAAS,OAAA,EAAS;AAC3B,IAAA,IAAI,CAAC,MAAM,WAAA,EAAY,IAAK,CAAC,KAAA,CAAM,IAAA,CAAK,UAAA,CAAW,MAAM,CAAA,EAAG;AAC1D,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,gBAAgB,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,KAAA,CAAM,MAAM,UAAU,CAAA;AACpE,IAAA,IAAI,MAAM,GAAA,CAAI,UAAA,CAAW,aAAa,CAAA,EAAG;AACvC,MAAA,UAAA,CAAW,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,IAC5B;AAAA,EACF;AAEA,EAAA,OAAO,UAAA,CAAW,KAAK,CAAC,CAAA,EAAG,MAAM,CAAA,CAAE,aAAA,CAAc,CAAC,CAAC,CAAA;AACrD;AAEO,SAAS,2BAAA,CACd,YACA,OAAA,EACU;AACV,EAAA,MAAM,cAAA,GAAiB,IAAI,GAAA,CAAI,OAAA,GAAU,4BAAA,CAA6B,OAAO,CAAA,IAAK,EAAC,GAAI,EAAE,CAAA;AACzF,EAAA,OAAO,WAAW,MAAA,CAAO,CAAA,SAAA,KAAa,CAAC,cAAA,CAAe,GAAA,CAAI,SAAS,CAAC,CAAA;AACtE;AASA,SAAS,oBAAA,GAA+B;AACtC,EAAA,MAAM,aAAa,IAAA,CAAK,OAAA,CAAQ,aAAA,CAAc,MAAA,CAAA,IAAA,CAAY,GAAG,CAAC,CAAA;AAC9D,EAAA,MAAM,WAAW,IAAA,CAAK,OAAA,CAAQ,UAAA,EAAY,IAAA,EAAM,aAAa,QAAQ,CAAA;AACrE,EAAA,IAAI,GAAA,CAAI,cAAA,CAAe,QAAQ,CAAA,EAAG;AAChC,IAAA,OAAO,QAAA;AAAA,EACT;AACA,EAAA,OAAO,KAAK,OAAA,CAAQ,UAAA,EAAY,IAAA,EAAM,IAAA,EAAM,aAAa,QAAQ,CAAA;AACnE;AASA,eAAe,UACb,YAAA,EACA,SAAA,EACA,aACA,UAAA,GAAgC,iBAAA,EAChC,YAAY,IAAA,EACO;AACnB,EAAA,MAAM,GAAA,GAAM,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,SAAS,CAAA;AAE7C,EAAA,IAAI,CAAE,MAAM,GAAA,CAAI,UAAA,CAAW,GAAG,CAAA,EAAI;AAChC,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,MAAM,cAAwB,EAAC;AAC/B,EAAA,MAAM,SAAA,GAAY,MAAM,GAAA,CAAI,OAAA,CAAQ,GAAA,EAAK,EAAE,SAAA,EAAW,IAAA,EAAM,aAAA,EAAe,IAAA,EAAM,CAAA;AACjF,EAAA,MAAM,aAAA,GAAgB,UAAU,MAAA,CAAO,CAAA,QAAA,KAAY,SAAS,MAAA,EAAQ,EACjE,GAAA,CAAI,CAAA,QAAA,KAAY,KAAK,QAAA,CAAS,GAAA,EAAK,KAAK,IAAA,CAAK,QAAA,CAAS,YAAY,QAAA,CAAS,IAAI,CAAC,CAAC,CAAA;AAEpF,EAAA,KAAA,MAAW,aAAa,UAAA,EAAY;AAClC,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,WAAA,EAAa,WAAW,SAAS,CAAA;AACxD,IAAA,MAAM,uBAAA,CAAwB,aAAa,IAAI,CAAA;AAC/C,IAAA,IAAI,CAAC,SAAA,EAAW;AAEd,MAAA,MAAM,eAAyB,EAAC;AAChC,MAAA,KAAA,MAAW,gBAAgB,aAAA,EAAe;AACxC,QAAA,IAAI,CAAE,MAAM,GAAA,CAAI,UAAA,CAAW,KAAK,IAAA,CAAK,IAAA,EAAM,YAAY,CAAC,CAAA,EAAI;AAC1D,UAAA,YAAA,CAAa,KAAK,YAAY,CAAA;AAAA,QAChC;AAAA,MACF;AACA,MAAA,IAAI,YAAA,CAAa,WAAW,CAAA,EAAG;AAC7B,QAAA;AAAA,MACF;AACA,MAAA,KAAA,MAAW,YAAA,IAAgB,YAAA;AACzB,QAAA,MAAM,wBAAwB,WAAA,EAAa,IAAA,CAAK,IAAA,CAAK,IAAA,EAAM,YAAY,CAAC,CAAA;AAC1E,MAAA,MAAM,IAAI,IAAA,CAAK,GAAA,EAAK,MAAM,EAAE,SAAA,EAAW,OAAO,CAAA;AAC9C,MAAA,WAAA,CAAY,KAAK,GAAG,YAAA,CAAa,GAAA,CAAI,CAAA,YAAA,KAAgB,GAAG,SAAS,CAAA,CAAA,EAAI,SAAS,CAAA,CAAA,EAAI,aAAa,UAAA,CAAW,IAAA,CAAK,KAAK,GAAG,CAAC,EAAE,CAAC,CAAA;AAAA,IAC7H,CAAA,MACK;AACH,MAAA,KAAA,MAAW,YAAA,IAAgB,aAAA;AACzB,QAAA,MAAM,wBAAwB,WAAA,EAAa,IAAA,CAAK,IAAA,CAAK,IAAA,EAAM,YAAY,CAAC,CAAA;AAC1E,MAAA,MAAM,IAAI,IAAA,CAAK,GAAA,EAAK,MAAM,EAAE,SAAA,EAAW,MAAM,CAAA;AAC7C,MAAA,WAAA,CAAY,IAAA,CAAK,CAAA,EAAG,SAAS,CAAA,CAAA,EAAI,SAAS,CAAA,SAAA,CAAW,CAAA;AAAA,IACvD;AAAA,EACF;AAEA,EAAA,OAAO,WAAA;AACT;AAGA,eAAe,uBAAA,CAAwB,aAAqB,WAAA,EAAoC;AAC9F,EAAA,IAAI,QAAA,GAAW,WAAA;AACf,EAAA,OAAO,CAAE,MAAM,GAAA,CAAI,UAAA,CAAW,QAAQ,CAAA,EAAI;AACxC,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,OAAA,CAAQ,QAAQ,CAAA;AACpC,IAAA,IAAI,MAAA,KAAW,QAAA;AACb,MAAA,MAAM,IAAI,KAAA,CAAM,IAAA,CAAK,8BAA8B,CAAC,CAAA;AACtD,IAAA,QAAA,GAAW,MAAA;AAAA,EACb;AACA,EAAA,MAAM,gBAAA,GAAmB,IAAA,CAAK,QAAA,CAAS,MAAM,GAAA,CAAI,QAAA,CAAS,WAAW,CAAA,EAAG,MAAM,GAAA,CAAI,QAAA,CAAS,QAAQ,CAAC,CAAA;AACpG,EAAA,IAAI,gBAAA,KAAqB,IAAA,IAAQ,gBAAA,CAAiB,UAAA,CAAW,CAAA,EAAA,EAAK,IAAA,CAAK,GAAG,CAAA,CAAE,CAAA,IAAK,IAAA,CAAK,UAAA,CAAW,gBAAgB,CAAA;AAC/G,IAAA,MAAM,IAAI,KAAA,CAAM,IAAA,CAAK,8BAA8B,CAAC,CAAA;AACxD;AAEA,eAAe,WACb,YAAA,EACA,UAAA,EACA,aACA,UAAA,GAAgC,iBAAA,EAChC,YAAY,IAAA,EACO;AACnB,EAAA,MAAM,cAAwB,EAAC;AAE/B,EAAA,KAAA,MAAW,SAAA,IAAa,IAAI,GAAA,CAAI,UAAU,CAAA,EAAG;AAC3C,IAAA,WAAA,CAAY,IAAA,CAAK,GAAG,MAAM,SAAA,CAAU,cAAc,SAAA,EAAW,WAAA,EAAa,UAAA,EAAY,SAAS,CAAC,CAAA;AAAA,EAClG;AAEA,EAAA,OAAO,WAAA;AACT;AAQA,eAAe,gBACb,YAAA,EACA,WAAA,EACA,SAAA,GAAY,IAAA,EACZ,SACA,WAAA,EACmB;AACnB,EAAA,MAAM,cAAwB,EAAC;AAE/B,EAAA,KAAA,MAAW,QAAQ,YAAA,EAAc;AAC/B,IAAA,MAAM,GAAA,GAAM,MAAM,mBAAA,CAAoB,YAAA,EAAc,KAAK,MAAA,EAAQ,OAAA,EAAS,gBAAgB,MAAS,CAAA;AACnG,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,WAAA,EAAa,KAAK,WAAW,CAAA;AAEpD,IAAA,IAAI,CAAC,GAAA,EAAK;AACR,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,CAAC,SAAA,IAAa,MAAM,GAAA,CAAI,UAAA,CAAW,IAAI,CAAA,EAAG;AAC5C,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,uBAAA,CAAwB,aAAa,IAAI,CAAA;AAC/C,IAAA,MAAM,GAAA,CAAI,SAAA,CAAU,IAAA,CAAK,OAAA,CAAQ,IAAI,CAAC,CAAA;AACtC,IAAA,IAAI,GAAA,CAAI,QAAA,CAAS,MAAM,CAAA,EAAG;AACxB,MAAA,MAAM,QAAA,GAAW,MAAM,GAAA,CAAI,QAAA,CAAS,KAAK,MAAM,CAAA;AAC/C,MAAA,MAAM,QAAA,GAAW,UAAA,CAAW,OAAA,CAAQ,QAAA,EAAU,EAAE,QAAA,EAAU,IAAA,EAAM,CAAA,CAAE,EAAE,WAAA,EAAa,CAAA;AACjF,MAAA,MAAM,GAAA,CAAI,SAAA,CAAU,IAAA,EAAM,QAAA,EAAU,MAAM,CAAA;AAAA,IAC5C,CAAA,MACK;AACH,MAAA,MAAM,IAAI,IAAA,CAAK,GAAA,EAAK,IAAA,EAAM,EAAE,WAAW,CAAA;AAAA,IACzC;AACA,IAAA,WAAA,CAAY,IAAA,CAAK,KAAK,WAAW,CAAA;AAAA,EACnC;AAEA,EAAA,OAAO,WAAA;AACT;AAEA,eAAe,mBAAA,CACb,YAAA,EACA,MAAA,EACA,OAAA,EACA,gBAAgB,KAAA,EACQ;AACxB,EAAA,MAAM,UAAU,OAAA,IAAW,oBAAA,CAAqB,IAAA,CAAK,OAAO,IAAI,OAAA,GAAU,SAAA;AAC1E,EAAA,MAAM,UAAA,GAAa;AAAA,IACjB,GAAI,aAAA,GAAgB,CAAC,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,SAAA,EAAW,OAAA,EAAS,CAAA,EAAG,MAAM,CAAA,IAAA,CAAM,CAAC,IAAI,EAAC;AAAA,IACtF,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,SAAA,EAAW,SAAS,MAAM,CAAA;AAAA,IAClD,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,SAAA,EAAW,WAAW,MAAM,CAAA;AAAA,IACpD,IAAA,CAAK,IAAA,CAAK,YAAA,EAAc,MAAM;AAAA,GAChC;AAEA,EAAA,KAAA,MAAW,aAAa,UAAA,EAAY;AAClC,IAAA,IAAI,MAAM,GAAA,CAAI,UAAA,CAAW,SAAS,CAAA,EAAG;AACnC,MAAA,OAAO,SAAA;AAAA,IACT;AAAA,EACF;AAEA,EAAA,OAAO,IAAA;AACT;AAWA,eAAsB,kBAAA,CACpB,WAAA,EACA,SAAA,EACA,OAAA,EACA,WAAA,EACmB;AACnB,EAAA,MAAM,eAAe,oBAAA,EAAqB;AAE1C,EAAA,IAAI,CAAE,MAAM,GAAA,CAAI,UAAA,CAAW,YAAY,CAAA,EAAI;AACzC,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,MAAM,cAAwB,EAAC;AAE/B,EAAA,MAAM,kBAAA,GAAqB,MAAM,sBAAA,CAAuB,YAAY,CAAA;AACpE,EAAA,MAAM,oBAAA,GAAuB,2BAAA,CAA4B,kBAAA,EAAoB,OAA8B,CAAA;AAE3G,EAAA,WAAA,CAAY,KAAK,GAAG,MAAM,WAAW,YAAA,EAAc,oBAAA,EAAsB,WAAW,CAAC,CAAA;AAGrF,EAAA,WAAA,CAAY,IAAA,CAAK,GAAG,MAAM,eAAA,CAAgB,cAAc,WAAA,EAAa,IAAA,EAAM,OAAA,EAAS,WAAW,CAAC,CAAA;AAEhG,EAAA,OAAO,WAAA;AACT;AAWA,eAAsB,uBAAA,CACpB,aACA,QAAA,EAC0B;AAC1B,EAAA,MAAM,SAAA,GAAY,iBAAiB,QAAQ,CAAA;AAC3C,EAAA,IAAI,CAAC,SAAA,EAAW;AACd,IAAA,OAAO,IAAA;AAAA,EACT;AAEA,EAAA,MAAM,cAAc,MAAM,wBAAA,CAAyB,WAAA,EAAa,CAAC,SAAS,CAAA,EAAG;AAAA,IAC3E,eAAA,EAAiB,KAAA;AAAA,IACjB,oBAAA,EAAsB;AAAA,GACvB,CAAA;AACD,EAAA,OAAO,WAAA,CAAY,MAAA,GAAS,CAAA,GAAI,WAAA,GAAc,IAAA;AAChD;AAEO,SAAS,6BAA6B,YAAA,EAAkC;AAC7E,EAAA,MAAM,UAAA,GAAa,CAAC,GAAG,eAAe,CAAA;AAEtC,EAAA,KAAA,MAAW,eAAe,YAAA,EAAc;AACtC,IAAA,MAAM,SAAA,GAAY,kBAAkB,WAAW,CAAA;AAC/C,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,UAAA,CAAW,KAAK,SAAS,CAAA;AAAA,IAC3B;AAAA,EACF;AAEA,EAAA,OAAO,CAAC,GAAG,IAAI,GAAA,CAAI,UAAU,CAAC,CAAA;AAChC;AAEA,eAAsB,wBAAA,CACpB,WAAA,EACA,UAAA,EACA,OAAA,GAKI,EAAC,EACc;AACnB,EAAA,MAAM,eAAe,oBAAA,EAAqB;AAE1C,EAAA,IAAI,CAAE,MAAM,GAAA,CAAI,UAAA,CAAW,YAAY,CAAA,EAAI;AACzC,IAAA,OAAO,EAAC;AAAA,EACV;AAEA,EAAA,MAAM;AAAA,IACJ,eAAA,GAAkB,IAAA;AAAA,IAClB,oBAAA,GAAuB;AAAA,GACzB,GAAI,OAAA;AAEJ,EAAA,MAAM,QAAA,GAAW,MAAM,mBAAA,CAAoB,WAAW,CAAA;AACtD,EAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,OAAA,IAAW,QAAA,CAAS,OAAA;AAC5C,EAAA,MAAM,WAAA,GAAc,OAAA,CAAQ,WAAA,IAAe,QAAA,CAAS,WAAA;AAEpD,EAAA,MAAM,kBAAA,GAAqB,UACvB,CAAC,GAAG,4BAA4B,MAAM,sBAAA,CAAuB,YAAY,CAAA,EAAG,OAAkB,GAAG,GAAG,eAAA,EAAiB,GAAG,UAAU,CAAA,GAClI,CAAC,GAAG,eAAA,EAAiB,GAAG,UAAU,CAAA;AACtC,EAAA,MAAM,cAAwB,EAAC;AAC/B,EAAA,WAAA,CAAY,IAAA,CAAK,GAAG,MAAM,UAAA,CAAW,cAAc,kBAAA,EAAoB,WAAA,EAAa,iBAAA,EAAmB,eAAe,CAAC,CAAA;AACvH,EAAA,WAAA,CAAY,IAAA,CAAK,GAAG,MAAM,eAAA,CAAgB,cAAc,WAAA,EAAa,oBAAA,EAAsB,OAAA,EAAS,WAAW,CAAC,CAAA;AAEhH,EAAA,OAAO,WAAA;AACT","file":"chunk-WWG3U5ZD.js","sourcesContent":["{\n \"cli_createFailed\": \"Failed to create project:\",\n \"cli_installFailed\": \"Dependency installation failed ({pm}).\",\n \"cli_commandLabel\": \"Command: {command}\",\n \"cli_exitCode\": \"Exit code: {code}\",\n \"cli_signal\": \"Signal: {signal}\",\n \"cli_selectHint\": \"- ↑/↓ select, Enter confirm\",\n \"cli_multiselectHint\": \"- Space select, Enter confirm\",\n \"cli_featuresPrompt\": \"Select features:\",\n \"cli_frontendsPrompt\": \"Select frontend targets:\",\n \"cli_invalidGenerateName\": \"Use a name starting with a letter, with only letters, digits, hyphens or underscores\",\n \"cli_generateOutsideWorkspace\": \"Generated files must remain inside the workspace, including symbolic link targets\",\n \"cli_generateExists\": \"File already exists: {path}. Use --force to overwrite it\",\n \"cli_deploy_module_missing\": \"Deploy module not found. Install @h-ai/deploy first:\",\n \"cli_deploy_load_credentials\": \"Loading credentials...\",\n \"cli_deploy_credentials_failed\": \"Failed to load credentials: {message}\",\n \"cli_deploy_credentials_loaded\": \"Loaded {count} credentials\",\n \"cli_deploy_load_config\": \"Loading deploy config...\",\n \"cli_deploy_config_missing\": \"Deploy config not found: {path}\",\n \"cli_deploy_config_hint\": \"Run: hai add deploy to generate config template\",\n \"cli_deploy_config_loaded\": \"Deploy config loaded\",\n \"cli_deploy_scanning\": \"Scanning application...\",\n \"cli_deploy_scan_failed\": \"Scan failed: {message}\",\n \"cli_deploy_scanned\": \"Scanned: {name} (SvelteKit: {sveltekit}, Services: {services})\",\n \"cli_deploy_none\": \"none\",\n \"cli_deploy_initializing\": \"Initializing deploy module...\",\n \"cli_deploy_init_failed\": \"Init failed: {message}\",\n \"cli_deploy_initialized\": \"Deploy module initialized\",\n \"cli_deploy_deploying\": \"Deploying application...\",\n \"cli_deploy_failed\": \"Deploy failed: {message}\",\n \"cli_deploy_success\": \"Deployment successful!\",\n \"cli_deploy_url\": \" URL: {url}\",\n \"cli_deploy_id\": \" ID: {id}\",\n \"cli_deploy_env\": \" Env: {names}\",\n \"cli_deploy_command_failed\": \"Deploy command failed\",\n \"cli_adminPasswordSaved\": \" Administrator: admin; the random initial password is saved as HAI_ADMIN_DEFAULT_PASSWORD in .env\"\n}\n","{\n \"cli_createFailed\": \"创建项目失败:\",\n \"cli_installFailed\": \"安装依赖失败({pm})。\",\n \"cli_commandLabel\": \"命令: {command}\",\n \"cli_exitCode\": \"退出码: {code}\",\n \"cli_signal\": \"信号: {signal}\",\n \"cli_selectHint\": \"- ↑/↓ 选择,回车确认\",\n \"cli_multiselectHint\": \"- 空格选择,回车确认\",\n \"cli_featuresPrompt\": \"选择功能:\",\n \"cli_frontendsPrompt\": \"选择前端目标:\",\n \"cli_invalidGenerateName\": \"名称必须以字母开头,且仅包含字母、数字、短横线或下划线\",\n \"cli_generateOutsideWorkspace\": \"生成文件必须位于工作目录内,符号链接目标也不得越界\",\n \"cli_generateExists\": \"文件已存在:{path}。使用 --force 才可覆盖\",\n \"cli_deploy_module_missing\": \"未找到部署模块,请先安装 @h-ai/deploy:\",\n \"cli_deploy_load_credentials\": \"正在加载凭证…\",\n \"cli_deploy_credentials_failed\": \"加载凭证失败:{message}\",\n \"cli_deploy_credentials_loaded\": \"已加载 {count} 项凭证\",\n \"cli_deploy_load_config\": \"正在加载部署配置…\",\n \"cli_deploy_config_missing\": \"未找到部署配置:{path}\",\n \"cli_deploy_config_hint\": \"运行 hai add deploy 生成部署配置模板\",\n \"cli_deploy_config_loaded\": \"部署配置已加载\",\n \"cli_deploy_scanning\": \"正在扫描应用…\",\n \"cli_deploy_scan_failed\": \"扫描失败:{message}\",\n \"cli_deploy_scanned\": \"已扫描:{name}(SvelteKit:{sveltekit},服务:{services})\",\n \"cli_deploy_none\": \"无\",\n \"cli_deploy_initializing\": \"正在初始化部署模块…\",\n \"cli_deploy_init_failed\": \"初始化失败:{message}\",\n \"cli_deploy_initialized\": \"部署模块已初始化\",\n \"cli_deploy_deploying\": \"正在部署应用…\",\n \"cli_deploy_failed\": \"部署失败:{message}\",\n \"cli_deploy_success\": \"部署成功!\",\n \"cli_deploy_url\": \" 地址:{url}\",\n \"cli_deploy_id\": \" 标识:{id}\",\n \"cli_deploy_env\": \" 环境变量:{names}\",\n \"cli_deploy_command_failed\": \"部署命令失败\",\n \"cli_adminPasswordSaved\": \" 管理员:admin;随机初始密码已保存到 .env 的 HAI_ADMIN_DEFAULT_PASSWORD\"\n}\n","/** CLI 用户可见消息;通过 core 的全局 locale 选择语言。 */\nimport { core } from '@h-ai/core'\nimport enUS from '../messages/en-US.json'\nimport zhCN from '../messages/zh-CN.json'\n\nexport const cliM = core.i18n.createMessageGetter<keyof typeof zhCN>({ 'en-US': enUS, 'zh-CN': zhCN })\n","/**\n * @h-ai/cli — Skill 模板生成\n *\n * 将 Skill 模板文件复制到用户项目中,供 AI 编程助手使用。\n * @module cli-skill-templates\n */\n\nimport type { AppType } from '../cli-types.js'\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\nimport fse from 'fs-extra'\nimport Handlebars from 'handlebars'\nimport { cliM } from '../cli-i18n.js'\n\n/**\n * 模块名到 Skill 目录名的映射\n */\nconst MODULE_SKILL_MAP: Record<string, string> = {\n 'db': 'hai-reldb',\n 'reldb': 'hai-reldb',\n 'cache': 'hai-cache',\n 'iam': 'hai-iam',\n 'storage': 'hai-storage',\n 'ai': 'hai-ai',\n 'crypto': 'hai-crypto',\n 'payment': 'hai-payment',\n 'vecdb': 'hai-vecdb',\n 'datapipe': 'hai-datapipe',\n 'reach': 'hai-reach',\n 'scheduler': 'hai-scheduler',\n 'audit': 'hai-audit',\n 'deploy': 'hai-deploy',\n 'kit': 'hai-kit',\n 'ui': 'hai-ui',\n 'api-client': 'hai-api-client',\n 'capacitor': 'hai-capacitor',\n}\n\n/**\n * 各 appType 互斥的 Skill。\n *\n * 生成样板工程时,默认复制 templates/skills 下所有 hai-* Skill,\n * 仅排除与当前样板技术栈明显冲突的少数 Skill。\n */\nconst SKILL_EXCLUSIONS_BY_APP_TYPE: Partial<Record<AppType, string[]>> = {\n 'admin': ['hai-serv', 'hai-api-contract', 'hai-api-client', 'hai-capacitor'],\n 'website': ['hai-serv', 'hai-api-contract', 'hai-api-client', 'hai-capacitor'],\n 'h5': ['hai-serv', 'hai-api-contract', 'hai-api-client', 'hai-capacitor'],\n 'api': ['hai-ui', 'hai-kit', 'hai-capacitor'],\n 'mobile-app': ['hai-core', 'hai-kit', 'hai-serv', 'hai-api-contract'],\n 'fullstack': ['hai-kit'],\n}\n\nconst WORKFLOW_SKILLS = [\n 'hai-build',\n 'hai-app-create',\n 'hai-app-review',\n 'hai-app-tests',\n]\n\nconst PACKAGE_SKILL_MAP: Record<string, string> = {\n '@h-ai/api-contract': 'hai-api-contract',\n '@h-ai/api-client': 'hai-api-client',\n '@h-ai/core': 'hai-core',\n '@h-ai/serv': 'hai-serv',\n '@h-ai/kit': 'hai-kit',\n '@h-ai/ui': 'hai-ui',\n '@h-ai/reldb': 'hai-reldb',\n '@h-ai/cache': 'hai-cache',\n '@h-ai/iam': 'hai-iam',\n '@h-ai/storage': 'hai-storage',\n '@h-ai/ai': 'hai-ai',\n '@h-ai/crypto': 'hai-crypto',\n '@h-ai/payment': 'hai-payment',\n '@h-ai/vecdb': 'hai-vecdb',\n '@h-ai/datapipe': 'hai-datapipe',\n '@h-ai/reach': 'hai-reach',\n '@h-ai/scheduler': 'hai-scheduler',\n '@h-ai/audit': 'hai-audit',\n '@h-ai/deploy': 'hai-deploy',\n '@h-ai/capacitor': 'hai-capacitor',\n}\n\nconst SKILL_TARGET_DIRS = ['.agents/skills'] as const\n\nconst BRIDGE_FILES = [\n {\n source: 'copilot-instructions.md',\n destination: '.github/copilot-instructions.md',\n },\n {\n source: 'CLAUDE.md',\n destination: 'CLAUDE.md',\n },\n {\n source: 'AGENTS.md',\n destination: 'AGENTS.md',\n },\n {\n source: 'opencode.json',\n destination: 'opencode.json',\n },\n] as const\n\nconst BRIDGE_PROFILE_REGEX = /^[a-z0-9-]+$/\n\n/** 从已有模板标识与实际包布局确认桥接类型,不按项目名称猜测技术栈。 */\nasync function detectBridgeContext(projectPath: string): Promise<{ appType?: AppType, projectName?: string }> {\n const packagePath = path.join(projectPath, 'package.json')\n if (!(await fse.pathExists(packagePath))) {\n return {}\n }\n\n let metadata: unknown\n try {\n metadata = await fse.readJson(packagePath)\n }\n catch {\n return {}\n }\n if (!metadata || typeof metadata !== 'object' || !('name' in metadata)\n || typeof metadata.name !== 'string' || !BRIDGE_PROFILE_REGEX.test(metadata.name)) {\n return {}\n }\n\n const projectName = metadata.name\n for (const [appType, directory, suffixes] of [\n ['fullstack', 'packages', ['contract', 'serv', 'shared']],\n ['api', 'apps', ['contract', 'service']],\n ] as const) {\n const manifests = await Promise.all(suffixes.map(suffix => fse.pathExists(\n path.join(projectPath, directory, `${projectName}-${suffix}`, 'package.json'),\n )))\n if (manifests.every(Boolean)) {\n return { appType, projectName }\n }\n }\n\n if ('keywords' in metadata && Array.isArray(metadata.keywords) && metadata.keywords.includes('hai')) {\n for (const appType of ['admin', 'website', 'h5', 'mobile-app'] as const) {\n if (metadata.keywords.includes(appType)) {\n return { appType, projectName }\n }\n }\n }\n return { projectName }\n}\n\nasync function listTemplateSkillNames(templatesDir: string): Promise<string[]> {\n const entries = await fse.readdir(templatesDir, { withFileTypes: true })\n const skillNames: string[] = []\n\n for (const entry of entries) {\n if (!entry.isDirectory() || !entry.name.startsWith('hai-')) {\n continue\n }\n\n const skillFilePath = path.join(templatesDir, entry.name, 'SKILL.md')\n if (await fse.pathExists(skillFilePath)) {\n skillNames.push(entry.name)\n }\n }\n\n return skillNames.sort((a, b) => a.localeCompare(b))\n}\n\nexport function resolveCompatibleSkillNames(\n skillNames: string[],\n appType?: AppType,\n): string[] {\n const excludedSkills = new Set(appType ? SKILL_EXCLUSIONS_BY_APP_TYPE[appType] ?? [] : [])\n return skillNames.filter(skillName => !excludedSkills.has(skillName))\n}\n\n/**\n * 获取 templates/skills/ 目录的绝对路径\n *\n * 兼容两种运行环境:\n * - 构建后:dist/cli-skill-templates.js → ../templates/skills\n * - 测试时:src/commands/cli-skill-templates.ts → ../../templates/skills\n */\nfunction getSkillTemplatesDir(): string {\n const currentDir = path.dirname(fileURLToPath(import.meta.url))\n const distPath = path.resolve(currentDir, '..', 'templates', 'skills')\n if (fse.pathExistsSync(distPath)) {\n return distPath\n }\n return path.resolve(currentDir, '..', '..', 'templates', 'skills')\n}\n\n/**\n * 复制单个 Skill 目录到项目\n *\n * @param templatesDir - Skill 模板根目录\n * @param skillName - Skill 目录名(如 'hai-reldb')\n * @param projectPath - 用户项目根目录\n */\nasync function copySkill(\n templatesDir: string,\n skillName: string,\n projectPath: string,\n targetDirs: readonly string[] = SKILL_TARGET_DIRS,\n overwrite = true,\n): Promise<string[]> {\n const src = path.join(templatesDir, skillName)\n\n if (!(await fse.pathExists(src))) {\n return []\n }\n\n const copiedFiles: string[] = []\n const resources = await fse.readdir(src, { recursive: true, withFileTypes: true })\n const relativeFiles = resources.filter(resource => resource.isFile())\n .map(resource => path.relative(src, path.join(resource.parentPath, resource.name)))\n\n for (const targetDir of targetDirs) {\n const dest = path.join(projectPath, targetDir, skillName)\n await assertProjectOutputPath(projectPath, dest)\n if (!overwrite) {\n // 已有入口不能使新参考资源被跳过;逐文件补缺,同时保留用户修改。\n const missingFiles: string[] = []\n for (const relativeFile of relativeFiles) {\n if (!(await fse.pathExists(path.join(dest, relativeFile)))) {\n missingFiles.push(relativeFile)\n }\n }\n if (missingFiles.length === 0) {\n continue\n }\n for (const relativeFile of missingFiles)\n await assertProjectOutputPath(projectPath, path.join(dest, relativeFile))\n await fse.copy(src, dest, { overwrite: false })\n copiedFiles.push(...missingFiles.map(relativeFile => `${targetDir}/${skillName}/${relativeFile.replaceAll(path.sep, '/')}`))\n }\n else {\n for (const relativeFile of relativeFiles)\n await assertProjectOutputPath(projectPath, path.join(dest, relativeFile))\n await fse.copy(src, dest, { overwrite: true })\n copiedFiles.push(`${targetDir}/${skillName}/SKILL.md`)\n }\n }\n\n return copiedFiles\n}\n\n/** 写入前解析已有目录/文件链接,所有 AI 输出均限制在当前项目内。 */\nasync function assertProjectOutputPath(projectPath: string, destination: string): Promise<void> {\n let ancestor = destination\n while (!(await fse.pathExists(ancestor))) {\n const parent = path.dirname(ancestor)\n if (parent === ancestor)\n throw new Error(cliM('cli_generateOutsideWorkspace'))\n ancestor = parent\n }\n const relativeAncestor = path.relative(await fse.realpath(projectPath), await fse.realpath(ancestor))\n if (relativeAncestor === '..' || relativeAncestor.startsWith(`..${path.sep}`) || path.isAbsolute(relativeAncestor))\n throw new Error(cliM('cli_generateOutsideWorkspace'))\n}\n\nasync function copySkills(\n templatesDir: string,\n skillNames: string[],\n projectPath: string,\n targetDirs: readonly string[] = SKILL_TARGET_DIRS,\n overwrite = true,\n): Promise<string[]> {\n const copiedFiles: string[] = []\n\n for (const skillName of new Set(skillNames)) {\n copiedFiles.push(...await copySkill(templatesDir, skillName, projectPath, targetDirs, overwrite))\n }\n\n return copiedFiles\n}\n\n/**\n * 复制桥接文件到项目\n *\n * @param templatesDir - Skill 模板根目录\n * @param projectPath - 用户项目根目录\n */\nasync function copyBridgeFiles(\n templatesDir: string,\n projectPath: string,\n overwrite = true,\n appType?: string,\n projectName?: string,\n): Promise<string[]> {\n const copiedFiles: string[] = []\n\n for (const file of BRIDGE_FILES) {\n const src = await resolveBridgeSource(templatesDir, file.source, appType, projectName !== undefined)\n const dest = path.join(projectPath, file.destination)\n\n if (!src) {\n continue\n }\n\n if (!overwrite && await fse.pathExists(dest)) {\n continue\n }\n\n await assertProjectOutputPath(projectPath, dest)\n await fse.ensureDir(path.dirname(dest))\n if (src.endsWith('.hbs')) {\n const template = await fse.readFile(src, 'utf8')\n const rendered = Handlebars.compile(template, { noEscape: true })({ projectName })\n await fse.writeFile(dest, rendered, 'utf8')\n }\n else {\n await fse.copy(src, dest, { overwrite })\n }\n copiedFiles.push(file.destination)\n }\n\n return copiedFiles\n}\n\nasync function resolveBridgeSource(\n templatesDir: string,\n source: string,\n appType?: string,\n allowTemplate = false,\n): Promise<string | null> {\n const profile = appType && BRIDGE_PROFILE_REGEX.test(appType) ? appType : 'generic'\n const candidates = [\n ...(allowTemplate ? [path.join(templatesDir, 'bridges', profile, `${source}.hbs`)] : []),\n path.join(templatesDir, 'bridges', profile, source),\n path.join(templatesDir, 'bridges', 'generic', source),\n path.join(templatesDir, source),\n ]\n\n for (const candidate of candidates) {\n if (await fse.pathExists(candidate)) {\n return candidate\n }\n }\n\n return null\n}\n\n/**\n * 为新项目生成完整的 Skill 文件。\n *\n * 默认复制 templates/skills 下所有 hai-* Skill,再按 appType 排除互斥项。\n *\n * @param projectPath - 用户项目根目录\n * @param _features - 预留参数;保留签名兼容 createProject 调用方\n * @param appType - 应用类型(api 类型不复制 UI Skill)\n */\nexport async function generateSkillFiles(\n projectPath: string,\n _features: string[],\n appType?: string,\n projectName?: string,\n): Promise<string[]> {\n const templatesDir = getSkillTemplatesDir()\n\n if (!(await fse.pathExists(templatesDir))) {\n return []\n }\n\n const copiedFiles: string[] = []\n\n const templateSkillNames = await listTemplateSkillNames(templatesDir)\n const compatibleSkillNames = resolveCompatibleSkillNames(templateSkillNames, appType as AppType | undefined)\n\n copiedFiles.push(...await copySkills(templatesDir, compatibleSkillNames, projectPath))\n\n // 复制桥接文件\n copiedFiles.push(...await copyBridgeFiles(templatesDir, projectPath, true, appType, projectName))\n\n return copiedFiles\n}\n\n/**\n * 为已有项目添加单个模块的 Skill 文件\n *\n * 同时补全普通开发所需工作流及缺失参考资源,保留已有文件。\n *\n * @param projectPath - 用户项目根目录\n * @param moduleId - 模块标识(如 'db'、'iam')\n * @returns 复制的文件路径,若模块无对应 Skill 则返回 null\n */\nexport async function generateModuleSkillFile(\n projectPath: string,\n moduleId: string,\n): Promise<string[] | null> {\n const skillName = MODULE_SKILL_MAP[moduleId]\n if (!skillName) {\n return null\n }\n\n const copiedFiles = await generateProjectAiSupport(projectPath, [skillName], {\n overwriteSkills: false,\n overwriteBridgeFiles: false,\n })\n return copiedFiles.length > 0 ? copiedFiles : null\n}\n\nexport function resolveSkillNamesForPackages(packageNames: string[]): string[] {\n const skillNames = [...WORKFLOW_SKILLS]\n\n for (const packageName of packageNames) {\n const skillName = PACKAGE_SKILL_MAP[packageName]\n if (skillName) {\n skillNames.push(skillName)\n }\n }\n\n return [...new Set(skillNames)]\n}\n\nexport async function generateProjectAiSupport(\n projectPath: string,\n skillNames: string[],\n options: {\n overwriteSkills?: boolean\n overwriteBridgeFiles?: boolean\n appType?: string\n projectName?: string\n } = {},\n): Promise<string[]> {\n const templatesDir = getSkillTemplatesDir()\n\n if (!(await fse.pathExists(templatesDir))) {\n return []\n }\n\n const {\n overwriteSkills = true,\n overwriteBridgeFiles = true,\n } = options\n\n const detected = await detectBridgeContext(projectPath)\n const appType = options.appType ?? detected.appType\n const projectName = options.projectName ?? detected.projectName\n // 已确认的样板补全整个兼容目录;其它项目只补工作流与明确请求的模块。\n const selectedSkillNames = appType\n ? [...resolveCompatibleSkillNames(await listTemplateSkillNames(templatesDir), appType as AppType), ...WORKFLOW_SKILLS, ...skillNames]\n : [...WORKFLOW_SKILLS, ...skillNames]\n const copiedFiles: string[] = []\n copiedFiles.push(...await copySkills(templatesDir, selectedSkillNames, projectPath, SKILL_TARGET_DIRS, overwriteSkills))\n copiedFiles.push(...await copyBridgeFiles(templatesDir, projectPath, overwriteBridgeFiles, appType, projectName))\n\n return copiedFiles\n}\n"]}
|