@h-ai/cli 0.1.0-alpha5
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/LICENSE +202 -0
- package/README.md +167 -0
- package/dist/chunk-2H7UOFLK.js +10 -0
- package/dist/chunk-2H7UOFLK.js.map +1 -0
- package/dist/chunk-LANIDJC7.js +659 -0
- package/dist/chunk-LANIDJC7.js.map +1 -0
- package/dist/chunk-YV7WPUI6.js +206 -0
- package/dist/chunk-YV7WPUI6.js.map +1 -0
- package/dist/config-templates-S5RI2MC6.js +5 -0
- package/dist/config-templates-S5RI2MC6.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1645 -0
- package/dist/index.js.map +1 -0
- package/dist/skill-templates-N5DU5FNX.js +5 -0
- package/dist/skill-templates-N5DU5FNX.js.map +1 -0
- package/dist/src-XJ6YXNAF.js +15030 -0
- package/dist/src-XJ6YXNAF.js.map +1 -0
- package/package.json +59 -0
- package/templates/README.md +126 -0
- package/templates/apps/admin/messages/en-US.json +33 -0
- package/templates/apps/admin/messages/zh-CN.json +33 -0
- package/templates/apps/admin/src/routes/+layout.svelte.hbs +30 -0
- package/templates/apps/admin/src/routes/+page.svelte.hbs +35 -0
- package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +44 -0
- package/templates/apps/admin/src/routes/admin/+page.svelte.hbs +45 -0
- package/templates/apps/admin/src/routes/admin/settings/+page.svelte.hbs +37 -0
- package/templates/apps/admin/src/routes/api/health/+server.ts +12 -0
- package/templates/apps/android-app/.env.hbs +3 -0
- package/templates/apps/android-app/capacitor.config.ts.hbs +12 -0
- package/templates/apps/android-app/messages/en-US.json +24 -0
- package/templates/apps/android-app/messages/zh-CN.json +24 -0
- package/templates/apps/android-app/src/lib/api.ts.hbs +30 -0
- package/templates/apps/android-app/src/lib/capacitor.ts +21 -0
- package/templates/apps/android-app/src/routes/+layout.svelte.hbs +42 -0
- package/templates/apps/android-app/src/routes/+layout.ts +7 -0
- package/templates/apps/android-app/src/routes/+page.svelte.hbs +27 -0
- package/templates/apps/api/src/routes/+layout.svelte +14 -0
- package/templates/apps/api/src/routes/+page.svelte +11 -0
- package/templates/apps/api/src/routes/api/v1/health/+server.ts +14 -0
- package/templates/apps/api/src/routes/api/v1/items/+server.ts +37 -0
- package/templates/apps/api/src/routes/api/v1/items/[id]/+server.ts +30 -0
- package/templates/apps/h5/messages/en-US.json +37 -0
- package/templates/apps/h5/messages/zh-CN.json +37 -0
- package/templates/apps/h5/src/routes/+layout.svelte.hbs +57 -0
- package/templates/apps/h5/src/routes/+page.svelte.hbs +27 -0
- package/templates/apps/h5/src/routes/discover/+page.svelte.hbs +27 -0
- package/templates/apps/h5/src/routes/profile/+page.svelte.hbs +27 -0
- package/templates/apps/website/messages/en-US.json +32 -0
- package/templates/apps/website/messages/zh-CN.json +32 -0
- package/templates/apps/website/src/routes/+layout.svelte.hbs +66 -0
- package/templates/apps/website/src/routes/+page.svelte.hbs +33 -0
- package/templates/apps/website/src/routes/about/+page.svelte.hbs +27 -0
- package/templates/apps/website/src/routes/api/health/+server.ts +12 -0
- package/templates/apps/website/src/routes/contact/+page.svelte.hbs +59 -0
- package/templates/apps/website/src/routes/services/+page.svelte.hbs +63 -0
- package/templates/base/e2e/helpers.ts +49 -0
- package/templates/base/package.json.hbs +67 -0
- package/templates/base/playwright.config.ts +32 -0
- package/templates/base/src/app.css +2 -0
- package/templates/base/src/app.d.ts.hbs +18 -0
- package/templates/base/src/app.html.hbs +16 -0
- package/templates/base/src/hooks.server.ts.hbs +123 -0
- package/templates/base/src/lib/server/init.ts.hbs +190 -0
- package/templates/base/svelte.config.js.hbs +30 -0
- package/templates/base/tsconfig.json +8 -0
- package/templates/base/vite.config.ts.hbs +27 -0
- package/templates/features/ai/routes/api/chat/+server.ts +26 -0
- package/templates/features/datapipe/routes/api/datapipe/pipeline/+server.ts +41 -0
- package/templates/features/iam/routes-admin/(auth)/+layout.svelte.hbs +21 -0
- package/templates/features/iam/routes-admin/(auth)/auth/login/+page.svelte.hbs +98 -0
- package/templates/features/iam/routes-admin/(auth)/auth/register/+page.svelte.hbs +124 -0
- package/templates/features/iam/routes-h5/auth/login/+page.svelte.hbs +98 -0
- package/templates/features/iam/routes-h5/auth/register/+page.svelte.hbs +114 -0
- package/templates/features/iam/routes-shared/api/auth/login/+server.ts +32 -0
- package/templates/features/iam/routes-shared/api/auth/logout/+server.ts +15 -0
- package/templates/features/iam/routes-shared/api/auth/me/+server.ts +12 -0
- package/templates/features/iam/routes-shared/api/auth/register/+server.ts +26 -0
- package/templates/features/payment/routes/api/v1/payment/create/+server.ts +30 -0
- package/templates/features/payment/routes/api/v1/payment/notify/[provider]/+server.ts +42 -0
- package/templates/features/payment/routes/api/v1/payment/query/[orderNo]/+server.ts +25 -0
- package/templates/features/storage/routes/api/upload/+server.ts +35 -0
- package/templates/features/vecdb/routes/api/vecdb/search/+server.ts +36 -0
- package/templates/i18n/project.inlang/settings.json +11 -0
- package/templates/skills/AGENTS.md +26 -0
- package/templates/skills/CLAUDE.md +12 -0
- package/templates/skills/copilot-instructions.md +61 -0
- package/templates/skills/hai-ai/SKILL.md +659 -0
- package/templates/skills/hai-api-client/SKILL.md +346 -0
- package/templates/skills/hai-app-create/SKILL.md +371 -0
- package/templates/skills/hai-app-review/SKILL.md +156 -0
- package/templates/skills/hai-app-tests/SKILL.md +468 -0
- package/templates/skills/hai-audit/SKILL.md +141 -0
- package/templates/skills/hai-build/SKILL.md +319 -0
- package/templates/skills/hai-cache/SKILL.md +184 -0
- package/templates/skills/hai-capacitor/SKILL.md +389 -0
- package/templates/skills/hai-core/SKILL.md +544 -0
- package/templates/skills/hai-crypto/SKILL.md +183 -0
- package/templates/skills/hai-datapipe/SKILL.md +214 -0
- package/templates/skills/hai-deploy/SKILL.md +210 -0
- package/templates/skills/hai-iam/SKILL.md +355 -0
- package/templates/skills/hai-kit/SKILL.md +319 -0
- package/templates/skills/hai-payment/SKILL.md +289 -0
- package/templates/skills/hai-reach/SKILL.md +325 -0
- package/templates/skills/hai-reldb/SKILL.md +459 -0
- package/templates/skills/hai-scheduler/SKILL.md +242 -0
- package/templates/skills/hai-storage/SKILL.md +230 -0
- package/templates/skills/hai-ui/SKILL.md +275 -0
- package/templates/skills/hai-vecdb/SKILL.md +273 -0
- package/templates/skills/opencode.json +11 -0
package/package.json
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@h-ai/cli",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.1.0-alpha5",
|
|
5
|
+
"description": "Hai Framework CLI for project scaffolding and code generation.",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"hai",
|
|
9
|
+
"cli",
|
|
10
|
+
"scaffold",
|
|
11
|
+
"generator"
|
|
12
|
+
],
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"bin": {
|
|
20
|
+
"hai": "./dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist",
|
|
24
|
+
"templates"
|
|
25
|
+
],
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"cac": "^7.0.0",
|
|
31
|
+
"chalk": "^5.4.1",
|
|
32
|
+
"fs-extra": "^11.2.0",
|
|
33
|
+
"handlebars": "^4.7.8",
|
|
34
|
+
"ora": "^9.1.0",
|
|
35
|
+
"prompts": "^2.4.2",
|
|
36
|
+
"yaml": "^2.7.0",
|
|
37
|
+
"@h-ai/core": "0.1.0-alpha5"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"@types/fs-extra": "^11.0.4",
|
|
41
|
+
"@types/node": "^25.1.0",
|
|
42
|
+
"@types/prompts": "^2.4.9",
|
|
43
|
+
"rimraf": "^6.0.1",
|
|
44
|
+
"tsup": "^8.3.5",
|
|
45
|
+
"typescript": "^5.7.2",
|
|
46
|
+
"vitest": "^4.0.18"
|
|
47
|
+
},
|
|
48
|
+
"scripts": {
|
|
49
|
+
"build": "tsup",
|
|
50
|
+
"dev": "tsup --watch",
|
|
51
|
+
"typecheck": "tsc --noEmit",
|
|
52
|
+
"lint": "eslint .",
|
|
53
|
+
"lint:fix": "eslint . --fix",
|
|
54
|
+
"test": "vitest run",
|
|
55
|
+
"test:watch": "vitest",
|
|
56
|
+
"test:coverage": "vitest run --coverage",
|
|
57
|
+
"clean": "rimraf dist .turbo"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# CLI Templates
|
|
2
|
+
|
|
3
|
+
此目录包含 `hai create` 命令使用的项目模板文件。
|
|
4
|
+
|
|
5
|
+
## 目录结构
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
templates/
|
|
9
|
+
├── base/ # 所有应用类型共用的骨架文件
|
|
10
|
+
│ ├── package.json.hbs # 动态:按 features 注入依赖
|
|
11
|
+
│ ├── vite.config.ts.hbs # 动态:按 hasI18n / hasUi 注入插件
|
|
12
|
+
│ ├── tsconfig.json
|
|
13
|
+
│ ├── svelte.config.js
|
|
14
|
+
│ ├── .gitignore
|
|
15
|
+
│ ├── playwright.config.ts
|
|
16
|
+
│ └── src/
|
|
17
|
+
│ ├── app.html.hbs # 动态:i18n 时输出 %lang% 占位符
|
|
18
|
+
│ ├── app.d.ts
|
|
19
|
+
│ ├── app.css
|
|
20
|
+
│ ├── hooks.server.ts.hbs # 动态:按 features / hasI18n 组装 handle 序列
|
|
21
|
+
│ └── lib/server/
|
|
22
|
+
│ └── init.ts.hbs # 动态:按 features 注入模块初始化
|
|
23
|
+
│
|
|
24
|
+
├── apps/ # 应用类型专属路由与页面
|
|
25
|
+
│ ├── admin/ # 管理后台
|
|
26
|
+
│ │ ├── messages/ # i18n 消息文件(zh-CN / en-US)
|
|
27
|
+
│ │ └── src/routes/ # +page / +layout .svelte.hbs
|
|
28
|
+
│ ├── website/ # 企业官网
|
|
29
|
+
│ │ ├── messages/
|
|
30
|
+
│ │ └── src/routes/
|
|
31
|
+
│ ├── h5/ # H5 移动端
|
|
32
|
+
│ │ ├── messages/
|
|
33
|
+
│ │ └── src/routes/
|
|
34
|
+
│ └── api/ # 纯 API 服务(无 UI / 无 i18n)
|
|
35
|
+
│ └── src/routes/
|
|
36
|
+
│
|
|
37
|
+
├── features/ # 可选 feature 路由(叠加到 src/routes/)
|
|
38
|
+
│ ├── iam/
|
|
39
|
+
│ │ ├── routes-shared/ # 所有应用类型共用(API 端点)
|
|
40
|
+
│ │ ├── routes-admin/ # admin 专属(登录/注册页 .hbs)
|
|
41
|
+
│ │ └── routes-h5/ # h5 专属(登录/注册页 .hbs)
|
|
42
|
+
│ ├── storage/
|
|
43
|
+
│ │ └── routes/ # 上传 API
|
|
44
|
+
│ └── ai/
|
|
45
|
+
│ └── routes/ # 聊天流 API
|
|
46
|
+
│
|
|
47
|
+
├── i18n/ # i18n 脚手架(hasI18n 时复制到项目根)
|
|
48
|
+
│ └── project.inlang/
|
|
49
|
+
│ └── settings.json # Paraglide 项目配置
|
|
50
|
+
│
|
|
51
|
+
└── skills/ # AI Skill 单一来源模板(分发到 .agents/skills/)
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## AI Skill 模板(Single Source of Truth)
|
|
55
|
+
|
|
56
|
+
`templates/skills/` 是 CLI 生成共享 AI 上下文时的单一来源,同时用于 `hai create` 与 `hai add`。
|
|
57
|
+
|
|
58
|
+
- 每个 Skill 目录会复制到 `.agents/skills/<skill>/`
|
|
59
|
+
- `copilot-instructions.md` 会复制到 `.github/copilot-instructions.md`,并引导 Copilot/其他助手读取 `.agents/skills/`
|
|
60
|
+
- `AGENTS.md`、`CLAUDE.md`、`opencode.json` 会复制到项目根目录
|
|
61
|
+
- `opencode.json` 使用 OpenCode 的 `instructions` 与 `skills.paths` 配置,将项目级指令与 Skill 目录显式指向 `AGENTS.md` 和 `.agents/skills/`
|
|
62
|
+
- `CLAUDE.md` 作为 Claude Code 的原生项目指引入口,并通过 `@AGENTS.md` 复用共享规范;`.agents/skills/` 仍是共享参考目录,而非 Claude Code 的原生 project skills 目录
|
|
63
|
+
- `hai add` 只补齐缺失的 AI 支持文件,不覆盖用户已自定义的桥接文件,也不会自动删除遗留的 `.github/skills/`
|
|
64
|
+
|
|
65
|
+
## 文件类型说明
|
|
66
|
+
|
|
67
|
+
| 类型 | 处理方式 |
|
|
68
|
+
| ------------------------------------------ | -------------------------------------------- |
|
|
69
|
+
| 普通文件(`.ts` / `.svelte` / `.json` 等) | 直接复制,内容不变 |
|
|
70
|
+
| `.hbs` 文件 | 经 Handlebars 渲染后输出(去掉 `.hbs` 后缀) |
|
|
71
|
+
|
|
72
|
+
## 渲染上下文(TemplateContext)
|
|
73
|
+
|
|
74
|
+
所有 `.hbs` 文件可使用以下变量:
|
|
75
|
+
|
|
76
|
+
| 变量 | 类型 | 说明 |
|
|
77
|
+
| ---------------------- | --------- | -------------------------------------------- |
|
|
78
|
+
| `{{projectName}}` | `string` | 项目名称(如 `my-app`) |
|
|
79
|
+
| `{{appType}}` | `string` | 应用类型:`admin` / `website` / `h5` / `api` |
|
|
80
|
+
| `{{hasUi}}` | `boolean` | 是否包含 UI(非 `api` 类型为 `true`) |
|
|
81
|
+
| `{{hasI18n}}` | `boolean` | 是否启用 i18n(非 `api` 类型为 `true`) |
|
|
82
|
+
| `{{defaultLocale}}` | `string` | 默认语言,如 `zh-CN` |
|
|
83
|
+
| `{{packageManager}}` | `string` | 包管理器:`pnpm` / `npm` / `yarn` |
|
|
84
|
+
| `{{features.iam}}` | `boolean` | 是否选中 iam feature |
|
|
85
|
+
| `{{features.db}}` | `boolean` | 是否选中 db feature |
|
|
86
|
+
| `{{features.cache}}` | `boolean` | 是否选中 cache feature |
|
|
87
|
+
| `{{features.crypto}}` | `boolean` | 是否选中 crypto feature |
|
|
88
|
+
| `{{features.storage}}` | `boolean` | 是否选中 storage feature |
|
|
89
|
+
| `{{features.ai}}` | `boolean` | 是否选中 ai feature |
|
|
90
|
+
|
|
91
|
+
### 常用条件写法
|
|
92
|
+
|
|
93
|
+
```handlebars
|
|
94
|
+
{{!-- 按 feature 条件注入内容 --}}
|
|
95
|
+
{{#if features.iam}}
|
|
96
|
+
import { iam } from '@h-ai/iam'
|
|
97
|
+
{{/if}}
|
|
98
|
+
|
|
99
|
+
{{!-- 按 i18n 条件切换内容 --}}
|
|
100
|
+
{{#if hasI18n}}
|
|
101
|
+
<title>{m.page_title()}</title>
|
|
102
|
+
{{else}}
|
|
103
|
+
<title>首页</title>
|
|
104
|
+
{{/if}}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## 生成流程
|
|
108
|
+
|
|
109
|
+
模板引擎执行 6 个步骤:
|
|
110
|
+
|
|
111
|
+
1. **复制 `base/` 静态文件** → 项目根
|
|
112
|
+
2. **复制 `apps/{appType}/` 路由** → 项目根(`messages/` 仅 `hasI18n` 时复制)
|
|
113
|
+
3. **叠加 feature 静态路由** → `src/routes/`
|
|
114
|
+
4. **渲染所有 `.hbs` 文件** — `base/` + `apps/{appType}/` 输出到项目根;`features/*/routes*/` 输出到 `src/routes/`
|
|
115
|
+
5. **复制 `i18n/` 脚手架** → 项目根(仅 `hasI18n` 时)
|
|
116
|
+
6. **确保 `static/` 目录存在**
|
|
117
|
+
|
|
118
|
+
## 新增模板
|
|
119
|
+
|
|
120
|
+
### 新增应用页面
|
|
121
|
+
|
|
122
|
+
在 `apps/{appType}/src/routes/` 下创建 `.svelte` 或 `.svelte.hbs` 文件。若含用户可见文本,使用 `.hbs` 并加 `{{#if hasI18n}}` 条件,同时在对应的 `apps/{appType}/messages/` 里补充 i18n key。
|
|
123
|
+
|
|
124
|
+
### 新增 feature 路由
|
|
125
|
+
|
|
126
|
+
在 `features/{featureId}/routes-shared/`(API 路由)或 `features/{featureId}/routes-{appType}/`(UI 页面)下创建文件,然后在 `template-engine.ts` 的 `FEATURE_ROUTE_DIRS` / `FEATURE_APP_ROUTE_DIRS` 中注册该目录。
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"app_title": "Admin Console",
|
|
3
|
+
"app_description": "Admin console built with hai Agent Framework",
|
|
4
|
+
"meta_description": "Admin Console — Enterprise management system",
|
|
5
|
+
"nav_home": "Home",
|
|
6
|
+
"nav_dashboard": "Dashboard",
|
|
7
|
+
"nav_settings": "Settings",
|
|
8
|
+
"nav_admin": "Enter Admin",
|
|
9
|
+
"page_home_title": "Admin Console",
|
|
10
|
+
"page_home_subtitle": "Built with hai Agent Framework",
|
|
11
|
+
"page_dashboard_title": "Dashboard",
|
|
12
|
+
"page_dashboard_total_users": "Total Users",
|
|
13
|
+
"page_dashboard_today_active": "Today Active",
|
|
14
|
+
"page_settings_title": "System Settings",
|
|
15
|
+
"page_settings_basic": "Basic Configuration",
|
|
16
|
+
"page_settings_desc": "Manage system settings here.",
|
|
17
|
+
"auth_login_title": "Login",
|
|
18
|
+
"auth_login_submit": "Login",
|
|
19
|
+
"auth_login_loading": "Logging in...",
|
|
20
|
+
"auth_login_failed": "Login failed",
|
|
21
|
+
"auth_login_to_register": "No account? Register now",
|
|
22
|
+
"auth_register_title": "Register",
|
|
23
|
+
"auth_register_submit": "Register",
|
|
24
|
+
"auth_register_loading": "Registering...",
|
|
25
|
+
"auth_register_failed": "Registration failed",
|
|
26
|
+
"auth_register_to_login": "Already have an account? Login now",
|
|
27
|
+
"auth_label_username": "Username",
|
|
28
|
+
"auth_label_email": "Email",
|
|
29
|
+
"auth_label_password": "Password",
|
|
30
|
+
"auth_label_confirm_password": "Confirm Password",
|
|
31
|
+
"auth_error_network": "Network error",
|
|
32
|
+
"auth_error_password_mismatch": "Passwords do not match"
|
|
33
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"app_title": "管理后台",
|
|
3
|
+
"app_description": "基于 hai Agent Framework 构建的管理后台",
|
|
4
|
+
"meta_description": "管理后台 — 企业级管理系统",
|
|
5
|
+
"nav_home": "首页",
|
|
6
|
+
"nav_dashboard": "仪表盘",
|
|
7
|
+
"nav_settings": "设置",
|
|
8
|
+
"nav_admin": "进入后台",
|
|
9
|
+
"page_home_title": "管理后台",
|
|
10
|
+
"page_home_subtitle": "基于 hai Agent Framework 构建",
|
|
11
|
+
"page_dashboard_title": "仪表盘",
|
|
12
|
+
"page_dashboard_total_users": "总用户",
|
|
13
|
+
"page_dashboard_today_active": "今日活跃",
|
|
14
|
+
"page_settings_title": "系统设置",
|
|
15
|
+
"page_settings_basic": "基本配置",
|
|
16
|
+
"page_settings_desc": "在此管理系统设置。",
|
|
17
|
+
"auth_login_title": "登录",
|
|
18
|
+
"auth_login_submit": "登录",
|
|
19
|
+
"auth_login_loading": "登录中...",
|
|
20
|
+
"auth_login_failed": "登录失败",
|
|
21
|
+
"auth_login_to_register": "没有账号?立即注册",
|
|
22
|
+
"auth_register_title": "注册",
|
|
23
|
+
"auth_register_submit": "注册",
|
|
24
|
+
"auth_register_loading": "注册中...",
|
|
25
|
+
"auth_register_failed": "注册失败",
|
|
26
|
+
"auth_register_to_login": "已有账号?立即登录",
|
|
27
|
+
"auth_label_username": "用户名",
|
|
28
|
+
"auth_label_email": "邮箱",
|
|
29
|
+
"auth_label_password": "密码",
|
|
30
|
+
"auth_label_confirm_password": "确认密码",
|
|
31
|
+
"auth_error_network": "网络错误",
|
|
32
|
+
"auth_error_password_mismatch": "密码不一致"
|
|
33
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{{!-- 管理后台根布局 --}}
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
/**
|
|
4
|
+
* 管理后台根布局
|
|
5
|
+
*/
|
|
6
|
+
import type { Snippet } from 'svelte'
|
|
7
|
+
import '../app.css'
|
|
8
|
+
{{#if hasI18n}}
|
|
9
|
+
import { browser } from '$app/environment'
|
|
10
|
+
import { setGlobalLocale } from '@h-ai/ui'
|
|
11
|
+
import { getLocale } from '$lib/paraglide/runtime.js'
|
|
12
|
+
{{/if}}
|
|
13
|
+
|
|
14
|
+
interface Props {
|
|
15
|
+
children: Snippet
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let { children }: Props = $props()
|
|
19
|
+
{{#if hasI18n}}
|
|
20
|
+
|
|
21
|
+
if (browser) {
|
|
22
|
+
const paraglideLocale = getLocale()
|
|
23
|
+
setGlobalLocale(paraglideLocale)
|
|
24
|
+
}
|
|
25
|
+
{{/if}}
|
|
26
|
+
</script>
|
|
27
|
+
|
|
28
|
+
<div class="min-h-screen bg-base-200">
|
|
29
|
+
{@render children()}
|
|
30
|
+
</div>
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{{!-- 管理后台首页 --}}
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
/**
|
|
4
|
+
* 管理后台首页 — 入口导航
|
|
5
|
+
*/
|
|
6
|
+
{{#if hasI18n}}
|
|
7
|
+
import * as m from '$lib/paraglide/messages'
|
|
8
|
+
{{/if}}
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<svelte:head>
|
|
12
|
+
{{#if hasI18n}}
|
|
13
|
+
<title>{m.app_title()}</title>
|
|
14
|
+
{{else}}
|
|
15
|
+
<title>管理后台</title>
|
|
16
|
+
{{/if}}
|
|
17
|
+
</svelte:head>
|
|
18
|
+
|
|
19
|
+
<main class="min-h-screen flex items-center justify-center">
|
|
20
|
+
<div class="text-center">
|
|
21
|
+
{{#if hasI18n}}
|
|
22
|
+
<h1 class="text-4xl font-bold mb-4">{m.app_title()}</h1>
|
|
23
|
+
<p class="text-gray-600 mb-8">{m.page_home_subtitle()}</p>
|
|
24
|
+
<div class="flex gap-4 justify-center">
|
|
25
|
+
<a href="/admin" class="btn btn-primary">{m.nav_admin()}</a>
|
|
26
|
+
</div>
|
|
27
|
+
{{else}}
|
|
28
|
+
<h1 class="text-4xl font-bold mb-4">管理后台</h1>
|
|
29
|
+
<p class="text-gray-600 mb-8">基于 hai Agent Framework 构建</p>
|
|
30
|
+
<div class="flex gap-4 justify-center">
|
|
31
|
+
<a href="/admin" class="btn btn-primary">进入后台</a>
|
|
32
|
+
</div>
|
|
33
|
+
{{/if}}
|
|
34
|
+
</div>
|
|
35
|
+
</main>
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{{!-- 后台管理布局(侧边栏 + 内容区) --}}
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
/**
|
|
4
|
+
* 后台管理布局(侧边栏 + 内容区)
|
|
5
|
+
*/
|
|
6
|
+
import type { Snippet } from 'svelte'
|
|
7
|
+
{{#if hasI18n}}
|
|
8
|
+
import * as m from '$lib/paraglide/messages'
|
|
9
|
+
{{/if}}
|
|
10
|
+
|
|
11
|
+
interface Props {
|
|
12
|
+
children: Snippet
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let { children }: Props = $props()
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<div class="drawer lg:drawer-open">
|
|
19
|
+
<input id="admin-drawer" type="checkbox" class="drawer-toggle" />
|
|
20
|
+
<div class="drawer-content p-6">
|
|
21
|
+
<label for="admin-drawer" class="btn btn-ghost drawer-button lg:hidden mb-4">
|
|
22
|
+
☰
|
|
23
|
+
</label>
|
|
24
|
+
{@render children()}
|
|
25
|
+
</div>
|
|
26
|
+
<div class="drawer-side">
|
|
27
|
+
<label for="admin-drawer" class="drawer-overlay"></label>
|
|
28
|
+
<nav class="menu p-4 w-64 min-h-full bg-base-100 text-base-content">
|
|
29
|
+
{{#if hasI18n}}
|
|
30
|
+
<div class="text-xl font-bold mb-6 px-2">{m.app_title()}</div>
|
|
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>
|
|
35
|
+
{{else}}
|
|
36
|
+
<div class="text-xl font-bold mb-6 px-2">管理后台</div>
|
|
37
|
+
<ul>
|
|
38
|
+
<li><a href="/admin">仪表盘</a></li>
|
|
39
|
+
<li><a href="/admin/settings">设置</a></li>
|
|
40
|
+
</ul>
|
|
41
|
+
{{/if}}
|
|
42
|
+
</nav>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{{!-- 仪表盘页面 --}}
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
/**
|
|
4
|
+
* 仪表盘页面
|
|
5
|
+
*/
|
|
6
|
+
{{#if hasI18n}}
|
|
7
|
+
import * as m from '$lib/paraglide/messages'
|
|
8
|
+
{{/if}}
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<svelte:head>
|
|
12
|
+
{{#if hasI18n}}
|
|
13
|
+
<title>{m.page_dashboard_title()}</title>
|
|
14
|
+
{{else}}
|
|
15
|
+
<title>仪表盘</title>
|
|
16
|
+
{{/if}}
|
|
17
|
+
</svelte:head>
|
|
18
|
+
|
|
19
|
+
{{#if hasI18n}}
|
|
20
|
+
<h1 class="text-2xl font-bold mb-6">{m.page_dashboard_title()}</h1>
|
|
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>
|
|
32
|
+
{{else}}
|
|
33
|
+
<h1 class="text-2xl font-bold mb-6">仪表盘</h1>
|
|
34
|
+
|
|
35
|
+
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
36
|
+
<div class="stat bg-base-100 rounded-box shadow">
|
|
37
|
+
<div class="stat-title">总用户</div>
|
|
38
|
+
<div class="stat-value">0</div>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="stat bg-base-100 rounded-box shadow">
|
|
41
|
+
<div class="stat-title">今日活跃</div>
|
|
42
|
+
<div class="stat-value">0</div>
|
|
43
|
+
</div>
|
|
44
|
+
</div>
|
|
45
|
+
{{/if}}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{{!-- 设置页面 --}}
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
/**
|
|
4
|
+
* 设置页面
|
|
5
|
+
*/
|
|
6
|
+
{{#if hasI18n}}
|
|
7
|
+
import * as m from '$lib/paraglide/messages'
|
|
8
|
+
{{/if}}
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<svelte:head>
|
|
12
|
+
{{#if hasI18n}}
|
|
13
|
+
<title>{m.page_settings_title()}</title>
|
|
14
|
+
{{else}}
|
|
15
|
+
<title>设置</title>
|
|
16
|
+
{{/if}}
|
|
17
|
+
</svelte:head>
|
|
18
|
+
|
|
19
|
+
{{#if hasI18n}}
|
|
20
|
+
<h1 class="text-2xl font-bold mb-6">{m.page_settings_title()}</h1>
|
|
21
|
+
|
|
22
|
+
<div class="card bg-base-100 shadow">
|
|
23
|
+
<div class="card-body">
|
|
24
|
+
<h2 class="card-title">{m.page_settings_basic()}</h2>
|
|
25
|
+
<p>{m.page_settings_desc()}</p>
|
|
26
|
+
</div>
|
|
27
|
+
</div>
|
|
28
|
+
{{else}}
|
|
29
|
+
<h1 class="text-2xl font-bold mb-6">系统设置</h1>
|
|
30
|
+
|
|
31
|
+
<div class="card bg-base-100 shadow">
|
|
32
|
+
<div class="card-body">
|
|
33
|
+
<h2 class="card-title">基本配置</h2>
|
|
34
|
+
<p>在此管理系统设置。</p>
|
|
35
|
+
</div>
|
|
36
|
+
</div>
|
|
37
|
+
{{/if}}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 健康检查端点
|
|
3
|
+
*/
|
|
4
|
+
import type { RequestHandler } from './$types'
|
|
5
|
+
import { kit } from '@h-ai/kit'
|
|
6
|
+
|
|
7
|
+
export const GET: RequestHandler = async ({ locals }) => {
|
|
8
|
+
return kit.response.ok({
|
|
9
|
+
status: 'ok',
|
|
10
|
+
timestamp: new Date().toISOString(),
|
|
11
|
+
}, locals.requestId)
|
|
12
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"app_title": "Android App",
|
|
3
|
+
"app_description": "Android app built with hai Agent Framework + Capacitor",
|
|
4
|
+
"nav_home": "Home",
|
|
5
|
+
"nav_discover": "Discover",
|
|
6
|
+
"nav_profile": "Profile",
|
|
7
|
+
"page_home_title": "Home",
|
|
8
|
+
"page_home_desc": "Welcome to the Android App",
|
|
9
|
+
"page_discover_title": "Discover",
|
|
10
|
+
"page_discover_desc": "Explore more content.",
|
|
11
|
+
"page_profile_title": "Profile",
|
|
12
|
+
"page_profile_username": "Username",
|
|
13
|
+
"page_profile_login_hint": "Tap to login",
|
|
14
|
+
"auth_login_title": "Login",
|
|
15
|
+
"auth_login_submit": "Login",
|
|
16
|
+
"auth_login_loading": "Logging in...",
|
|
17
|
+
"auth_login_failed": "Login failed",
|
|
18
|
+
"auth_login_to_register": "No account? Register now",
|
|
19
|
+
"auth_register_title": "Register",
|
|
20
|
+
"auth_register_submit": "Register",
|
|
21
|
+
"auth_register_loading": "Registering...",
|
|
22
|
+
"auth_register_failed": "Registration failed",
|
|
23
|
+
"auth_register_to_login": "Already have an account? Login"
|
|
24
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"app_title": "Android 应用",
|
|
3
|
+
"app_description": "基于 hai Agent Framework + Capacitor 构建的 Android 应用",
|
|
4
|
+
"nav_home": "首页",
|
|
5
|
+
"nav_discover": "发现",
|
|
6
|
+
"nav_profile": "我的",
|
|
7
|
+
"page_home_title": "首页",
|
|
8
|
+
"page_home_desc": "欢迎使用 Android 应用",
|
|
9
|
+
"page_discover_title": "发现",
|
|
10
|
+
"page_discover_desc": "探索更多精彩内容。",
|
|
11
|
+
"page_profile_title": "我的",
|
|
12
|
+
"page_profile_username": "用户名",
|
|
13
|
+
"page_profile_login_hint": "点击登录",
|
|
14
|
+
"auth_login_title": "登录",
|
|
15
|
+
"auth_login_submit": "登录",
|
|
16
|
+
"auth_login_loading": "登录中...",
|
|
17
|
+
"auth_login_failed": "登录失败",
|
|
18
|
+
"auth_login_to_register": "没有账号?立即注册",
|
|
19
|
+
"auth_register_title": "注册",
|
|
20
|
+
"auth_register_submit": "注册",
|
|
21
|
+
"auth_register_loading": "注册中...",
|
|
22
|
+
"auth_register_failed": "注册失败",
|
|
23
|
+
"auth_register_to_login": "已有账号?去登录"
|
|
24
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* {{projectName}} — API 客户端初始化
|
|
3
|
+
*
|
|
4
|
+
* 使用 @h-ai/api-client 单例模式构建统一 HTTP 客户端,
|
|
5
|
+
* 搭配 @h-ai/capacitor 的原生 Token 存储。
|
|
6
|
+
*/
|
|
7
|
+
import { api } from '@h-ai/api-client'
|
|
8
|
+
import { createCapacitorTokenStorage } from '@h-ai/capacitor'
|
|
9
|
+
|
|
10
|
+
/** API 基础地址(开发时指向本地后端) */
|
|
11
|
+
const API_BASE = import.meta.env.PUBLIC_API_BASE ?? 'http://localhost:3000'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* 初始化 API 客户端
|
|
15
|
+
*
|
|
16
|
+
* 应在应用启动时调用一次。
|
|
17
|
+
* - Token 存储使用 Capacitor Preferences(原生安全存储)
|
|
18
|
+
* - 自动附加 Bearer Token、401 自动刷新重试
|
|
19
|
+
*/
|
|
20
|
+
export async function initApi() {
|
|
21
|
+
return api.init({
|
|
22
|
+
baseUrl: API_BASE,
|
|
23
|
+
auth: {
|
|
24
|
+
storage: createCapacitorTokenStorage(),
|
|
25
|
+
refreshUrl: '/api/v1/auth/refresh',
|
|
26
|
+
},
|
|
27
|
+
})
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export { api }
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capacitor 初始化
|
|
3
|
+
*
|
|
4
|
+
* 在应用启动时调用,配置状态栏等原生能力。
|
|
5
|
+
*/
|
|
6
|
+
import { capacitor } from '@h-ai/capacitor'
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* 初始化 Capacitor 原生能力
|
|
10
|
+
*/
|
|
11
|
+
export async function initCapacitor(): Promise<void> {
|
|
12
|
+
await capacitor.init()
|
|
13
|
+
|
|
14
|
+
if (capacitor.isNative()) {
|
|
15
|
+
await capacitor.statusBar.configure({
|
|
16
|
+
backgroundColor: '#ffffff',
|
|
17
|
+
style: 'LIGHT',
|
|
18
|
+
overlay: false,
|
|
19
|
+
})
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{{!-- Android App 根布局 --}}
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
/**
|
|
4
|
+
* Android App 根布局
|
|
5
|
+
*
|
|
6
|
+
* - 初始化 Capacitor 原生能力
|
|
7
|
+
* - 使用 SafeArea 包裹确保安全区域
|
|
8
|
+
*/
|
|
9
|
+
import type { Snippet } from 'svelte'
|
|
10
|
+
import { onMount } from 'svelte'
|
|
11
|
+
import '../app.css'
|
|
12
|
+
import { initCapacitor } from '$lib/capacitor'
|
|
13
|
+
{{#if hasI18n}}
|
|
14
|
+
import { browser } from '$app/environment'
|
|
15
|
+
import { setGlobalLocale } from '@h-ai/ui'
|
|
16
|
+
import { getLocale } from '$lib/paraglide/runtime.js'
|
|
17
|
+
import * as m from '$lib/paraglide/messages'
|
|
18
|
+
{{/if}}
|
|
19
|
+
|
|
20
|
+
interface Props {
|
|
21
|
+
children: Snippet
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let { children }: Props = $props()
|
|
25
|
+
|
|
26
|
+
onMount(() => {
|
|
27
|
+
initCapacitor()
|
|
28
|
+
})
|
|
29
|
+
{{#if hasI18n}}
|
|
30
|
+
|
|
31
|
+
if (typeof window !== 'undefined') {
|
|
32
|
+
const paraglideLocale = getLocale()
|
|
33
|
+
setGlobalLocale(paraglideLocale)
|
|
34
|
+
}
|
|
35
|
+
{{/if}}
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<div class="hai-safe-all min-h-screen flex flex-col bg-base-200">
|
|
39
|
+
<main class="flex-1">
|
|
40
|
+
{@render children()}
|
|
41
|
+
</main>
|
|
42
|
+
</div>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{{!-- Android App 首页 --}}
|
|
2
|
+
<script lang="ts">
|
|
3
|
+
/**
|
|
4
|
+
* Android App 首页
|
|
5
|
+
*/
|
|
6
|
+
{{#if hasI18n}}
|
|
7
|
+
import * as m from '$lib/paraglide/messages'
|
|
8
|
+
{{/if}}
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<svelte:head>
|
|
12
|
+
{{#if hasI18n}}
|
|
13
|
+
<title>{m.app_title()}</title>
|
|
14
|
+
{{else}}
|
|
15
|
+
<title>{{projectName}}</title>
|
|
16
|
+
{{/if}}
|
|
17
|
+
</svelte:head>
|
|
18
|
+
|
|
19
|
+
<section class="p-4">
|
|
20
|
+
{{#if hasI18n}}
|
|
21
|
+
<h1 class="text-2xl font-bold mb-4">{m.page_home_title()}</h1>
|
|
22
|
+
<p class="text-gray-600">{m.page_home_desc()}</p>
|
|
23
|
+
{{else}}
|
|
24
|
+
<h1 class="text-2xl font-bold mb-4">首页</h1>
|
|
25
|
+
<p class="text-gray-600">欢迎使用 Android 应用</p>
|
|
26
|
+
{{/if}}
|
|
27
|
+
</section>
|