@h-ai/cli 0.1.0-alpha.18 → 0.1.0-alpha.20

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.
Files changed (77) hide show
  1. package/dist/{chunk-BPO34NRL.js → chunk-3BBXDQ4Y.js} +5 -5
  2. package/dist/chunk-3BBXDQ4Y.js.map +1 -0
  3. package/dist/cli-config-templates-IGGO7P45.js +5 -0
  4. package/dist/{cli-config-templates-JCS7T3NU.js.map → cli-config-templates-IGGO7P45.js.map} +1 -1
  5. package/dist/index.js +67 -39
  6. package/dist/index.js.map +1 -1
  7. package/dist/{src-N4NPS7AG.js → src-QNEJJ3BV.js} +261 -103
  8. package/dist/src-QNEJJ3BV.js.map +1 -0
  9. package/package.json +2 -2
  10. package/templates/apps/admin/messages/en-US.json +5 -0
  11. package/templates/apps/admin/messages/zh-CN.json +5 -0
  12. package/templates/apps/admin/src/routes/+layout.svelte.hbs +5 -5
  13. package/templates/apps/admin/src/routes/+page.svelte.hbs +32 -12
  14. package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +37 -20
  15. package/templates/apps/admin/src/routes/admin/+page.svelte.hbs +33 -24
  16. package/templates/apps/admin/src/routes/admin/settings/+page.svelte.hbs +16 -13
  17. package/templates/apps/android-app/src/lib/api.ts.hbs +5 -4
  18. package/templates/apps/android-app/src/lib/capacitor.ts +1 -1
  19. package/templates/apps/android-app/src/routes/+layout.svelte.hbs +11 -10
  20. package/templates/apps/android-app/src/routes/+page.svelte.hbs +17 -6
  21. package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +4 -1
  22. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_core.yml.hbs +14 -0
  23. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_serv.yml.hbs +13 -0
  24. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/index.ts.hbs +3 -0
  25. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server-app.ts.hbs +23 -3
  26. package/templates/apps/h5/messages/en-US.json +3 -0
  27. package/templates/apps/h5/messages/zh-CN.json +3 -0
  28. package/templates/apps/h5/src/routes/+layout.svelte.hbs +30 -29
  29. package/templates/apps/h5/src/routes/+page.svelte.hbs +17 -6
  30. package/templates/apps/h5/src/routes/discover/+page.svelte.hbs +17 -6
  31. package/templates/apps/h5/src/routes/profile/+page.svelte.hbs +17 -6
  32. package/templates/apps/website/src/routes/+layout.svelte.hbs +35 -26
  33. package/templates/apps/website/src/routes/+page.svelte.hbs +28 -10
  34. package/templates/apps/website/src/routes/about/+page.svelte.hbs +11 -6
  35. package/templates/apps/website/src/routes/contact/+page.svelte.hbs +37 -34
  36. package/templates/apps/website/src/routes/services/+page.svelte.hbs +27 -40
  37. package/templates/base/package.json.hbs +30 -24
  38. package/templates/base/src/app.html.hbs +4 -0
  39. package/templates/base/src/hooks.server.ts.hbs +17 -7
  40. package/templates/base/src/lib/server/init.ts.hbs +20 -12
  41. package/templates/base/static/favicon.png +0 -0
  42. package/templates/base/tests/scaffold.test.ts.hbs +9 -1
  43. package/templates/base/vite.config.ts.hbs +3 -3
  44. package/templates/features/iam/routes-admin/(auth)/+layout.svelte.hbs +5 -5
  45. package/templates/features/iam/routes-admin/(auth)/auth/login/+page.svelte.hbs +34 -32
  46. package/templates/features/iam/routes-admin/(auth)/auth/register/+page.svelte.hbs +46 -48
  47. package/templates/features/iam/routes-h5/auth/login/+page.svelte.hbs +35 -31
  48. package/templates/features/iam/routes-h5/auth/register/+page.svelte.hbs +41 -38
  49. package/templates/features/payment/routes/api/v1/payment/create/+server.ts +15 -7
  50. package/templates/features/payment/routes/api/v1/payment/notify/[provider]/+server.ts +1 -2
  51. package/templates/skills/AGENTS.md +11 -1
  52. package/templates/skills/CLAUDE.md +2 -1
  53. package/templates/skills/copilot-instructions.md +22 -6
  54. package/templates/skills/hai-ai/SKILL.md +115 -646
  55. package/templates/skills/hai-ai/reference.md +197 -0
  56. package/templates/skills/hai-api-client/SKILL.md +7 -1
  57. package/templates/skills/hai-app-create/SKILL.md +1 -1
  58. package/templates/skills/hai-app-review/SKILL.md +1 -1
  59. package/templates/skills/hai-audit/SKILL.md +7 -2
  60. package/templates/skills/hai-cache/SKILL.md +2 -0
  61. package/templates/skills/hai-capacitor/SKILL.md +11 -9
  62. package/templates/skills/hai-core/SKILL.md +4 -1
  63. package/templates/skills/hai-crypto/SKILL.md +42 -8
  64. package/templates/skills/hai-deploy/SKILL.md +12 -9
  65. package/templates/skills/hai-iam/SKILL.md +2 -0
  66. package/templates/skills/hai-kit/SKILL.md +14 -5
  67. package/templates/skills/hai-payment/SKILL.md +5 -0
  68. package/templates/skills/hai-reach/SKILL.md +3 -1
  69. package/templates/skills/hai-reldb/SKILL.md +2 -0
  70. package/templates/skills/hai-scheduler/SKILL.md +2 -0
  71. package/templates/skills/hai-serv/SKILL.md +5 -0
  72. package/templates/skills/hai-storage/SKILL.md +10 -1
  73. package/templates/skills/hai-ui/SKILL.md +25 -11
  74. package/templates/skills/hai-vecdb/SKILL.md +8 -1
  75. package/dist/chunk-BPO34NRL.js.map +0 -1
  76. package/dist/cli-config-templates-JCS7T3NU.js +0 -5
  77. package/dist/src-N4NPS7AG.js.map +0 -1
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.18",
4
+ "version": "0.1.0-alpha.20",
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.18"
37
+ "@h-ai/core": "0.1.0-alpha.20"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@types/fs-extra": "^11.0.4",
@@ -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="ts">
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
- let { children }: Props = $props()
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="min-h-screen bg-base-200">
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="ts">
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="min-h-screen flex items-center justify-center">
20
- <div class="text-center">
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
- <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>
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
- <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>
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
- </div>
54
+ </Card>
35
55
  </main>
