@h-ai/cli 0.1.0-alpha.19 → 0.1.0-alpha.21
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.md +10 -7
- package/dist/{chunk-GSMXGUYF.js → chunk-5IGMJVV5.js} +56 -38
- package/dist/chunk-5IGMJVV5.js.map +1 -0
- package/dist/{chunk-BPO34NRL.js → chunk-CFCXOKGV.js} +27 -5
- package/dist/chunk-CFCXOKGV.js.map +1 -0
- package/dist/cli-config-templates-5J5VKWWD.js +5 -0
- package/dist/{cli-config-templates-JCS7T3NU.js.map → cli-config-templates-5J5VKWWD.js.map} +1 -1
- package/dist/cli-skill-templates-JMSV2SVW.js +5 -0
- package/dist/{cli-skill-templates-IMYZPQRG.js.map → cli-skill-templates-JMSV2SVW.js.map} +1 -1
- package/dist/index.js +627 -107
- package/dist/index.js.map +1 -1
- package/dist/{src-N4NPS7AG.js → src-QNEJJ3BV.js} +261 -103
- package/dist/src-QNEJJ3BV.js.map +1 -0
- package/package.json +3 -2
- package/templates/README.md +40 -29
- package/templates/apps/admin/messages/en-US.json +5 -0
- package/templates/apps/admin/messages/zh-CN.json +5 -0
- package/templates/apps/admin/src/routes/+layout.svelte.hbs +5 -5
- package/templates/apps/admin/src/routes/+page.svelte.hbs +32 -12
- package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +37 -20
- package/templates/apps/admin/src/routes/admin/+page.svelte.hbs +33 -24
- package/templates/apps/admin/src/routes/admin/settings/+page.svelte.hbs +16 -13
- package/templates/apps/api/apps/{{projectName}}-contract/README.md.hbs +16 -0
- package/templates/apps/api/apps/{{projectName}}-contract/package.json.hbs +38 -0
- package/templates/apps/api/apps/{{projectName}}-contract/src/app-contract.ts.hbs +27 -0
- package/templates/apps/api/apps/{{projectName}}-contract/src/app-schemas.ts.hbs +33 -0
- package/templates/apps/api/apps/{{projectName}}-contract/src/index.ts.hbs +3 -0
- package/templates/apps/api/apps/{{projectName}}-contract/src/{{projectName}}-contract.ts.hbs +12 -0
- package/templates/apps/api/apps/{{projectName}}-contract/tests/contract.test.ts.hbs +18 -0
- package/templates/apps/api/apps/{{projectName}}-contract/tsconfig.json.hbs +12 -0
- package/templates/apps/api/apps/{{projectName}}-contract/tsup.config.ts.hbs +11 -0
- package/templates/apps/api/apps/{{projectName}}-contract/vitest.config.ts.hbs +9 -0
- package/templates/apps/api/apps/{{projectName}}-service/README.md.hbs +17 -0
- package/templates/apps/api/apps/{{projectName}}-service/config/_core.yml.hbs +19 -0
- package/templates/apps/api/apps/{{projectName}}-service/config/_serv.yml.hbs +26 -0
- package/templates/apps/api/apps/{{projectName}}-service/package.json.hbs +55 -0
- package/templates/apps/api/apps/{{projectName}}-service/src/app.ts.hbs +98 -0
- package/templates/apps/api/apps/{{projectName}}-service/src/index.ts.hbs +21 -0
- package/templates/apps/api/apps/{{projectName}}-service/src/lib/server/init.ts.hbs +184 -0
- package/templates/apps/api/apps/{{projectName}}-service/src/server/procedures/app-procedures.ts.hbs +49 -0
- package/templates/apps/api/apps/{{projectName}}-service/src/server/procedures/index.ts.hbs +18 -0
- package/templates/apps/api/apps/{{projectName}}-service/tests/service.test.ts.hbs +168 -0
- package/templates/apps/api/apps/{{projectName}}-service/tsconfig.json.hbs +16 -0
- package/templates/apps/api/apps/{{projectName}}-service/tsup.config.ts.hbs +11 -0
- package/templates/apps/api/apps/{{projectName}}-service/vitest.config.ts.hbs +9 -0
- package/templates/apps/api/e2e/api-service.spec.ts.hbs +18 -0
- package/templates/apps/api/eslint.config.js +32 -0
- package/templates/apps/api/package.json.hbs +29 -0
- package/templates/apps/api/playwright.config.ts.hbs +58 -0
- package/templates/apps/api/pnpm-workspace.yaml.hbs +14 -0
- package/templates/apps/api/tsconfig.base.json +15 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/.env.example.hbs +10 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/README.md.hbs +24 -7
- package/templates/apps/fullstack/apps/{{projectName}}-app/capacitor.config.ts.hbs +18 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/eslint.config.js.hbs +1 -1
- package/templates/apps/fullstack/apps/{{projectName}}-app/index.html.hbs +16 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/messages/en-US.json.hbs +6 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/messages/zh-CN.json.hbs +6 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/package.json.hbs +51 -29
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/App.svelte.hbs +186 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/app.css.hbs +2 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/app.d.ts.hbs +0 -1
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/lib/capacitor.ts.hbs +18 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/main.ts.hbs +14 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/svelte.config.js.hbs +1 -5
- package/templates/apps/fullstack/apps/{{projectName}}-app/tsconfig.json.hbs +10 -4
- package/templates/apps/fullstack/apps/{{projectName}}-app/vite.config.ts.hbs +4 -3
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/.env.example.hbs +6 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/README.md.hbs +20 -6
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/eslint.config.js.hbs +1 -1
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/index.html.hbs +15 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/package.json.hbs +33 -30
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/App.svelte.hbs +152 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/app.d.ts.hbs +1 -2
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/main.ts.hbs +13 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/Cargo.toml.hbs +22 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/build.rs.hbs +6 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/capabilities/default.json.hbs +12 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/128x128.png +0 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/128x128@2x.png +0 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/32x32.png +0 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/icon.icns +0 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/icon.ico +0 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/src/lib.rs.hbs +16 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/src/main.rs.hbs +8 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/tauri.conf.json.hbs +41 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/svelte.config.js.hbs +2 -8
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/tsconfig.json.hbs +9 -4
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/vite.config.ts.hbs +44 -21
- package/templates/apps/fullstack/apps/{{projectName}}-web/README.md.hbs +15 -6
- package/templates/apps/fullstack/apps/{{projectName}}-web/eslint.config.js.hbs +1 -1
- package/templates/apps/fullstack/apps/{{projectName}}-web/index.html.hbs +15 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/package.json.hbs +25 -27
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/App.svelte.hbs +153 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/app.d.ts.hbs +0 -1
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/main.ts.hbs +14 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/svelte.config.js.hbs +1 -5
- package/templates/apps/fullstack/apps/{{projectName}}-web/tsconfig.json.hbs +10 -4
- package/templates/apps/fullstack/apps/{{projectName}}-web/vite.config.ts.hbs +3 -2
- package/templates/apps/fullstack/e2e/fullstack.spec.ts.hbs +2 -1
- package/templates/apps/fullstack/eslint.config.js +0 -1
- package/templates/apps/fullstack/package.json.hbs +18 -17
- package/templates/apps/fullstack/packages/{{projectName}}-contract/package.json.hbs +3 -3
- package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +5 -2
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_core.yml.hbs +14 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_serv.yml.hbs +13 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +2 -2
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/{server-app.ts.hbs → app-server.ts.hbs} +23 -3
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/index.ts.hbs +4 -1
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/{server-app.test.ts.hbs → app-server.test.ts.hbs} +1 -1
- package/templates/apps/fullstack/packages/{{projectName}}-shared/package.json.hbs +9 -8
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/index.ts.hbs +1 -1
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/api-client.ts.hbs +5 -1
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/ThemeSwitcher.svelte.hbs +1 -1
- package/templates/apps/fullstack/packages/{{projectName}}-shared/tsconfig.json.hbs +1 -1
- package/templates/apps/fullstack/playwright.config.ts.hbs +41 -4
- package/templates/apps/fullstack/pnpm-workspace.yaml.hbs +15 -0
- package/templates/apps/h5/messages/en-US.json +3 -0
- package/templates/apps/h5/messages/zh-CN.json +3 -0
- package/templates/apps/h5/src/routes/+layout.svelte.hbs +30 -29
- package/templates/apps/h5/src/routes/+page.svelte.hbs +17 -6
- package/templates/apps/h5/src/routes/discover/+page.svelte.hbs +17 -6
- package/templates/apps/h5/src/routes/profile/+page.svelte.hbs +17 -6
- package/templates/apps/mobile-app/.env.hbs +3 -0
- package/templates/apps/{android-app → mobile-app}/capacitor.config.ts.hbs +2 -2
- package/templates/apps/mobile-app/index.html.hbs +13 -0
- package/templates/apps/mobile-app/messages/en-US.json +36 -0
- package/templates/apps/mobile-app/messages/zh-CN.json +36 -0
- package/templates/apps/mobile-app/src/App.svelte.hbs +162 -0
- package/templates/apps/mobile-app/src/lib/api.ts.hbs +54 -0
- package/templates/apps/{android-app → mobile-app}/src/lib/capacitor.ts +6 -7
- package/templates/apps/mobile-app/src/main.ts.hbs +11 -0
- package/templates/apps/website/src/routes/+layout.svelte.hbs +35 -26
- package/templates/apps/website/src/routes/+page.svelte.hbs +28 -10
- package/templates/apps/website/src/routes/about/+page.svelte.hbs +11 -6
- package/templates/apps/website/src/routes/contact/+page.svelte.hbs +37 -34
- package/templates/apps/website/src/routes/services/+page.svelte.hbs +27 -40
- package/templates/base/.gitignore.hbs +16 -0
- package/templates/base/{eslint.config.js → eslint.config.js.hbs} +4 -1
- package/templates/base/package.json.hbs +55 -31
- package/templates/base/playwright.config.ts +30 -3
- package/templates/base/pnpm-workspace.yaml.hbs +14 -0
- package/templates/base/src/app.d.ts.hbs +3 -0
- package/templates/base/src/app.html.hbs +7 -0
- package/templates/base/src/hooks.server.ts.hbs +17 -7
- package/templates/base/src/lib/server/init.ts.hbs +20 -12
- package/templates/base/static/favicon.png +0 -0
- package/templates/base/svelte.config.js.hbs +43 -3
- package/templates/base/tests/scaffold.test.ts.hbs +16 -1
- package/templates/base/tsconfig.json.hbs +50 -0
- package/templates/base/vite.config.ts.hbs +13 -3
- package/templates/features/iam/routes-admin/(auth)/+layout.svelte.hbs +5 -5
- package/templates/features/iam/routes-admin/(auth)/auth/login/+page.svelte.hbs +34 -32
- package/templates/features/iam/routes-admin/(auth)/auth/register/+page.svelte.hbs +46 -48
- package/templates/features/iam/routes-h5/auth/login/+page.svelte.hbs +35 -31
- package/templates/features/iam/routes-h5/auth/register/+page.svelte.hbs +41 -38
- package/templates/skills/AGENTS.md +60 -17
- package/templates/skills/CLAUDE.md +18 -6
- package/templates/skills/bridges/admin/AGENTS.md +66 -0
- package/templates/skills/bridges/admin/CLAUDE.md +19 -0
- package/templates/skills/bridges/admin/copilot-instructions.md +46 -0
- package/templates/skills/bridges/api/AGENTS.md +65 -0
- package/templates/skills/bridges/api/CLAUDE.md +19 -0
- package/templates/skills/bridges/api/copilot-instructions.md +46 -0
- package/templates/skills/bridges/fullstack/AGENTS.md +84 -0
- package/templates/skills/bridges/fullstack/CLAUDE.md +19 -0
- package/templates/skills/bridges/fullstack/copilot-instructions.md +54 -0
- package/templates/skills/bridges/h5/AGENTS.md +65 -0
- package/templates/skills/bridges/h5/CLAUDE.md +19 -0
- package/templates/skills/bridges/h5/copilot-instructions.md +44 -0
- package/templates/skills/bridges/mobile-app/AGENTS.md +77 -0
- package/templates/skills/bridges/mobile-app/CLAUDE.md +19 -0
- package/templates/skills/bridges/mobile-app/copilot-instructions.md +45 -0
- package/templates/skills/bridges/website/AGENTS.md +65 -0
- package/templates/skills/bridges/website/CLAUDE.md +19 -0
- package/templates/skills/bridges/website/copilot-instructions.md +44 -0
- package/templates/skills/copilot-instructions.md +29 -50
- package/templates/skills/hai-ai/SKILL.md +115 -648
- package/templates/skills/hai-ai/reference.md +197 -0
- package/templates/skills/hai-api-client/SKILL.md +3 -1
- package/templates/skills/hai-app-create/SKILL.md +2 -1
- package/templates/skills/hai-app-review/SKILL.md +2 -2
- package/templates/skills/hai-app-tests/SKILL.md +28 -3
- package/templates/skills/hai-capacitor/SKILL.md +14 -22
- package/templates/skills/hai-deploy/SKILL.md +12 -9
- package/templates/skills/hai-kit/SKILL.md +5 -3
- package/templates/skills/hai-serv/SKILL.md +2 -0
- package/templates/skills/hai-ui/SKILL.md +25 -11
- package/templates/skills/opencode.json +1 -6
- package/dist/chunk-BPO34NRL.js.map +0 -1
- package/dist/chunk-GSMXGUYF.js.map +0 -1
- package/dist/cli-config-templates-JCS7T3NU.js +0 -5
- package/dist/cli-skill-templates-IMYZPQRG.js +0 -5
- package/dist/src-N4NPS7AG.js.map +0 -1
- package/templates/apps/android-app/.env.hbs +0 -3
- package/templates/apps/android-app/messages/en-US.json +0 -24
- package/templates/apps/android-app/messages/zh-CN.json +0 -24
- package/templates/apps/android-app/src/lib/api.ts.hbs +0 -31
- package/templates/apps/android-app/src/routes/+layout.svelte.hbs +0 -42
- package/templates/apps/android-app/src/routes/+layout.ts +0 -7
- package/templates/apps/android-app/src/routes/+page.svelte.hbs +0 -27
- package/templates/apps/api/src/routes/+layout.svelte +0 -14
- package/templates/apps/api/src/routes/+page.svelte +0 -11
- package/templates/apps/api/src/routes/api/v1/health/+server.ts +0 -14
- package/templates/apps/api/src/routes/api/v1/items/+server.ts +0 -37
- package/templates/apps/api/src/routes/api/v1/items/[id]/+server.ts +0 -30
- package/templates/apps/api/tests/health.test.ts.hbs +0 -26
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/app.html.hbs +0 -14
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/routes/+layout.svelte.hbs +0 -18
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/routes/+page.svelte.hbs +0 -162
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/app.html.hbs +0 -14
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/routes/+layout.svelte.hbs +0 -18
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/routes/+page.svelte.hbs +0 -162
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/app.html.hbs +0 -14
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/routes/+layout.svelte.hbs +0 -18
- package/templates/apps/fullstack/apps/{{projectName}}-web/src/routes/+page.svelte.hbs +0 -162
- package/templates/apps/fullstack/pnpm-workspace.yaml +0 -7
- package/templates/base/tsconfig.json +0 -20
- /package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/{theme.svelte.ts.hbs → theme-store.svelte.ts.hbs} +0 -0
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@h-ai/cli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.1.0-alpha.
|
|
4
|
+
"version": "0.1.0-alpha.21",
|
|
5
5
|
"description": "Hai Framework CLI for project scaffolding and code generation.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
7
7
|
"keywords": [
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"ora": "^9.1.0",
|
|
35
35
|
"prompts": "^2.4.2",
|
|
36
36
|
"yaml": "^2.7.0",
|
|
37
|
-
"@h-ai/core": "0.1.0-alpha.
|
|
37
|
+
"@h-ai/core": "0.1.0-alpha.21"
|
|
38
38
|
},
|
|
39
39
|
"devDependencies": {
|
|
40
40
|
"@types/fs-extra": "^11.0.4",
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
"lint": "eslint .",
|
|
53
53
|
"lint:fix": "eslint . --fix",
|
|
54
54
|
"test": "vitest run",
|
|
55
|
+
"test:e2e": "pnpm test:scaffold-gates",
|
|
55
56
|
"test:scaffold-gates": "pnpm build && node tests/run-scaffold-gates.mjs",
|
|
56
57
|
"test:watch": "vitest",
|
|
57
58
|
"test:coverage": "vitest run --coverage",
|
package/templates/README.md
CHANGED
|
@@ -9,13 +9,13 @@ templates/
|
|
|
9
9
|
├── base/ # 所有应用类型共用的骨架文件
|
|
10
10
|
│ ├── package.json.hbs # 动态:按 features 注入依赖
|
|
11
11
|
│ ├── vite.config.ts.hbs # 动态:按 hasI18n / hasUi 注入插件
|
|
12
|
-
│ ├── tsconfig.json
|
|
13
|
-
│ ├── svelte.config.js
|
|
14
|
-
│ ├── .gitignore
|
|
12
|
+
│ ├── tsconfig.json.hbs # 动态:SvelteKit / 纯 Svelte 5 分支
|
|
13
|
+
│ ├── svelte.config.js.hbs # 动态:SvelteKit / 纯 Svelte 5 分支
|
|
14
|
+
│ ├── .gitignore.hbs # 动态:纯 Svelte 5 应用不输出 .svelte-kit
|
|
15
15
|
│ ├── playwright.config.ts
|
|
16
16
|
│ └── src/
|
|
17
|
-
│ ├── app.html.hbs # 动态:
|
|
18
|
-
│ ├── app.d.ts
|
|
17
|
+
│ ├── app.html.hbs # 动态:SvelteKit 应用输出 app shell
|
|
18
|
+
│ ├── app.d.ts.hbs # 动态:SvelteKit 应用输出 App namespace
|
|
19
19
|
│ ├── app.css
|
|
20
20
|
│ ├── hooks.server.ts.hbs # 动态:按 features / hasI18n 组装 handle 序列
|
|
21
21
|
│ └── lib/server/
|
|
@@ -33,6 +33,10 @@ templates/
|
|
|
33
33
|
│ │ └── src/routes/
|
|
34
34
|
│ ├── api/ # 纯 API 服务(无 UI / 无 i18n)
|
|
35
35
|
│ │ └── src/routes/
|
|
36
|
+
│ ├── mobile-app/ # Svelte 5 + Vite + Capacitor 移动应用
|
|
37
|
+
│ │ ├── index.html.hbs
|
|
38
|
+
│ │ ├── messages/
|
|
39
|
+
│ │ └── src/App.svelte.hbs
|
|
36
40
|
│ └── fullstack/ # 前后端分离多包工程(contract / serv / web / app / desktop / miniapp 占位)
|
|
37
41
|
│ ├── packages/ # 共享 contract 与后端 serv 包
|
|
38
42
|
│ ├── apps/ # 多前端目标,按用户选择条件生成
|
|
@@ -52,17 +56,20 @@ templates/
|
|
|
52
56
|
│ └── project.inlang/
|
|
53
57
|
│ └── settings.json # Paraglide 项目配置
|
|
54
58
|
│
|
|
55
|
-
└── skills/ # AI Skill
|
|
59
|
+
└── skills/ # AI Skill 与各 appType 桥接指引
|
|
60
|
+
└── bridges/ # admin / api / website / h5 / mobile-app / fullstack 专属 AGENTS/Copilot/Claude
|
|
56
61
|
```
|
|
57
62
|
|
|
58
63
|
## AI Skill 模板(Single Source of Truth)
|
|
59
64
|
|
|
60
65
|
`templates/skills/` 是 CLI 生成共享 AI 上下文时的单一来源,同时用于 `hai create` 与 `hai add`。
|
|
61
66
|
|
|
62
|
-
-
|
|
63
|
-
- `copilot-instructions.md` 会复制到 `.github/copilot-instructions.md
|
|
64
|
-
- `AGENTS.md`、`CLAUDE.md
|
|
65
|
-
- `opencode.json`
|
|
67
|
+
- `hai create` 会把 `templates/skills/` 下所有 `hai-*` Skill 目录复制到 `.agents/skills/<skill>/`,再按 appType 排除互斥项(例如 fullstack 不复制 `hai-kit`;admin / website / h5 不复制 `hai-serv`、`hai-api-contract`、`hai-api-client`、`hai-capacitor`;mobile-app 不复制 `hai-core`、`hai-kit`、`hai-serv`、`hai-api-contract`)
|
|
68
|
+
- `bridges/<appType>/copilot-instructions.md` 会复制到 `.github/copilot-instructions.md`;没有专属文件时回退到通用桥接文件
|
|
69
|
+
- `bridges/<appType>/AGENTS.md`、`bridges/<appType>/CLAUDE.md` 会复制到项目根目录,确保不同样板工程使用自己的 AI 指引
|
|
70
|
+
- `opencode.json` 会复制到项目根目录
|
|
71
|
+
- `templates/skills/AGENTS.md`、`CLAUDE.md`、`copilot-instructions.md` 与 `opencode.json` 不是多余副本:它们是 generic fallback,主要服务于缺少 appType 上下文时的桥接复制与 `hai add` 回填 AI 支持
|
|
72
|
+
- `opencode.json` 使用 OpenCode 的 `instructions` 配置复用 `.github/copilot-instructions.md`;`.agents/skills/` 由 OpenCode 原生发现,不再写入过期的 `skills.paths`
|
|
66
73
|
- `CLAUDE.md` 作为 Claude Code 的原生项目指引入口,并通过 `@AGENTS.md` 复用共享规范;`.agents/skills/` 仍是共享参考目录,而非 Claude Code 的原生 project skills 目录
|
|
67
74
|
- `hai add` 只补齐缺失的 AI 支持文件,不覆盖用户已自定义的桥接文件,也不会自动删除遗留的 `.github/skills/`
|
|
68
75
|
|
|
@@ -77,23 +84,27 @@ templates/
|
|
|
77
84
|
|
|
78
85
|
所有 `.hbs` 文件可使用以下变量:
|
|
79
86
|
|
|
80
|
-
| 变量 | 类型 | 说明
|
|
81
|
-
| ---------------------- | --------- |
|
|
82
|
-
| `{{projectName}}` | `string` | 项目名称(如 `my-app`)
|
|
83
|
-
| `{{appType}}` | `string` |
|
|
84
|
-
| `{{hasUi}}` | `boolean` | 是否包含 UI(非 `api` 类型为 `true`)
|
|
85
|
-
| `{{hasI18n}}` | `boolean` | 是否启用 i18n(非 `api` 类型为 `true`)
|
|
86
|
-
| `{{
|
|
87
|
-
| `{{
|
|
88
|
-
| `{{
|
|
89
|
-
| `{{
|
|
90
|
-
| `{{
|
|
91
|
-
| `{{features.
|
|
92
|
-
| `{{features.
|
|
93
|
-
| `{{features.
|
|
94
|
-
| `{{features.
|
|
95
|
-
|
|
96
|
-
`
|
|
87
|
+
| 变量 | 类型 | 说明 |
|
|
88
|
+
| ---------------------- | --------- | ----------------------------------------- |
|
|
89
|
+
| `{{projectName}}` | `string` | 项目名称(如 `my-app`) |
|
|
90
|
+
| `{{appType}}` | `string` | 应用类型 |
|
|
91
|
+
| `{{hasUi}}` | `boolean` | 是否包含 UI(非 `api` 类型为 `true`) |
|
|
92
|
+
| `{{hasI18n}}` | `boolean` | 是否启用 i18n(非 `api` 类型为 `true`) |
|
|
93
|
+
| `{{isSvelteOnlyApp}}` | `boolean` | 是否为不依赖 SvelteKit 的纯 Svelte 5 应用 |
|
|
94
|
+
| `{{isCapacitorApp}}` | `boolean` | 是否为 Capacitor 移动应用 |
|
|
95
|
+
| `{{defaultLocale}}` | `string` | 默认语言,如 `zh-CN` |
|
|
96
|
+
| `{{packageManager}}` | `string` | 包管理器:`pnpm` / `npm` / `yarn` |
|
|
97
|
+
| `{{fullstack.*}}` | `object` | fullstack 类型专用上下文 |
|
|
98
|
+
| `{{features.iam}}` | `boolean` | 是否选中 iam feature |
|
|
99
|
+
| `{{features.db}}` | `boolean` | 是否选中 db feature |
|
|
100
|
+
| `{{features.cache}}` | `boolean` | 是否选中 cache feature |
|
|
101
|
+
| `{{features.crypto}}` | `boolean` | 是否选中 crypto feature |
|
|
102
|
+
| `{{features.storage}}` | `boolean` | 是否选中 storage feature |
|
|
103
|
+
| `{{features.ai}}` | `boolean` | 是否选中 ai feature |
|
|
104
|
+
|
|
105
|
+
`appType` 支持 `admin` / `website` / `h5` / `api` / `mobile-app` / `fullstack`。
|
|
106
|
+
|
|
107
|
+
`fullstack.*` 包含包名、前端选择、依赖版本、`contractExportName` 和原生壳 `nativeAppIdSegment`,用于渲染 contract / serv / 多端 UI / Capacitor / Tauri 模板。
|
|
97
108
|
|
|
98
109
|
### 常用条件写法
|
|
99
110
|
|
|
@@ -116,8 +127,8 @@ import { iam } from '@h-ai/iam'
|
|
|
116
127
|
模板引擎执行 6 个步骤:
|
|
117
128
|
|
|
118
129
|
1. **复制 `base/` 静态文件** → 项目根
|
|
119
|
-
2. **复制 `apps/{appType}/`
|
|
120
|
-
3. **叠加 feature 静态路由** → `src/routes
|
|
130
|
+
2. **复制 `apps/{appType}/` 专属文件** → 项目根(`messages/` 仅 `hasI18n` 时复制)
|
|
131
|
+
3. **叠加 feature 静态路由** → `src/routes/`(纯 Svelte 5 应用跳过 SvelteKit 路由)
|
|
121
132
|
4. **渲染所有 `.hbs` 文件** — `base/` + `apps/{appType}/` 输出到项目根;`features/*/routes*/` 输出到 `src/routes/`
|
|
122
133
|
5. **复制 `i18n/` 脚手架** → 项目根(仅 `hasI18n` 时)
|
|
123
134
|
6. **确保 `static/` 目录存在**
|
|
@@ -8,10 +8,15 @@
|
|
|
8
8
|
"nav_admin": "Enter Admin",
|
|
9
9
|
"page_home_title": "Admin Console",
|
|
10
10
|
"page_home_subtitle": "Built with hai Agent Framework",
|
|
11
|
+
"page_home_badge": "Powered by hai",
|
|
11
12
|
"page_dashboard_title": "Dashboard",
|
|
13
|
+
"page_dashboard_subtitle": "Overview of system operations",
|
|
12
14
|
"page_dashboard_total_users": "Total Users",
|
|
13
15
|
"page_dashboard_today_active": "Today Active",
|
|
16
|
+
"page_dashboard_revenue": "Monthly Revenue",
|
|
17
|
+
"page_dashboard_orders": "Pending Orders",
|
|
14
18
|
"page_settings_title": "System Settings",
|
|
19
|
+
"page_settings_subtitle": "Manage system configuration",
|
|
15
20
|
"page_settings_basic": "Basic Configuration",
|
|
16
21
|
"page_settings_desc": "Manage system settings here.",
|
|
17
22
|
"auth_login_title": "Login",
|
|
@@ -8,10 +8,15 @@
|
|
|
8
8
|
"nav_admin": "进入后台",
|
|
9
9
|
"page_home_title": "管理后台",
|
|
10
10
|
"page_home_subtitle": "基于 hai Agent Framework 构建",
|
|
11
|
+
"page_home_badge": "由 hai 驱动",
|
|
11
12
|
"page_dashboard_title": "仪表盘",
|
|
13
|
+
"page_dashboard_subtitle": "系统运营数据总览",
|
|
12
14
|
"page_dashboard_total_users": "总用户",
|
|
13
15
|
"page_dashboard_today_active": "今日活跃",
|
|
16
|
+
"page_dashboard_revenue": "本月营收",
|
|
17
|
+
"page_dashboard_orders": "待处理订单",
|
|
14
18
|
"page_settings_title": "系统设置",
|
|
19
|
+
"page_settings_subtitle": "管理系统配置项",
|
|
15
20
|
"page_settings_basic": "基本配置",
|
|
16
21
|
"page_settings_desc": "在此管理系统设置。",
|
|
17
22
|
"auth_login_title": "登录",
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{{!-- 管理后台根布局 --}}
|
|
2
|
-
<script lang=
|
|
2
|
+
<script lang='ts'>
|
|
3
3
|
/**
|
|
4
4
|
* 管理后台根布局
|
|
5
5
|
*/
|
|
6
6
|
import type { Snippet } from 'svelte'
|
|
7
|
-
import '../app.css'
|
|
8
7
|
{{#if hasI18n}}
|
|
9
8
|
import { browser } from '$app/environment'
|
|
10
|
-
import { setGlobalLocale } from '@h-ai/ui'
|
|
11
9
|
import { getLocale } from '$lib/paraglide/runtime.js'
|
|
10
|
+
import { setGlobalLocale } from '@h-ai/ui'
|
|
12
11
|
{{/if}}
|
|
12
|
+
import '../app.css'
|
|
13
13
|
|
|
14
14
|
interface Props {
|
|
15
15
|
children: Snippet
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
const { children }: Props = $props()
|
|
19
19
|
{{#if hasI18n}}
|
|
20
20
|
|
|
21
21
|
if (browser) {
|
|
@@ -25,6 +25,6 @@
|
|
|
25
25
|
{{/if}}
|
|
26
26
|
</script>
|
|
27
27
|
|
|
28
|
-
<div class=
|
|
28
|
+
<div class='min-h-screen bg-base-200'>
|
|
29
29
|
{@render children()}
|
|
30
30
|
</div>
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
{{!-- 管理后台首页 --}}
|
|
2
|
-
<script lang=
|
|
2
|
+
<script lang='ts'>
|
|
3
3
|
/**
|
|
4
4
|
* 管理后台首页 — 入口导航
|
|
5
5
|
*/
|
|
6
|
+
import { resolve } from '$app/paths'
|
|
6
7
|
{{#if hasI18n}}
|
|
7
8
|
import * as m from '$lib/paraglide/messages'
|
|
8
9
|
{{/if}}
|
|
10
|
+
import { Badge, Card } from '@h-ai/ui'
|
|
9
11
|
</script>
|
|
10
12
|
|
|
11
13
|
<svelte:head>
|
|
@@ -16,20 +18,38 @@
|
|
|
16
18
|
{{/if}}
|
|
17
19
|
</svelte:head>
|
|
18
20
|
|
|
19
|
-
<main class=
|
|
20
|
-
<
|
|
21
|
+
<main class='min-h-screen flex items-center justify-center p-6'>
|
|
22
|
+
<Card shadow='lg' padding='xl' class='w-full max-w-xl bg-base-100 text-center'>
|
|
21
23
|
{{#if hasI18n}}
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
<div class='flex justify-center'>
|
|
25
|
+
<Badge variant='primary'>
|
|
26
|
+
<span class='icon-[tabler--sparkles] size-4'></span>
|
|
27
|
+
{m.page_home_badge()}
|
|
28
|
+
</Badge>
|
|
29
|
+
</div>
|
|
30
|
+
<h1 class='mt-4 text-4xl font-black tracking-tight'>{m.app_title()}</h1>
|
|
31
|
+
<p class='mt-3 text-base-content/60'>{m.page_home_subtitle()}</p>
|
|
32
|
+
<div class='mt-8 flex flex-wrap gap-3 justify-center'>
|
|
33
|
+
<a href={resolve('/admin', {})} class='btn btn-primary'>
|
|
34
|
+
<span class='icon-[tabler--layout-dashboard] size-5'></span>
|
|
35
|
+
{m.nav_admin()}
|
|
36
|
+
</a>
|
|
26
37
|
</div>
|
|
27
38
|
{{else}}
|
|
28
|
-
<
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
39
|
+
<div class='flex justify-center'>
|
|
40
|
+
<Badge variant='primary'>
|
|
41
|
+
<span class='icon-[tabler--sparkles] size-4'></span>
|
|
42
|
+
由 hai 驱动
|
|
43
|
+
</Badge>
|
|
44
|
+
</div>
|
|
45
|
+
<h1 class='mt-4 text-4xl font-black tracking-tight'>管理后台</h1>
|
|
46
|
+
<p class='mt-3 text-base-content/60'>基于 hai Agent Framework 构建</p>
|
|
47
|
+
<div class='mt-8 flex flex-wrap gap-3 justify-center'>
|
|
48
|
+
<a href={resolve('/admin', {})} class='btn btn-primary'>
|
|
49
|
+
<span class='icon-[tabler--layout-dashboard] size-5'></span>
|
|
50
|
+
进入后台
|
|
51
|
+
</a>
|
|
32
52
|
</div>
|
|
33
53
|
{{/if}}
|
|
34
|
-
</
|
|
54
|
+
</Card>
|
|
35
55
|
</main>
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
{{!-- 后台管理布局(侧边栏 + 内容区) --}}
|
|
2
|
-
<script lang=
|
|
2
|
+
<script lang='ts'>
|
|
3
3
|
/**
|
|
4
4
|
* 后台管理布局(侧边栏 + 内容区)
|
|
5
5
|
*/
|
|
6
6
|
import type { Snippet } from 'svelte'
|
|
7
|
+
import { resolve } from '$app/paths'
|
|
8
|
+
import { page } from '$app/state'
|
|
7
9
|
{{#if hasI18n}}
|
|
8
10
|
import * as m from '$lib/paraglide/messages'
|
|
9
11
|
{{/if}}
|
|
@@ -12,33 +14,48 @@
|
|
|
12
14
|
children: Snippet
|
|
13
15
|
}
|
|
14
16
|
|
|
15
|
-
|
|
17
|
+
const { children }: Props = $props()
|
|
18
|
+
|
|
19
|
+
const navItems = $derived([
|
|
20
|
+
{{#if hasI18n}}
|
|
21
|
+
{ path: '/admin', label: m.nav_dashboard(), icon: 'icon-[tabler--layout-dashboard]' },
|
|
22
|
+
{ path: '/admin/settings', label: m.nav_settings(), icon: 'icon-[tabler--settings]' },
|
|
23
|
+
{{else}}
|
|
24
|
+
{ path: '/admin', label: '仪表盘', icon: 'icon-[tabler--layout-dashboard]' },
|
|
25
|
+
{ path: '/admin/settings', label: '设置', icon: 'icon-[tabler--settings]' },
|
|
26
|
+
{{/if}}
|
|
27
|
+
] as const)
|
|
16
28
|
</script>
|
|
17
29
|
|
|
18
|
-
<div class=
|
|
19
|
-
<input id=
|
|
20
|
-
<div class=
|
|
21
|
-
<label for=
|
|
22
|
-
|
|
30
|
+
<div class='drawer lg:drawer-open'>
|
|
31
|
+
<input id='admin-drawer' type='checkbox' class='drawer-toggle' />
|
|
32
|
+
<div class='drawer-content p-6'>
|
|
33
|
+
<label for='admin-drawer' class='btn btn-ghost btn-sm drawer-button lg:hidden mb-4'>
|
|
34
|
+
<span class='icon-[tabler--menu-2] size-5'></span>
|
|
23
35
|
</label>
|
|
24
36
|
{@render children()}
|
|
25
37
|
</div>
|
|
26
|
-
<div class=
|
|
27
|
-
<label for=
|
|
28
|
-
<nav class=
|
|
38
|
+
<div class='drawer-side'>
|
|
39
|
+
<label for='admin-drawer' class='drawer-overlay' aria-label='close sidebar'></label>
|
|
40
|
+
<nav class='menu p-4 w-64 min-h-full gap-1 bg-base-100 text-base-content border-r border-base-300/60'>
|
|
41
|
+
<div class='flex items-center gap-2 px-2 mb-6 text-xl font-bold'>
|
|
42
|
+
<span class='icon-[tabler--cube] size-6 text-primary'></span>
|
|
29
43
|
{{#if hasI18n}}
|
|
30
|
-
|
|
31
|
-
<ul>
|
|
32
|
-
<li><a href="/admin">{m.nav_dashboard()}</a></li>
|
|
33
|
-
<li><a href="/admin/settings">{m.nav_settings()}</a></li>
|
|
34
|
-
</ul>
|
|
44
|
+
{m.app_title()}
|
|
35
45
|
{{else}}
|
|
36
|
-
|
|
37
|
-
<ul>
|
|
38
|
-
<li><a href="/admin">仪表盘</a></li>
|
|
39
|
-
<li><a href="/admin/settings">设置</a></li>
|
|
40
|
-
</ul>
|
|
46
|
+
管理后台
|
|
41
47
|
{{/if}}
|
|
48
|
+
</div>
|
|
49
|
+
<ul class='gap-1'>
|
|
50
|
+
{#each navItems as item (item.path)}
|
|
51
|
+
<li>
|
|
52
|
+
<a href={resolve(item.path, {})} class:menu-active={page.url.pathname === item.path}>
|
|
53
|
+
<span class='{item.icon} size-5'></span>
|
|
54
|
+
{item.label}
|
|
55
|
+
</a>
|
|
56
|
+
</li>
|
|
57
|
+
{/each}
|
|
58
|
+
</ul>
|
|
42
59
|
</nav>
|
|
43
60
|
</div>
|
|
44
61
|
</div>
|
|
@@ -1,10 +1,27 @@
|
|
|
1
1
|
{{!-- 仪表盘页面 --}}
|
|
2
|
-
<script lang=
|
|
2
|
+
<script lang='ts'>
|
|
3
3
|
/**
|
|
4
4
|
* 仪表盘页面
|
|
5
5
|
*/
|
|
6
6
|
{{#if hasI18n}}
|
|
7
7
|
import * as m from '$lib/paraglide/messages'
|
|
8
|
+
{{/if}}
|
|
9
|
+
import { Card, PageHeader } from '@h-ai/ui'
|
|
10
|
+
{{#if hasI18n}}
|
|
11
|
+
|
|
12
|
+
const stats = $derived([
|
|
13
|
+
{ label: m.page_dashboard_total_users(), value: '0', icon: 'icon-[tabler--users]', accent: 'text-primary' },
|
|
14
|
+
{ label: m.page_dashboard_today_active(), value: '0', icon: 'icon-[tabler--activity]', accent: 'text-success' },
|
|
15
|
+
{ label: m.page_dashboard_revenue(), value: '¥0', icon: 'icon-[tabler--coin]', accent: 'text-warning' },
|
|
16
|
+
{ label: m.page_dashboard_orders(), value: '0', icon: 'icon-[tabler--shopping-cart]', accent: 'text-info' },
|
|
17
|
+
])
|
|
18
|
+
{{else}}
|
|
19
|
+
const stats = [
|
|
20
|
+
{ label: '总用户', value: '0', icon: 'icon-[tabler--users]', accent: 'text-primary' },
|
|
21
|
+
{ label: '今日活跃', value: '0', icon: 'icon-[tabler--activity]', accent: 'text-success' },
|
|
22
|
+
{ label: '本月营收', value: '¥0', icon: 'icon-[tabler--coin]', accent: 'text-warning' },
|
|
23
|
+
{ label: '待处理订单', value: '0', icon: 'icon-[tabler--shopping-cart]', accent: 'text-info' },
|
|
24
|
+
]
|
|
8
25
|
{{/if}}
|
|
9
26
|
</script>
|
|
10
27
|
|
|
@@ -17,29 +34,21 @@
|
|
|
17
34
|
</svelte:head>
|
|
18
35
|
|
|
19
36
|
{{#if hasI18n}}
|
|
20
|
-
<
|
|
21
|
-
|
|
22
|
-
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
23
|
-
<div class="stat bg-base-100 rounded-box shadow">
|
|
24
|
-
<div class="stat-title">{m.page_dashboard_total_users()}</div>
|
|
25
|
-
<div class="stat-value">0</div>
|
|
26
|
-
</div>
|
|
27
|
-
<div class="stat bg-base-100 rounded-box shadow">
|
|
28
|
-
<div class="stat-title">{m.page_dashboard_today_active()}</div>
|
|
29
|
-
<div class="stat-value">0</div>
|
|
30
|
-
</div>
|
|
31
|
-
</div>
|
|
37
|
+
<PageHeader title={m.page_dashboard_title()} description={m.page_dashboard_subtitle()} />
|
|
32
38
|
{{else}}
|
|
33
|
-
<
|
|
39
|
+
<PageHeader title='仪表盘' description='系统运营数据总览' />
|
|
40
|
+
{{/if}}
|
|
34
41
|
|
|
35
|
-
<div class=
|
|
36
|
-
|
|
37
|
-
<
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
42
|
+
<div class='grid grid-cols-1 sm:grid-cols-2 xl:grid-cols-4 gap-4'>
|
|
43
|
+
{#each stats as stat (stat.label)}
|
|
44
|
+
<Card shadow='sm' class='bg-base-100'>
|
|
45
|
+
<div class='flex items-center justify-between'>
|
|
46
|
+
<div>
|
|
47
|
+
<div class='text-sm text-base-content/55'>{stat.label}</div>
|
|
48
|
+
<div class='mt-1 text-3xl font-bold tracking-tight'>{stat.value}</div>
|
|
49
|
+
</div>
|
|
50
|
+
<span class='{stat.icon} {stat.accent} size-9'></span>
|
|
51
|
+
</div>
|
|
52
|
+
</Card>
|
|
53
|
+
{/each}
|
|
44
54
|
</div>
|
|
45
|
-
{{/if}}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{{!-- 设置页面 --}}
|
|
2
|
-
<script lang=
|
|
2
|
+
<script lang='ts'>
|
|
3
3
|
/**
|
|
4
4
|
* 设置页面
|
|
5
5
|
*/
|
|
6
6
|
{{#if hasI18n}}
|
|
7
7
|
import * as m from '$lib/paraglide/messages'
|
|
8
8
|
{{/if}}
|
|
9
|
+
import { Card, PageHeader } from '@h-ai/ui'
|
|
9
10
|
</script>
|
|
10
11
|
|
|
11
12
|
<svelte:head>
|
|
@@ -17,21 +18,23 @@
|
|
|
17
18
|
</svelte:head>
|
|
18
19
|
|
|
19
20
|
{{#if hasI18n}}
|
|
20
|
-
<
|
|
21
|
+
<PageHeader title={m.page_settings_title()} description={m.page_settings_subtitle()} />
|
|
21
22
|
|
|
22
|
-
<
|
|
23
|
-
<div class=
|
|
24
|
-
<
|
|
25
|
-
<
|
|
23
|
+
<Card shadow='sm' class='bg-base-100'>
|
|
24
|
+
<div class='flex items-center gap-2'>
|
|
25
|
+
<span class='icon-[tabler--adjustments] size-5 text-primary'></span>
|
|
26
|
+
<h2 class='text-base font-semibold'>{m.page_settings_basic()}</h2>
|
|
26
27
|
</div>
|
|
27
|
-
</
|
|
28
|
+
<p class='mt-2 text-sm text-base-content/60'>{m.page_settings_desc()}</p>
|
|
29
|
+
</Card>
|
|
28
30
|
{{else}}
|
|
29
|
-
<
|
|
31
|
+
<PageHeader title='系统设置' description='管理系统配置项' />
|
|
30
32
|
|
|
31
|
-
<
|
|
32
|
-
<div class=
|
|
33
|
-
<
|
|
34
|
-
<
|
|
33
|
+
<Card shadow='sm' class='bg-base-100'>
|
|
34
|
+
<div class='flex items-center gap-2'>
|
|
35
|
+
<span class='icon-[tabler--adjustments] size-5 text-primary'></span>
|
|
36
|
+
<h2 class='text-base font-semibold'>基本配置</h2>
|
|
35
37
|
</div>
|
|
36
|
-
|
|
38
|
+
<p class='mt-2 text-sm text-base-content/60'>在此管理系统设置。</p>
|
|
39
|
+
</Card>
|
|
37
40
|
{{/if}}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# {{api.contractPackageName}}
|
|
2
|
+
|
|
3
|
+
{{projectName}} API service 的共享 contract 包。
|
|
4
|
+
|
|
5
|
+
## 包含内容
|
|
6
|
+
|
|
7
|
+
- `app-contract.ts`:应用级路由定义
|
|
8
|
+
- `app-schemas.ts`:输入输出 Zod schema
|
|
9
|
+
- `{{projectName}}-contract.ts`:工程级 contract 聚合入口
|
|
10
|
+
|
|
11
|
+
## 常用命令
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pnpm --filter {{api.contractPackageName}} build
|
|
15
|
+
pnpm --filter {{api.contractPackageName}} test
|
|
16
|
+
```
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "{{api.contractPackageName}}",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.1.0",
|
|
5
|
+
"private": true,
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"main": "./dist/index.js",
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"files": [
|
|
16
|
+
"dist",
|
|
17
|
+
"README.md"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsup",
|
|
21
|
+
"typecheck": "tsc --noEmit",
|
|
22
|
+
"lint": "eslint .",
|
|
23
|
+
"test": "vitest run",
|
|
24
|
+
"test:watch": "vitest",
|
|
25
|
+
"clean": "rimraf dist .turbo"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@h-ai/api-contract": "{{haiPackageSpecifier}}",
|
|
29
|
+
"zod": "{{api.packageSpecifiers.zod}}"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "{{api.packageSpecifiers.nodeTypes}}",
|
|
33
|
+
"rimraf": "{{api.packageSpecifiers.rimraf}}",
|
|
34
|
+
"tsup": "{{api.packageSpecifiers.tsup}}",
|
|
35
|
+
"typescript": "{{api.packageSpecifiers.typescript}}",
|
|
36
|
+
"vitest": "{{api.packageSpecifiers.vitest}}"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { apiContract } from '@h-ai/api-contract'
|
|
2
|
+
import { AppEchoInputSchema, AppEchoOutputSchema, AppInfoOutputSchema } from './app-schemas.js'
|
|
3
|
+
|
|
4
|
+
/** 应用自有 app contract。 */
|
|
5
|
+
export const appContract = {
|
|
6
|
+
info: apiContract
|
|
7
|
+
.route({
|
|
8
|
+
method: 'POST',
|
|
9
|
+
path: '/app/info',
|
|
10
|
+
operationId: 'app.info',
|
|
11
|
+
summary: 'Get service info',
|
|
12
|
+
tags: ['app'],
|
|
13
|
+
})
|
|
14
|
+
.output(AppInfoOutputSchema),
|
|
15
|
+
echo: apiContract
|
|
16
|
+
.route({
|
|
17
|
+
method: 'POST',
|
|
18
|
+
path: '/app/echo',
|
|
19
|
+
operationId: 'app.echo',
|
|
20
|
+
summary: '{{#if features.iam}}Echo a message (auth required){{else}}Echo a message{{/if}}',
|
|
21
|
+
tags: ['app'],
|
|
22
|
+
})
|
|
23
|
+
.input(AppEchoInputSchema)
|
|
24
|
+
.output(AppEchoOutputSchema),
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export type AppContract = typeof appContract
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { apiContract } from '@h-ai/api-contract'
|
|
2
|
+
import { z } from 'zod'
|
|
3
|
+
|
|
4
|
+
/** 服务元信息响应数据。 */
|
|
5
|
+
export const AppInfoOutputDataSchema = z.object({
|
|
6
|
+
name: z.string(),
|
|
7
|
+
version: z.string(),
|
|
8
|
+
uptimeMs: z.number().int().nonnegative(),
|
|
9
|
+
transportEnabled: z.boolean(),
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
/** app.info 标准 HaiResult 输出。 */
|
|
13
|
+
export const AppInfoOutputSchema = apiContract.haiResultSchema(AppInfoOutputDataSchema)
|
|
14
|
+
|
|
15
|
+
/** 输入:单条文本消息(演示用,限制最大长度防止误用)。 */
|
|
16
|
+
export const AppEchoInputSchema = z.object({
|
|
17
|
+
message: z.string().min(1).max(2000),
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
/** 输出:原样回显 + 调用者快照。 */
|
|
21
|
+
export const AppEchoOutputDataSchema = z.object({
|
|
22
|
+
message: z.string(),
|
|
23
|
+
requestId: z.string(),
|
|
24
|
+
timestamp: z.string(),
|
|
25
|
+
userId: z.string().optional(),
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
/** app.echo 标准 HaiResult 输出。 */
|
|
29
|
+
export const AppEchoOutputSchema = apiContract.haiResultSchema(AppEchoOutputDataSchema)
|
|
30
|
+
|
|
31
|
+
export type AppInfoOutputData = z.infer<typeof AppInfoOutputDataSchema>
|
|
32
|
+
export type AppEchoInput = z.infer<typeof AppEchoInputSchema>
|
|
33
|
+
export type AppEchoOutputData = z.infer<typeof AppEchoOutputDataSchema>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { apiContract } from '@h-ai/api-contract'
|
|
2
|
+
import { appContract } from './app-contract.js'
|
|
3
|
+
|
|
4
|
+
/** 工程级应用 contract。 */
|
|
5
|
+
export const {{api.contractExportName}} = apiContract.create({
|
|
6
|
+
{{#if features.iam}} iam: apiContract.iam,
|
|
7
|
+
{{/if}}{{#if features.storage}} storage: apiContract.storage,
|
|
8
|
+
{{/if}}{{#if features.ai}} ai: apiContract.ai,
|
|
9
|
+
{{/if}} app: appContract,
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
export type ApiWorkspaceContract = typeof {{api.contractExportName}}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { AppEchoInputSchema, {{api.contractExportName}} } from '../src/index.js'
|
|
3
|
+
|
|
4
|
+
describe('{{api.contractPackageName}}', () => {
|
|
5
|
+
it('includes generated contract routes', () => {
|
|
6
|
+
expect({{api.contractExportName}}.app.info).toBeDefined()
|
|
7
|
+
expect({{api.contractExportName}}.app.echo).toBeDefined()
|
|
8
|
+
{{#if features.iam}} expect({{api.contractExportName}}.iam.auth.login).toBeDefined()
|
|
9
|
+
{{/if}}{{#if features.storage}} expect({{api.contractExportName}}.storage.presignedUrls.createUpload).toBeDefined()
|
|
10
|
+
{{/if}}{{#if features.ai}} expect({{api.contractExportName}}.ai.chats.createCompletion).toBeDefined()
|
|
11
|
+
{{/if}} })
|
|
12
|
+
|
|
13
|
+
it('validates app.echo input length', () => {
|
|
14
|
+
expect(AppEchoInputSchema.safeParse({ message: 'hello' }).success).toBe(true)
|
|
15
|
+
expect(AppEchoInputSchema.safeParse({ message: '' }).success).toBe(false)
|
|
16
|
+
expect(AppEchoInputSchema.safeParse({ message: 'x'.repeat(2001) }).success).toBe(false)
|
|
17
|
+
})
|
|
18
|
+
})
|