@@ -1,9 +1,11 @@
1
1
  {{!-- 后台管理布局(侧边栏 + 内容区) --}}
2
- <script lang="ts">
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
- let { children }: Props = $props()
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="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
- ☰
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="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">
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
- <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>
44
+ {m.app_title()}
35
45
  {{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>
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="ts">
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
- <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>
37
+ <PageHeader title={m.page_dashboard_title()} description={m.page_dashboard_subtitle()} />
32
38
  {{else}}
33
- <h1 class="text-2xl font-bold mb-6">仪表盘</h1>
39
+ <PageHeader title='仪表盘' description='系统运营数据总览' />
40
+ {{/if}}
34
41
 
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>
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="ts">
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
- <h1 class="text-2xl font-bold mb-6">{m.page_settings_title()}</h1>
21
+ <PageHeader title={m.page_settings_title()} description={m.page_settings_subtitle()} />
21
22
 
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>
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
- </div>
28
+ <p class='mt-2 text-sm text-base-content/60'>{m.page_settings_desc()}</p>
29
+ </Card>
28
30
  {{else}}
29
- <h1 class="text-2xl font-bold mb-6">系统设置</h1>
31
+ <PageHeader title='系统设置' description='管理系统配置项' />
30
32
 
31
- <div class="card bg-base-100 shadow">
32
- <div class="card-body">
33
- <h2 class="card-title">基本配置</h2>
34
- <p>在此管理系统设置。</p>
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
- </div>
38
+ <p class='mt-2 text-sm text-base-content/60'>在此管理系统设置。</p>
39
+ </Card>
37
40
  {{/if}}
@@ -4,7 +4,7 @@
4
4
  * 使用 @h-ai/api-client 单例模式构建统一 HTTP 客户端,
5
5
  * 搭配 @h-ai/capacitor 的原生 Token 存储。
6
6
  */
7
- import { api } from '@h-ai/api-client'
7
+ import { apiClient } from '@h-ai/api-client'
8
8
  import { createCapacitorTokenStorage } from '@h-ai/capacitor'
9
9
 
10
10
  // Capacitor 静态构建后通过 Vite 的 import.meta.env 注入 PUBLIC_* 变量
@@ -15,11 +15,12 @@ const API_BASE = (import.meta.env.PUBLIC_API_BASE as string | undefined) ?? 'htt
15
15
  * 初始化 API 客户端
16
16
  *
17
17
  * 应在应用启动时调用一次。
18
- * - Token 存储使用 Capacitor Preferences(原生安全存储)
18
+ * - Token 存储使用 Capacitor 原生安全存储插件(仅原生环境启用)
19
19
  * - 自动附加 Bearer Token、401 自动刷新重试
20
20
  */
21
21
  export async function initApi() {
22
- return api.init({
22
+ // 公共入口统一命名为 apiClient;不要使用历史 api 别名,避免生成项目类型不匹配。
23
+ return apiClient.init({
23
24
  baseUrl: `${API_BASE}/api/v1`,
24
25
  auth: {
25
26
  storage: createCapacitorTokenStorage(),
@@ -28,4 +29,4 @@ export async function initApi() {
28
29
  })
29
30
  }
30
31
 
31
- export { api }
32
+ export { apiClient }
@@ -14,7 +14,7 @@ export async function initCapacitor(): Promise<void> {
14
14
  if (capacitor.isNative()) {
15
15
  await capacitor.statusBar.configure({
16
16
  backgroundColor: '#ffffff',
17
- style: 'LIGHT',
17
+ style: 'light',
18
18
  overlay: false,
19
19
  })
20
20
  }
@@ -1,5 +1,5 @@
1
1
  {{!-- Android App 根布局 --}}
2
- <script lang="ts">
2
+ <script lang='ts'>
3
3
  /**
4
4
  * Android App 根布局
5
5
  *
@@ -7,36 +7,37 @@
7
7
  * - 使用 SafeArea 包裹确保安全区域
8
8
  */
9
9
  import type { Snippet } from 'svelte'
10
- import { onMount } from 'svelte'
11
- import '../app.css'
12
- import { initCapacitor } from '$lib/capacitor'
13
10
  {{#if hasI18n}}
14
11
  import { browser } from '$app/environment'
15
- import { setGlobalLocale } from '@h-ai/ui'
12
+ {{/if}}
13
+ import { initCapacitor } from '$lib/capacitor'
14
+ {{#if hasI18n}}
16
15
  import { getLocale } from '$lib/paraglide/runtime.js'
17
- import * as m from '$lib/paraglide/messages'
16
+ import { setGlobalLocale } from '@h-ai/ui'
18
17
  {{/if}}
18
+ import { onMount } from 'svelte'
19
+ import '../app.css'
19
20
 
20
21
  interface Props {
21
22
  children: Snippet
22
23
  }
23
24
 
24
- let { children }: Props = $props()
25
+ const { children }: Props = $props()
25
26
 
26
27
  onMount(() => {
27
28
  initCapacitor()
28
29
  })
29
30
  {{#if hasI18n}}
30
31
 
31
- if (typeof window !== 'undefined') {
32
+ if (browser) {
32
33
  const paraglideLocale = getLocale()
33
34
  setGlobalLocale(paraglideLocale)
34
35
  }
35
36
  {{/if}}
36
37
  </script>
37
38
 
38
- <div class="hai-safe-all min-h-screen flex flex-col bg-base-200">
39
- <main class="flex-1">
39
+ <div class='hai-safe-all min-h-screen flex flex-col bg-base-200'>
40
+ <main class='flex-1'>
40
41
  {@render children()}
41
42
  </main>
42
43
  </div>
@@ -1,11 +1,12 @@
1
1
  {{!-- Android App 首页 --}}
2
- <script lang="ts">
2
+ <script lang='ts'>
3
3
  /**
4
4
  * Android App 首页
5
5
  */
6
6
  {{#if hasI18n}}
7
7
  import * as m from '$lib/paraglide/messages'
8
8
  {{/if}}
9
+ import { Card } from '@h-ai/ui'
9
10
  </script>
10
11
 
11
12
  <svelte:head>
@@ -16,12 +17,22 @@
16
17
  {{/if}}
17
18
  </svelte:head>
18
19
 
19
- <section class="p-4">
20
+ <section class='p-4 space-y-4'>
20
21
  {{#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>
22
+ <h1 class='text-2xl font-black tracking-tight'>{m.page_home_title()}</h1>
23
+ <Card shadow='sm' class='bg-base-100'>
24
+ <div class='flex items-center gap-3'>
25
+ <span class='icon-[tabler--device-mobile] size-8 text-primary'></span>
26
+ <p class='text-base-content/70'>{m.page_home_desc()}</p>
27
+ </div>
28
+ </Card>
23
29
  {{else}}
24
- <h1 class="text-2xl font-bold mb-4">首页</h1>
25
- <p class="text-gray-600">欢迎使用 Android 应用</p>
30
+ <h1 class='text-2xl font-black tracking-tight'>首页</h1>
31
+ <Card shadow='sm' class='bg-base-100'>
32
+ <div class='flex items-center gap-3'>
33
+ <span class='icon-[tabler--device-mobile] size-8 text-primary'></span>
34
+ <p class='text-base-content/70'>欢迎使用 Android 应用</p>
35
+ </div>
36
+ </Card>
26
37
  {{/if}}
27
38
  </section>
@@ -4,7 +4,10 @@
4
4
 
5
5
  ## 骨架说明
6
6
 
7
- - `src/server-app.ts`:服务装配入口,挂载健康检查、OpenAPI、docs 与 procedures。
7
+ - `config/_core.yml`:应用元信息(名称 / 版本 / 环境 / 语言),启动时由 `core.config` 加载。
8
+ - `config/_serv.yml`:服务端运行时设置(CORS 来源等)。
9
+ - `src/index.ts`:进程入口,先 `core.init({ configDir: './config' })` 加载配置再启动监听。
10
+ - `src/server-app.ts`:服务装配入口,挂载健康检查、OpenAPI、docs 与 procedures;应用名称 / 版本与 CORS 来源均取自上述配置。
8
11
  - `src/server/procedures/app-procedures.ts`:app 领域 procedures,对应 contract 中的 `app.info` / `app.echo` 路由。
9
12
  - `tests/server-app.test.ts`:通过 `ServerApp.request()` 验证健康检查与业务路由。
10
13
 
@@ -0,0 +1,14 @@
1
+ # =============================================================================
2
+ # {{fullstack.servPackageName}} - 应用配置
3
+ # =============================================================================
4
+ #
5
+ # 后端服务的应用级配置,由 core.config 在启动时加载。
6
+ # 敏感信息请通过环境变量注入。
7
+ # =============================================================================
8
+
9
+ name: {{fullstack.servPackageName}}
10
+ version: 0.1.0
11
+ env: ${HAI_ENV:development}
12
+ debug: ${HAI_DEBUG:false}
13
+
14
+ defaultLocale: {{fullstack.i18n.baseLocale}}
@@ -0,0 +1,13 @@
1
+ # =============================================================================
2
+ # {{fullstack.servPackageName}} - Serv / HTTP 入口配置
3
+ # =============================================================================
4
+ #
5
+ # HTTP 路由路径(apiPrefix / health / openapi / docs)由共享 contract
6
+ # 统一定义,作为前后端唯一事实来源,因此不在此重复声明。
7
+ # 本文件仅声明服务端运行时设置。
8
+ # =============================================================================
9
+
10
+ # CORS 允许的来源。
11
+ # 开发环境放开为 *,生产环境应收敛为前端域名(如 https://app.example.com)。
12
+ cors:
13
+ origin: ${HAI_CORS_ORIGIN:*}
@@ -3,6 +3,9 @@ import { core } from '@h-ai/core'
3
3
  import { serv } from '@h-ai/serv'
4
4
  import { createServerApp } from './server-app.js'
5
5
 
6
+ // 加载 config/ 下的 _core.yml / _serv.yml 等配置文件(约定优于配置)
7
+ core.init({ configDir: './config', logging: { level: 'info' } })
8
+
6
9
  const app = createServerApp()
7
10
  const port = process.env.PORT ? Number(process.env.PORT) : 3000
8
11
  const host = process.env.HOST ?? '127.0.0.1'
@@ -1,9 +1,21 @@
1
+ import { core } from '@h-ai/core'
1
2
  import { serv } from '@h-ai/serv'
2
3
  import { APP_HTTP_ROUTES, ENABLED_FRONTENDS, {{fullstack.contractExportName}} } from '{{fullstack.contractPackageName}}'
3
4
  import { createServerProcedures } from './server/procedures/index.js'
4
5
 
5
6
  const STARTED_AT = new Date().toISOString()
6
7
 
8
+ /** `_core.yml` 中的应用元信息(由 core.config 加载,未初始化时回退到默认值)。 */
9
+ interface AppCoreConfig {
10
+ name?: string
11
+ version?: string
12
+ }
13
+
14
+ /** `_serv.yml` 中的服务端运行时设置。 */
15
+ interface AppServConfig {
16
+ cors?: { origin?: string }
17
+ }
18
+
7
19
  /** 应用侧最小 HTTP App 抽象;不把底层 Hono 类型暴露给项目代码。 */
8
20
  export interface ServerApp {
9
21
  readonly fetch: (request: Request) => Response | Promise<Response>
@@ -12,12 +24,20 @@ export interface ServerApp {
12
24
 
13
25
  /** 创建后端 HTTP App;与 @h-ai/serv 的 createApp 返回语义保持一致。 */
14
26
  export function createServerApp(): ServerApp {
27
+ // 配置来自 config/_core.yml 与 config/_serv.yml。
28
+ // 单元测试可不初始化 core,此时回退到内置默认值。
29
+ const coreConfig = core.config.get<AppCoreConfig>('core')
30
+ const servConfig = core.config.get<AppServConfig>('serv')
31
+ const appName = coreConfig?.name ?? '{{fullstack.servPackageName}}'
32
+ const appVersion = coreConfig?.version ?? '0.1.0'
33
+ const corsOrigin = servConfig?.cors?.origin ?? '*'
34
+
15
35
  return serv.createApp({
16
36
  contract: {{fullstack.contractExportName}},
17
37
  procedures: createServerProcedures({
18
38
  app: {
19
- name: '{{fullstack.servPackageName}}',
20
- version: '0.1.0',
39
+ name: appName,
40
+ version: appVersion,
21
41
  startedAt: STARTED_AT,
22
42
  frontends: [...ENABLED_FRONTENDS],
23
43
  },
@@ -34,7 +54,7 @@ export function createServerApp(): ServerApp {
34
54
  },
35
55
  middlewares: [{
36
56
  middleware: serv.cors({
37
- origin: '*',
57
+ origin: corsOrigin,
38
58
  allowedHeaders: ['Authorization', 'Content-Type', 'X-Requested-With'],
39
59
  }),
40
60
  }],
@@ -4,6 +4,8 @@
4
4
  "nav_home": "Home",
5
5
  "nav_discover": "Discover",
6
6
  "nav_profile": "Profile",
7
+ "page_home_title": "Home",
8
+ "page_home_desc": "Welcome to H5 App",
7
9
  "page_home_search": "Search...",
8
10
  "page_home_feature1": "Feature 1",
9
11
  "page_home_feature2": "Feature 2",
@@ -14,6 +16,7 @@
14
16
  "page_discover_title": "Discover",
15
17
  "page_discover_desc": "Explore more content.",
16
18
  "page_profile_title": "Profile",
19
+ "page_profile_desc": "Manage your personal information",
17
20
  "page_profile_username": "Username",
18
21
  "page_profile_login_hint": "Tap to login",
19
22
  "page_profile_info": "Personal Info",
@@ -4,6 +4,8 @@
4
4
  "nav_home": "首页",
5
5
  "nav_discover": "发现",
6
6
  "nav_profile": "我的",
7
+ "page_home_title": "首页",
8
+ "page_home_desc": "欢迎使用 H5 应用",
7
9
  "page_home_search": "搜索...",
8
10
  "page_home_feature1": "功能一",
9
11
  "page_home_feature2": "功能二",
@@ -14,6 +16,7 @@
14
16
  "page_discover_title": "发现",
15
17
  "page_discover_desc": "探索更多精彩内容。",
16
18
  "page_profile_title": "我的",
19
+ "page_profile_desc": "管理您的个人信息",
17
20
  "page_profile_username": "用户名",
18
21
  "page_profile_login_hint": "点击登录",
19
22
  "page_profile_info": "个人信息",