@h-ai/cli 0.1.0-alpha.56 → 0.1.0-alpha.58

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 (208) hide show
  1. package/README.en.md +239 -0
  2. package/README.ja.md +239 -0
  3. package/README.md +51 -1
  4. package/dist/chunk-2H7UOFLK.js +0 -0
  5. package/dist/chunk-F4IBPVZ5.js +355 -0
  6. package/dist/chunk-F4IBPVZ5.js.map +1 -0
  7. package/dist/{chunk-O3ANVICQ.js → chunk-WUSFJFW5.js} +13 -7
  8. package/dist/chunk-WUSFJFW5.js.map +1 -0
  9. package/dist/cli-config-templates-6XA7V6CC.js +5 -0
  10. package/dist/{cli-config-templates-OWBEGBZQ.js.map → cli-config-templates-6XA7V6CC.js.map} +1 -1
  11. package/dist/{cli-skill-templates-ZIWYMS4Y.js → cli-skill-templates-45CK4RQ2.js} +3 -3
  12. package/dist/{cli-skill-templates-ZIWYMS4Y.js.map → cli-skill-templates-45CK4RQ2.js.map} +1 -1
  13. package/dist/index.js +134 -125
  14. package/dist/index.js.map +1 -1
  15. package/dist/{src-TBIET7YU.js → src-DUGLX4YB.js} +7270 -2119
  16. package/dist/src-DUGLX4YB.js.map +1 -0
  17. package/package.json +17 -17
  18. package/templates/README.md +4 -4
  19. package/templates/apps/admin/src/routes/+layout.svelte.hbs +7 -0
  20. package/templates/apps/admin/src/routes/+page.svelte.hbs +5 -4
  21. package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +2 -2
  22. package/templates/apps/api/.gitignore.hbs +13 -0
  23. package/templates/apps/api/.npmrc.hbs +1 -0
  24. package/templates/apps/api/Dockerfile.hbs +6 -5
  25. package/templates/apps/api/apps/{{projectName}}-contract/package.json.hbs +1 -1
  26. package/templates/apps/api/apps/{{projectName}}-contract/src/app-schemas.ts.hbs +2 -0
  27. package/templates/apps/api/apps/{{projectName}}-contract/tsup.config.ts.hbs +1 -1
  28. package/templates/apps/api/apps/{{projectName}}-service/config/_core.yml.hbs +8 -0
  29. package/templates/apps/api/apps/{{projectName}}-service/package.json.hbs +1 -1
  30. package/templates/apps/api/apps/{{projectName}}-service/src/app.ts.hbs +7 -8
  31. package/templates/apps/api/apps/{{projectName}}-service/src/index.ts.hbs +4 -3
  32. package/templates/apps/api/apps/{{projectName}}-service/src/lib/server/init.ts.hbs +0 -1
  33. package/templates/apps/api/apps/{{projectName}}-service/src/server/procedures/app-procedures.ts.hbs +4 -0
  34. package/templates/apps/api/apps/{{projectName}}-service/tests/service.test.ts.hbs +3 -1
  35. package/templates/apps/api/e2e/api-service.spec.ts.hbs +4 -2
  36. package/templates/apps/api/{eslint.config.js → eslint.config.js.hbs} +6 -8
  37. package/templates/apps/api/package.json.hbs +3 -3
  38. package/templates/apps/api/pnpm-workspace.yaml.hbs +26 -0
  39. package/templates/apps/api/tsconfig.base.json +0 -1
  40. package/templates/apps/fullstack/.dockerignore.hbs +3 -0
  41. package/templates/apps/fullstack/.gitignore.hbs +16 -0
  42. package/templates/apps/fullstack/.npmrc.hbs +1 -0
  43. package/templates/apps/fullstack/Dockerfile.hbs +6 -5
  44. package/templates/apps/fullstack/apps/{{projectName}}-app/README.md.hbs +2 -2
  45. package/templates/apps/fullstack/apps/{{projectName}}-app/capacitor.config.ts.hbs +1 -1
  46. package/templates/apps/fullstack/apps/{{projectName}}-app/eslint.config.js.hbs +5 -8
  47. package/templates/apps/fullstack/apps/{{projectName}}-app/index.html.hbs +7 -2
  48. package/templates/apps/fullstack/apps/{{projectName}}-app/messages/en-US.json.hbs +1 -34
  49. package/templates/apps/fullstack/apps/{{projectName}}-app/messages/zh-CN.json.hbs +1 -34
  50. package/templates/apps/fullstack/apps/{{projectName}}-app/package.json.hbs +2 -2
  51. package/templates/apps/fullstack/apps/{{projectName}}-app/src/App.svelte.hbs +30 -170
  52. package/templates/apps/fullstack/apps/{{projectName}}-app/src/app.d.ts.hbs +1 -1
  53. package/templates/apps/fullstack/apps/{{projectName}}-app/src/lib/capacitor.ts.hbs +6 -5
  54. package/templates/apps/fullstack/apps/{{projectName}}-app/src/main.ts.hbs +1 -1
  55. package/templates/apps/fullstack/apps/{{projectName}}-app/vite.config.ts.hbs +48 -22
  56. package/templates/apps/fullstack/apps/{{projectName}}-desktop/README.md.hbs +3 -1
  57. package/templates/apps/fullstack/apps/{{projectName}}-desktop/eslint.config.js.hbs +5 -8
  58. package/templates/apps/fullstack/apps/{{projectName}}-desktop/index.html.hbs +6 -1
  59. package/templates/apps/fullstack/apps/{{projectName}}-desktop/messages/en-US.json.hbs +1 -28
  60. package/templates/apps/fullstack/apps/{{projectName}}-desktop/messages/zh-CN.json.hbs +1 -28
  61. package/templates/apps/fullstack/apps/{{projectName}}-desktop/package.json.hbs +5 -4
  62. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/App.svelte.hbs +10 -141
  63. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/Cargo.toml.hbs +5 -5
  64. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/tauri.conf.json.hbs +3 -3
  65. package/templates/apps/fullstack/apps/{{projectName}}-desktop/vite.config.ts.hbs +21 -2
  66. package/templates/apps/fullstack/apps/{{projectName}}-web/README.md.hbs +2 -2
  67. package/templates/apps/fullstack/apps/{{projectName}}-web/eslint.config.js.hbs +5 -8
  68. package/templates/apps/fullstack/apps/{{projectName}}-web/index.html.hbs +6 -1
  69. package/templates/apps/fullstack/apps/{{projectName}}-web/messages/en-US.json.hbs +1 -28
  70. package/templates/apps/fullstack/apps/{{projectName}}-web/messages/zh-CN.json.hbs +1 -28
  71. package/templates/apps/fullstack/apps/{{projectName}}-web/package.json.hbs +2 -2
  72. package/templates/apps/fullstack/apps/{{projectName}}-web/src/App.svelte.hbs +5 -143
  73. package/templates/apps/fullstack/apps/{{projectName}}-web/src/app.d.ts.hbs +1 -1
  74. package/templates/apps/fullstack/apps/{{projectName}}-web/src/main.ts.hbs +1 -1
  75. package/templates/apps/fullstack/apps/{{projectName}}-web/vite.config.ts.hbs +48 -22
  76. package/templates/apps/fullstack/e2e/fullstack.spec.ts.hbs +207 -17
  77. package/templates/apps/fullstack/{eslint.config.js → eslint.config.js.hbs} +6 -8
  78. package/templates/apps/fullstack/package.json.hbs +3 -3
  79. package/templates/apps/fullstack/packages/{{projectName}}-contract/README.md.hbs +2 -0
  80. package/templates/apps/fullstack/packages/{{projectName}}-contract/package.json.hbs +1 -1
  81. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/admin-contract.ts.hbs +66 -0
  82. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/admin-schemas.ts.hbs +96 -0
  83. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/app-schemas.ts.hbs +3 -0
  84. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/index.ts.hbs +3 -1
  85. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/{{projectName}}-contract.ts.hbs +5 -0
  86. package/templates/apps/fullstack/packages/{{projectName}}-contract/tests/contract.test.ts.hbs +3 -0
  87. package/templates/apps/fullstack/packages/{{projectName}}-contract/tsup.config.ts.hbs +1 -1
  88. package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +13 -3
  89. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_audit.yml.hbs +3 -0
  90. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_cache.yml.hbs +2 -0
  91. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_core.yml.hbs +10 -3
  92. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_db.yml.hbs +3 -0
  93. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_iam.yml.hbs +21 -0
  94. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_serv.yml.hbs +10 -3
  95. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_storage.yml.hbs +3 -0
  96. package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +10 -3
  97. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/app-server.ts.hbs +63 -28
  98. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/index.ts.hbs +26 -11
  99. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/admin-service.ts.hbs +276 -0
  100. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/messages.ts.hbs +29 -0
  101. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/admin-procedures.ts.hbs +94 -0
  102. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/app-procedures.ts.hbs +6 -0
  103. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/index.ts.hbs +5 -1
  104. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/runtime.ts.hbs +98 -0
  105. package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/app-server.test.ts.hbs +446 -33
  106. package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/runtime.test.ts.hbs +48 -0
  107. package/templates/apps/fullstack/packages/{{projectName}}-serv/tsup.config.ts.hbs +1 -1
  108. package/templates/apps/fullstack/packages/{{projectName}}-shared/README.md.hbs +19 -26
  109. package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/en-US.json.hbs +78 -15
  110. package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/zh-CN.json.hbs +78 -15
  111. package/templates/apps/fullstack/packages/{{projectName}}-shared/package.json.hbs +4 -1
  112. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/index.ts.hbs +3 -4
  113. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/api-client.ts.hbs +53 -27
  114. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AdminWorkspace.svelte.hbs +73 -0
  115. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AppShell.svelte.hbs +55 -45
  116. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AuditManagement.svelte.hbs +61 -0
  117. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/ProfileSettings.svelte.hbs +57 -0
  118. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/RoleManagement.svelte.hbs +49 -0
  119. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/UserManagement.svelte.hbs +174 -0
  120. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/management-store.svelte.ts.hbs +399 -0
  121. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/theme-store.svelte.ts.hbs +7 -39
  122. package/templates/apps/fullstack/packages/{{projectName}}-shared/svelte.config.js.hbs +1 -0
  123. package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/api-client.test.ts.hbs +151 -0
  124. package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/management-store.test.ts.hbs +101 -0
  125. package/templates/apps/fullstack/packages/{{projectName}}-shared/vitest.config.ts.hbs +7 -0
  126. package/templates/apps/fullstack/playwright.config.ts.hbs +6 -0
  127. package/templates/apps/fullstack/pnpm-workspace.yaml.hbs +24 -0
  128. package/templates/apps/fullstack/tsconfig.base.json +0 -1
  129. package/templates/apps/h5/src/routes/+layout.svelte.hbs +4 -0
  130. package/templates/apps/h5/src/routes/+page.svelte.hbs +3 -2
  131. package/templates/apps/mobile-app/index.html.hbs +2 -2
  132. package/templates/apps/mobile-app/src/App.svelte.hbs +6 -2
  133. package/templates/apps/mobile-app/src/lib/app-config.ts.hbs +13 -0
  134. package/templates/apps/website/src/routes/+layout.svelte.hbs +8 -2
  135. package/templates/apps/website/src/routes/+page.svelte.hbs +4 -3
  136. package/templates/base/.npmrc.hbs +1 -0
  137. package/templates/base/Dockerfile.hbs +9 -8
  138. package/templates/base/e2e/app.spec.ts.hbs +1 -0
  139. package/templates/base/eslint-rules.js +45 -0
  140. package/templates/base/eslint.config.js.hbs +6 -8
  141. package/templates/base/package.json.hbs +39 -42
  142. package/templates/base/pnpm-workspace.yaml.hbs +26 -0
  143. package/templates/base/src/app.d.ts.hbs +4 -0
  144. package/templates/base/src/hooks.server.ts.hbs +0 -8
  145. package/templates/base/src/lib/server/init.ts.hbs +26 -5
  146. package/templates/base/src/routes/+layout.server.ts.hbs +18 -0
  147. package/templates/base/tests/scaffold.test.ts.hbs +21 -1
  148. package/templates/base/vite.config.ts.hbs +21 -0
  149. package/templates/features/ai/routes/api/chat/+server.ts +6 -7
  150. package/templates/features/iam/routes-admin/(auth)/auth/login/+page.svelte.hbs +1 -1
  151. package/templates/features/iam/routes-h5/auth/login/+page.svelte.hbs +1 -1
  152. package/templates/features/iam/routes-shared/api/auth/login/+server.ts +14 -10
  153. package/templates/features/iam/routes-shared/api/auth/logout/+server.ts +6 -4
  154. package/templates/features/storage/routes/api/upload/+server.ts +10 -8
  155. package/templates/skills/AGENTS.md +9 -8
  156. package/templates/skills/CLAUDE.md +0 -10
  157. package/templates/skills/bridges/admin/AGENTS.md +8 -0
  158. package/templates/skills/bridges/admin/copilot-instructions.md +2 -0
  159. package/templates/skills/bridges/api/AGENTS.md +8 -1
  160. package/templates/skills/bridges/api/copilot-instructions.md +2 -0
  161. package/templates/skills/bridges/fullstack/AGENTS.md.hbs +21 -4
  162. package/templates/skills/bridges/fullstack/copilot-instructions.md.hbs +5 -0
  163. package/templates/skills/bridges/h5/AGENTS.md +8 -0
  164. package/templates/skills/bridges/h5/copilot-instructions.md +2 -0
  165. package/templates/skills/bridges/mobile-app/AGENTS.md +8 -0
  166. package/templates/skills/bridges/mobile-app/copilot-instructions.md +2 -0
  167. package/templates/skills/bridges/website/AGENTS.md +8 -0
  168. package/templates/skills/bridges/website/copilot-instructions.md +2 -0
  169. package/templates/skills/copilot-instructions.md +2 -0
  170. package/templates/skills/hai-api-client/SKILL.md +2 -0
  171. package/templates/skills/hai-app-create/SKILL.md +9 -7
  172. package/templates/skills/hai-app-create/development.md +72 -0
  173. package/templates/skills/hai-app-create/reference.md +44 -32
  174. package/templates/skills/hai-app-review/SKILL.md +50 -144
  175. package/templates/skills/hai-app-tests/SKILL.md +3 -1
  176. package/templates/skills/hai-app-tests/reference.md +47 -27
  177. package/templates/skills/hai-build/SKILL.md +5 -4
  178. package/templates/skills/hai-build/reference.md +56 -34
  179. package/templates/skills/hai-ci/SKILL.md +8 -15
  180. package/templates/skills/hai-core/SKILL.md +2 -0
  181. package/templates/skills/hai-core/reference.md +6 -4
  182. package/templates/skills/hai-framework-sync/SKILL.md +8 -2
  183. package/templates/skills/hai-pr-review/SKILL.md +5 -4
  184. package/templates/skills/hai-reldb/SKILL.md +1 -0
  185. package/templates/skills/hai-reldb/reference.md +3 -0
  186. package/templates/skills/hai-scheduler/SKILL.md +3 -0
  187. package/templates/skills/hai-serv/SKILL.md +2 -0
  188. package/templates/skills/hai-serv/reference.md +18 -2
  189. package/templates/skills/hai-storage/SKILL.md +3 -1
  190. package/templates/skills/hai-ui/SKILL.md +6 -0
  191. package/templates/skills/hai-ui/reference.md +7 -4
  192. package/templates/skills/hai-vecdb/reference.md +53 -49
  193. package/dist/chunk-O3ANVICQ.js.map +0 -1
  194. package/dist/chunk-WUYLYCW2.js +0 -237
  195. package/dist/chunk-WUYLYCW2.js.map +0 -1
  196. package/dist/cli-config-templates-OWBEGBZQ.js +0 -5
  197. package/dist/src-TBIET7YU.js.map +0 -1
  198. package/templates/apps/fullstack/apps/{{projectName}}-app/tests/api.test.ts.hbs +0 -28
  199. package/templates/apps/fullstack/apps/{{projectName}}-desktop/tests/api.test.ts.hbs +0 -28
  200. package/templates/apps/fullstack/apps/{{projectName}}-web/tests/api.test.ts.hbs +0 -55
  201. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/LanguageSwitcher.svelte.hbs +0 -27
  202. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/ThemeSwitcher.svelte.hbs +0 -18
  203. package/templates/skills/bridges/admin/CLAUDE.md +0 -11
  204. package/templates/skills/bridges/api/CLAUDE.md +0 -11
  205. package/templates/skills/bridges/fullstack/CLAUDE.md.hbs +0 -5
  206. package/templates/skills/bridges/h5/CLAUDE.md +0 -11
  207. package/templates/skills/bridges/mobile-app/CLAUDE.md +0 -11
  208. package/templates/skills/bridges/website/CLAUDE.md +0 -11
@@ -1,152 +1,21 @@
1
1
  {{! @skipIfEmpty }}
2
2
  {{#if fullstack.frontends.desktop}}
3
3
  <script lang="ts">
4
- import type { AppInfo } from '{{fullstack.sharedPackageName}}'
5
- import * as appM from './lib/paraglide/messages.js'
4
+ import type { ManagementApiOptions } from '{{fullstack.sharedPackageName}}'
5
+ import { apiClient } from '@h-ai/api-client'
6
+ import { AdminWorkspace } from '{{fullstack.sharedPackageName}}'
6
7
  import { setLocale } from './lib/paraglide/runtime.js'
7
- import { Alert, Button, Card, Skeleton } from '@h-ai/ui'
8
- import { onMount } from 'svelte'
9
- import { AppShell, fetchAppInfo, messages as sharedM } from '{{fullstack.sharedPackageName}}'
10
8
 
11
- let info = $state<AppInfo | null>(null)
12
- let loading = $state(true)
13
- let errorMessage = $state('')
14
-
15
- function syncLocale(locale: string) {
16
- setLocale(locale as Parameters<typeof setLocale>[0])
9
+ const native = '__TAURI_INTERNALS__' in globalThis
10
+ const apiOptions: ManagementApiOptions = {
11
+ clientName: '{{projectName}}-desktop',
12
+ ...(native ? { requireApiBase: true, tokenStorage: apiClient.tokenStorage.memory(), headers: { 'X-HAI-Token-Transport': 'body' } } : {}),
17
13
  }
18
14
 
19
- async function refreshStatus() {
20
- loading = true
21
- errorMessage = ''
22
- try {
23
- info = await fetchAppInfo({ clientName: '{{projectName}}-desktop' })
24
- }
25
- catch {
26
- info = null
27
- errorMessage = sharedM.home_error()
28
- }
29
- finally {
30
- loading = false
31
- }
15
+ function syncLocale(locale: string) {
16
+ setLocale(locale as Parameters<typeof setLocale>[0], { reload: false })
32
17
  }
33
-
34
- onMount(() => {
35
- document.title = appM.page_title({ name: sharedM.app_name() })
36
- void refreshStatus()
37
- })
38
18
  </script>
39
19
 
40
- <AppShell platform="desktop" onLocaleChange={syncLocale}>
41
- <section class="space-y-8">
42
- <div class="grid gap-6 lg:grid-cols-[1.2fr_0.8fr]">
43
- <section class="relative overflow-hidden rounded-[1.5rem] border border-base-300/70 bg-base-100 p-6 shadow-xl lg:p-10">
44
- <div class="max-w-2xl space-y-6">
45
- <span class="badge badge-primary badge-lg gap-2">
46
- <span class="icon-[tabler--device-desktop] size-4"></span>
47
- {appM.hero_badge()}
48
- </span>
49
- <div class="space-y-4">
50
- <h1 class="text-4xl font-black tracking-tight text-base-content sm:text-5xl">
51
- {appM.hero_title({ name: sharedM.app_name() })}
52
- </h1>
53
- <p class="max-w-xl text-lg leading-8 text-base-content/70">
54
- {appM.hero_subtitle()}
55
- </p>
56
- </div>
57
- <div class="flex flex-wrap gap-3">
58
- <a class="btn btn-primary" href="#status">
59
- <span class="icon-[tabler--activity-heartbeat] size-5"></span>
60
- {appM.hero_primary_action()}
61
- </a>
62
- <a class="btn btn-ghost" href="#customize">
63
- <span class="icon-[tabler--adjustments] size-5"></span>
64
- {appM.hero_secondary_action()}
65
- </a>
66
- </div>
67
- </div>
68
- </section>
69
-
70
- <aside class="rounded-[1.5rem] border border-base-300/70 bg-base-100 p-5 shadow-lg">
71
- <div class="mockup-window border border-base-300 bg-base-200/70">
72
- <div class="space-y-4 bg-base-100 p-5">
73
- <div class="flex items-center justify-between">
74
- <div>
75
- <p class="text-sm font-semibold">{appM.preview_title()}</p>
76
- <p class="text-xs text-base-content/55">{appM.preview_body()}</p>
77
- </div>
78
- <span class="badge badge-success badge-outline">{appM.platform_name()}</span>
79
- </div>
80
- <div class="grid gap-3 text-sm">
81
- <div class="rounded-2xl bg-primary/10 p-4">
82
- <span class="icon-[tabler--components] mb-2 size-6 text-primary"></span>
83
- <p class="font-semibold">{appM.preview_metric_shared()}</p>
84
- </div>
85
- <div class="grid grid-cols-2 gap-3">
86
- <div class="rounded-2xl bg-secondary/10 p-4">
87
- <span class="icon-[tabler--language] mb-2 size-6 text-secondary"></span>
88
- <p class="font-semibold">{appM.preview_metric_local()}</p>
89
- </div>
90
- <div class="rounded-2xl bg-accent/10 p-4">
91
- <span class="icon-[tabler--palette] mb-2 size-6 text-accent"></span>
92
- <p class="font-semibold">{appM.preview_metric_theme()}</p>
93
- </div>
94
- </div>
95
- </div>
96
- </div>
97
- </div>
98
- </aside>
99
- </div>
100
-
101
- <div class="grid gap-6 lg:grid-cols-[0.95fr_1.05fr]">
102
- <div id="status">
103
- <Card title={appM.status_title()} bordered shadow="md" class="bg-base-100">
104
- <p class="mb-5 text-sm text-base-content/65">{appM.status_description()}</p>
105
- {#if loading}
106
- <Skeleton variant="title" class="mb-3" />
107
- <Skeleton count={3} />
108
- <p class="sr-only" data-testid="service-status">{sharedM.home_loading()}</p>
109
- {:else if info}
110
- <Alert variant="success" title={appM.status_online({ name: info.name })}>
111
- <p data-testid="service-status">{info.name}</p>
112
- </Alert>
113
- <dl class="mt-5 grid gap-3 text-sm sm:grid-cols-2">
114
- <div class="rounded-box border border-base-300/70 bg-base-200/60 p-4">
115
- <dt class="text-xs text-base-content/55">{appM.status_version()}</dt>
116
- <dd class="mt-1 font-semibold">{info.version}</dd>
117
- </div>
118
- <div class="rounded-box border border-base-300/70 bg-base-200/60 p-4">
119
- <dt class="text-xs text-base-content/55">{appM.status_started({ time: info.startedAt })}</dt>
120
- <dd class="mt-1 font-semibold">{appM.status_frontends_count({ count: String(info.frontends.length) })}</dd>
121
- </div>
122
- </dl>
123
- {:else}
124
- <Alert variant="error" title={sharedM.home_error()}>
125
- <p data-testid="service-status">{errorMessage}</p>
126
- </Alert>
127
- {/if}
128
-
129
- <div class="mt-5">
130
- <Button type="button" variant="primary" loading={loading} onclick={refreshStatus}>
131
- {sharedM.home_refresh()}
132
- </Button>
133
- </div>
134
- </Card>
135
- </div>
136
-
137
- <section id="customize" class="grid gap-4 sm:grid-cols-2">
138
- <div class="rounded-[1.5rem] border border-base-300/70 bg-base-100 p-5 shadow-md">
139
- <span class="icon-[tabler--package] mb-4 size-7 text-primary"></span>
140
- <h2 class="text-lg font-bold">{appM.custom_shared_title()}</h2>
141
- <p class="mt-2 text-sm leading-6 text-base-content/65">{appM.custom_shared_body()}</p>
142
- </div>
143
- <div class="rounded-[1.5rem] border border-base-300/70 bg-base-100 p-5 shadow-md">
144
- <span class="icon-[tabler--message-language] mb-4 size-7 text-secondary"></span>
145
- <h2 class="text-lg font-bold">{appM.custom_local_title()}</h2>
146
- <p class="mt-2 text-sm leading-6 text-base-content/65">{appM.custom_local_body()}</p>
147
- </div>
148
- </section>
149
- </div>
150
- </section>
151
- </AppShell>
20
+ <AdminWorkspace platform="desktop" {apiOptions} onLocaleChange={syncLocale} />
152
21
  {{/if}}
@@ -19,11 +19,11 @@ panic = "abort"
19
19
  strip = true
20
20
 
21
21
  [build-dependencies]
22
- tauri-build = { version = "2", features = [] }
22
+ tauri-build = { version = "2.7.2", features = [] }
23
23
 
24
24
  [dependencies]
25
- tauri = { version = "2", features = [] }
26
- tauri-plugin-shell = "2"
27
- serde = { version = "1", features = ["derive"] }
28
- serde_json = "1"
25
+ tauri = { version = "2.12.3", features = [] }
26
+ tauri-plugin-shell = "2.5.0"
27
+ serde = { version = "1.0.229", features = ["derive"] }
28
+ serde_json = "1.0.152"
29
29
  {{/if}}
@@ -2,7 +2,7 @@
2
2
  {{#if fullstack.frontends.desktop}}
3
3
  {
4
4
  "$schema": "https://schema.tauri.app/config/2",
5
- "productName": "{{projectName}} Desktop",
5
+ "productName": {{json fullstack.appName}},
6
6
  "version": "0.1.0",
7
7
  "identifier": "com.hai.{{fullstack.nativeAppIdSegment}}.desktop",
8
8
  "build": {
@@ -14,7 +14,7 @@
14
14
  "app": {
15
15
  "windows": [
16
16
  {
17
- "title": "{{projectName}} Desktop",
17
+ "title": {{json fullstack.appName}},
18
18
  "width": 1280,
19
19
  "height": 800,
20
20
  "resizable": true,
@@ -28,7 +28,7 @@
28
28
  "Cross-Origin-Embedder-Policy": "require-corp",
29
29
  "Cross-Origin-Resource-Policy": "same-origin"
30
30
  },
31
- "csp": "default-src 'self'; img-src 'self' data: https:; style-src 'self' 'unsafe-inline'; script-src 'self' 'wasm-unsafe-eval'; worker-src 'self' blob:; connect-src 'self' http://localhost:3000 http://127.0.0.1:3000 ws://localhost:* ws://127.0.0.1:*; font-src 'self' data:"
31
+ "csp": "default-src 'self'; img-src 'self' data: https: http://localhost:3000 http://127.0.0.1:3000; style-src 'self' 'unsafe-inline'; script-src 'self' 'wasm-unsafe-eval'; worker-src 'self' blob:; connect-src 'self' http://localhost:3000 http://127.0.0.1:3000 ws://localhost:* ws://127.0.0.1:*; font-src 'self' data:"
32
32
  }
33
33
  },
34
34
  "bundle": {
@@ -1,6 +1,7 @@
1
1
  {{! @skipIfEmpty }}
2
2
  {{#if fullstack.frontends.desktop}}
3
3
  import process from 'node:process'
4
+ import { fileURLToPath } from 'node:url'
4
5
  import { haiOptimizeExclude, haiPrebundledDeps } from '@h-ai/ui/vite'
5
6
  import { paraglideVitePlugin } from '@inlang/paraglide-js'
6
7
  import { svelte } from '@sveltejs/vite-plugin-svelte'
@@ -9,12 +10,29 @@ import { loadEnv } from 'vite'
9
10
  import { defineConfig } from 'vitest/config'
10
11
 
11
12
  const host = process.env.TAURI_DEV_HOST
13
+ const envDir = fileURLToPath(new URL('../../', import.meta.url))
12
14
 
13
15
  export default defineConfig(({ mode }) => {
14
- const env = loadEnv(mode, process.cwd(), '')
15
- Object.assign(process.env, env)
16
+ const env = loadEnv(mode, envDir, 'PUBLIC_')
17
+ const target = (env.PUBLIC_API_BASE || process.env.SERVICE_BASE_URL || 'http://127.0.0.1:3000').replace(/\/api\/v1\/?$/, '')
18
+ const proxy = { '/api': { target, changeOrigin: true } }
16
19
 
17
20
  return {
21
+ envDir,
22
+ preview: { proxy },
23
+ build: {
24
+ rolldownOptions: {
25
+ output: {
26
+ codeSplitting: {
27
+ groups: [
28
+ { name: 'vendor-ui', test: /node_modules\/(?:@h-ai\/ui|bits-ui|svelte)\// },
29
+ { name: 'vendor-crypto', test: /node_modules\/(?:@h-ai\/(?:core|crypto)|sm-crypto(?:-v2)?)\// },
30
+ { name: 'vendor-api', test: /node_modules\/(?:@orpc\/|zod\/)/ },
31
+ ],
32
+ },
33
+ },
34
+ },
35
+ },
18
36
  plugins: [
19
37
  svelte(),
20
38
  tailwindcss(),
@@ -26,6 +44,7 @@ export default defineConfig(({ mode }) => {
26
44
  ],
27
45
  clearScreen: false,
28
46
  server: {
47
+ proxy,
29
48
  port: {{fullstack.ports.desktop}},
30
49
  strictPort: true,
31
50
  host: host || false,
@@ -2,13 +2,13 @@
2
2
  {{#if fullstack.frontends.web}}
3
3
  # {{projectName}}-web
4
4
 
5
- Web 前端工程,通过 `packages/{{fullstack.sharedPackageName}}` 调用后端 API,并通过 `@h-ai/ui` 组件搭建页面。
5
+ 响应式 mini 后台 Web 前端,通过 `packages/{{fullstack.sharedPackageName}}` 调用后端 API,并通过 `@h-ai/ui` 组件搭建页面。
6
6
 
7
7
  ## i18n 与 shared 协同
8
8
 
9
9
  - 本端页面文案:`messages/{locale}.json` + `project.inlang/settings.json`
10
10
  - 共享 Shell/主题/语言/API:`packages/{{fullstack.sharedPackageName}}`
11
- - 语言切换由 shared 的 `LanguageSwitcher` 触发,并同步本端 `$lib/paraglide/runtime.js`
11
+ - 个人设置保存语言与风格偏好到 IAM 元数据,并同步 shared 和本端 Paraglide runtime
12
12
 
13
13
  自定义建议:Web 独有文案放在本目录 `messages/`;跨端通用文案或组件放到 shared。
14
14
 
@@ -1,18 +1,15 @@
1
1
  {{! @skipIfEmpty }}
2
2
  {{#if fullstack.frontends.web}}
3
- import antfu from '@antfu/eslint-config'
3
+ import antfu, { GLOB_SRC } from '@antfu/eslint-config'
4
+ import { haiQualityConfig } from '../../eslint-rules.js'
4
5
 
5
6
  export default antfu({
7
+ // unused-imports 使用 TS 规则,JS 同样使用 TS parser 以保持 scope 契约一致。
8
+ typescript: { files: [GLOB_SRC] },
6
9
  formatters: true,
7
10
  ignores: ['**/build/**', '**/dist/**', '**/*.d.ts', '**/project.inlang/**', '**/src/lib/paraglide/**'],
8
11
  svelte: true,
9
- }, {
10
- files: ['**/*.ts', '**/*.svelte'],
11
- rules: {
12
- 'no-console': 'error',
13
- 'ts/no-explicit-any': 'error',
14
- },
15
- }, {
12
+ }, haiQualityConfig, {
16
13
  files: ['**/*.svelte'],
17
14
  rules: {
18
15
  'svelte/html-quotes': 'off',
@@ -5,7 +5,12 @@
5
5
  <head>
6
6
  <meta charset="UTF-8" />
7
7
  <meta name="viewport" content="width=device-width, initial-scale=1" />
8
- <title>{{projectName}} Web</title>
8
+ <title>{{html fullstack.appName}}</title>
9
+ <link
10
+ rel="icon"
11
+ type="image/svg+xml"
12
+ href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='8' fill='%234438df'/%3E%3Cpath d='M10 8v16M22 8v16M10 16h12' fill='none' stroke='white' stroke-width='3'/%3E%3C/svg%3E"
13
+ />
9
14
  <script src="/runtime-config.js"></script>
10
15
  </head>
11
16
  <body>
@@ -2,33 +2,6 @@
2
2
  {{#if fullstack.frontends.web}}
3
3
  {
4
4
  "$schema": "https://inlang.com/schema/inlang-message-format",
5
- "page_title": "{name} · Web",
6
- "platform_name": "Web",
7
- "hero_badge": "Web workspace",
8
- "hero_title": "{name} Web Console",
9
- "hero_subtitle": "A browser-first product landing page. Page copy comes from this app's messages, while shared provides the shell, theme, locale switcher and API client.",
10
- "hero_primary_action": "View service status",
11
- "hero_secondary_action": "Customize the starter",
12
- "preview_title": "Responsive web experience",
13
- "preview_body": "Ready for websites, consoles and admin entry points",
14
- "preview_metric_shared": "Shared components and API client",
15
- "preview_metric_local": "Web-owned messages",
16
- "preview_metric_theme": "Configurable themes",
17
- "status_title": "Service connectivity",
18
- "status_description": "This page calls the backend service to verify contract, service, shared and the Web frontend are wired together.",
19
- "status_online": "{name} is connected",
20
- "status_version": "Service version",
21
- "status_started": "Started at: {time}",
22
- "status_frontends": "Service frontends: {list}",
23
- "status_frontends_count": "{count} frontend targets",
24
- "custom_shared_title": "Shared owns common capabilities",
25
- "custom_shared_body": "Put cross-platform shell, theme, locale switching, API client and shared UI in packages/{{projectName}}-shared.",
26
- "custom_local_title": "Web owns product copy",
27
- "custom_local_body": "Write Web-only page copy in apps/{{projectName}}-web/messages and compile it with this app's project.inlang.",
28
- "flow_title": "Collaboration boundary",
29
- "flow_contract": "Contract defines API truth",
30
- "flow_service": "Service implements business endpoints",
31
- "flow_shared": "Shared provides cross-platform UI/API",
32
- "flow_frontend": "Web composes pages and local copy"
5
+ "page_title": "{name}"
33
6
  }
34
7
  {{/if}}
@@ -2,33 +2,6 @@
2
2
  {{#if fullstack.frontends.web}}
3
3
  {
4
4
  "$schema": "https://inlang.com/schema/inlang-message-format",
5
- "page_title": "{name} · Web",
6
- "platform_name": "Web",
7
- "hero_badge": "Web 工作台",
8
- "hero_title": "{name} Web 控制台",
9
- "hero_subtitle": "面向浏览器的产品首页,使用本端 messages 管理页面文案,并复用 shared 的 Shell、主题、语言与 API 客户端。",
10
- "hero_primary_action": "查看服务状态",
11
- "hero_secondary_action": "了解如何自定义",
12
- "preview_title": "响应式 Web 体验",
13
- "preview_body": "适合官网、控制台与运营后台入口",
14
- "preview_metric_shared": "共享组件与 API 客户端",
15
- "preview_metric_local": "Web 自有 messages",
16
- "preview_metric_theme": "主题可配置",
17
- "status_title": "服务联通状态",
18
- "status_description": "页面会调用后端服务,确认 contract、service、shared 与 Web 前端已经连通。",
19
- "status_online": "{name} 已连接",
20
- "status_version": "服务版本",
21
- "status_started": "启动时间:{time}",
22
- "status_frontends": "服务声明的前端:{list}",
23
- "status_frontends_count": "{count} 个前端目标",
24
- "custom_shared_title": "共享层放通用能力",
25
- "custom_shared_body": "把跨端一致的 Shell、主题、语言切换、API client 与通用组件放在 packages/{{projectName}}-shared。",
26
- "custom_local_title": "Web 层放产品文案",
27
- "custom_local_body": "Web 独有页面文案写在 apps/{{projectName}}-web/messages,再由本端 project.inlang 编译。",
28
- "flow_title": "协同边界",
29
- "flow_contract": "Contract 定义接口真相源",
30
- "flow_service": "Service 实现业务接口",
31
- "flow_shared": "Shared 提供跨端 UI/API 能力",
32
- "flow_frontend": "Web 组合页面与本端文案"
5
+ "page_title": "{name}"
33
6
  }
34
7
  {{/if}}
@@ -5,7 +5,7 @@
5
5
  "type": "module",
6
6
  "version": "0.1.0",
7
7
  "private": true,
8
- "engines": { "node": ">=22.12.0" },
8
+ "engines": { "node": "^22.22.2 || ^24.15.0 || >=26.0.0" },
9
9
  "scripts": {
10
10
  "paraglide:compile": "paraglide-js compile --project ./project.inlang --outdir ./src/lib/paraglide",
11
11
  "paraglide:watch": "paraglide-js compile --project ./project.inlang --outdir ./src/lib/paraglide --watch",
@@ -16,7 +16,7 @@
16
16
  "preview": "vite preview --host 127.0.0.1 --port {{fullstack.ports.web}} --strictPort",
17
17
  "typecheck": "pnpm paraglide:compile && svelte-check --tsconfig ./tsconfig.json",
18
18
  "lint": "eslint .",
19
- "test": "vitest run",
19
+ "test": "vitest run --passWithNoTests",
20
20
  "test:watch": "vitest",
21
21
  "clean": "rimraf dist build .turbo src/lib/paraglide"
22
22
  },
@@ -1,153 +1,15 @@
1
1
  {{! @skipIfEmpty }}
2
2
  {{#if fullstack.frontends.web}}
3
3
  <script lang="ts">
4
- import type { AppInfo } from '{{fullstack.sharedPackageName}}'
5
- import * as appM from './lib/paraglide/messages.js'
4
+ import { AdminWorkspace } from '{{fullstack.sharedPackageName}}'
6
5
  import { setLocale } from './lib/paraglide/runtime.js'
7
- import { Alert, Button, Card, Skeleton } from '@h-ai/ui'
8
- import { onMount } from 'svelte'
9
- import { AppShell, fetchAppInfo, messages as sharedM } from '{{fullstack.sharedPackageName}}'
10
6
 
11
- let info = $state<AppInfo | null>(null)
12
- let loading = $state(true)
13
- let errorMessage = $state('')
7
+ const apiOptions = { clientName: '{{projectName}}-web' }
14
8
 
15
9
  function syncLocale(locale: string) {
16
- setLocale(locale as Parameters<typeof setLocale>[0])
10
+ setLocale(locale as Parameters<typeof setLocale>[0], { reload: false })
17
11
  }
18
-
19
- async function refreshStatus() {
20
- loading = true
21
- errorMessage = ''
22
- try {
23
- info = await fetchAppInfo({ clientName: '{{projectName}}-web' })
24
- }
25
- catch {
26
- info = null
27
- errorMessage = sharedM.home_error()
28
- }
29
- finally {
30
- loading = false
31
- }
32
- }
33
-
34
- onMount(() => {
35
- document.title = appM.page_title({ name: sharedM.app_name() })
36
- void refreshStatus()
37
- })
38
12
  </script>
39
13
 
40
- <AppShell platform="web" onLocaleChange={syncLocale}>
41
- <section class="space-y-8">
42
- <div class="grid gap-6 lg:grid-cols-[1.2fr_0.8fr]">
43
- <section class="relative overflow-hidden rounded-[2rem] border border-base-300/70 bg-gradient-to-br from-primary/15 via-base-100 to-secondary/15 p-6 shadow-2xl shadow-primary/10 lg:p-10">
44
- <div class="absolute right-8 top-8 hidden size-28 rounded-full bg-primary/20 blur-3xl sm:block"></div>
45
- <div class="relative z-10 max-w-2xl space-y-6">
46
- <span class="badge badge-primary badge-lg gap-2">
47
- <span class="icon-[tabler--rocket] size-4"></span>
48
- {appM.hero_badge()}
49
- </span>
50
- <div class="space-y-4">
51
- <h1 class="text-4xl font-black tracking-tight text-base-content sm:text-5xl">
52
- {appM.hero_title({ name: sharedM.app_name() })}
53
- </h1>
54
- <p class="max-w-xl text-lg leading-8 text-base-content/70">
55
- {appM.hero_subtitle()}
56
- </p>
57
- </div>
58
- <div class="flex flex-wrap gap-3">
59
- <a class="btn btn-primary shadow-lg shadow-primary/20" href="#status">
60
- <span class="icon-[tabler--activity-heartbeat] size-5"></span>
61
- {appM.hero_primary_action()}
62
- </a>
63
- <a class="btn btn-ghost" href="#customize">
64
- <span class="icon-[tabler--adjustments] size-5"></span>
65
- {appM.hero_secondary_action()}
66
- </a>
67
- </div>
68
- </div>
69
- </section>
70
-
71
- <aside class="rounded-[2rem] border border-base-300/70 bg-base-100/80 p-5 shadow-xl backdrop-blur">
72
- <div class="mockup-window border border-base-300 bg-base-200/70">
73
- <div class="space-y-4 bg-base-100 p-5">
74
- <div class="flex items-center justify-between">
75
- <div>
76
- <p class="text-sm font-semibold">{appM.preview_title()}</p>
77
- <p class="text-xs text-base-content/55">{appM.preview_body()}</p>
78
- </div>
79
- <span class="badge badge-success badge-outline">{appM.platform_name()}</span>
80
- </div>
81
- <div class="grid gap-3 text-sm">
82
- <div class="rounded-2xl bg-primary/10 p-4">
83
- <span class="icon-[tabler--components] mb-2 size-6 text-primary"></span>
84
- <p class="font-semibold">{appM.preview_metric_shared()}</p>
85
- </div>
86
- <div class="grid grid-cols-2 gap-3">
87
- <div class="rounded-2xl bg-secondary/10 p-4">
88
- <span class="icon-[tabler--language] mb-2 size-6 text-secondary"></span>
89
- <p class="font-semibold">{appM.preview_metric_local()}</p>
90
- </div>
91
- <div class="rounded-2xl bg-accent/10 p-4">
92
- <span class="icon-[tabler--palette] mb-2 size-6 text-accent"></span>
93
- <p class="font-semibold">{appM.preview_metric_theme()}</p>
94
- </div>
95
- </div>
96
- </div>
97
- </div>
98
- </div>
99
- </aside>
100
- </div>
101
-
102
- <div class="grid gap-6 lg:grid-cols-[0.95fr_1.05fr]">
103
- <div id="status">
104
- <Card title={appM.status_title()} bordered shadow="md" class="bg-base-100/90 backdrop-blur">
105
- <p class="mb-5 text-sm text-base-content/65">{appM.status_description()}</p>
106
- {#if loading}
107
- <Skeleton variant="title" class="mb-3" />
108
- <Skeleton count={3} />
109
- <p class="sr-only" data-testid="service-status">{sharedM.home_loading()}</p>
110
- {:else if info}
111
- <Alert variant="success" title={appM.status_online({ name: info.name })}>
112
- <p data-testid="service-status">{info.name}</p>
113
- </Alert>
114
- <dl class="mt-5 grid gap-3 text-sm sm:grid-cols-2">
115
- <div class="rounded-box border border-base-300/70 bg-base-200/60 p-4">
116
- <dt class="text-xs text-base-content/55">{appM.status_version()}</dt>
117
- <dd class="mt-1 font-semibold">{info.version}</dd>
118
- </div>
119
- <div class="rounded-box border border-base-300/70 bg-base-200/60 p-4">
120
- <dt class="text-xs text-base-content/55">{appM.status_started({ time: info.startedAt })}</dt>
121
- <dd class="mt-1 font-semibold">{appM.status_frontends_count({ count: String(info.frontends.length) })}</dd>
122
- </div>
123
- </dl>
124
- {:else}
125
- <Alert variant="error" title={sharedM.home_error()}>
126
- <p data-testid="service-status">{errorMessage}</p>
127
- </Alert>
128
- {/if}
129
-
130
- <div class="mt-5">
131
- <Button type="button" variant="primary" loading={loading} onclick={refreshStatus}>
132
- {sharedM.home_refresh()}
133
- </Button>
134
- </div>
135
- </Card>
136
- </div>
137
-
138
- <section id="customize" class="grid gap-4 sm:grid-cols-2">
139
- <div class="rounded-[1.5rem] border border-base-300/70 bg-base-100/90 p-5 shadow-md">
140
- <span class="icon-[tabler--package] mb-4 size-7 text-primary"></span>
141
- <h2 class="text-lg font-bold">{appM.custom_shared_title()}</h2>
142
- <p class="mt-2 text-sm leading-6 text-base-content/65">{appM.custom_shared_body()}</p>
143
- </div>
144
- <div class="rounded-[1.5rem] border border-base-300/70 bg-base-100/90 p-5 shadow-md">
145
- <span class="icon-[tabler--message-language] mb-4 size-7 text-secondary"></span>
146
- <h2 class="text-lg font-bold">{appM.custom_local_title()}</h2>
147
- <p class="mt-2 text-sm leading-6 text-base-content/65">{appM.custom_local_body()}</p>
148
- </div>
149
- </section>
150
- </div>
151
- </section>
152
- </AppShell>
153
- {{/if}}
14
+ <AdminWorkspace platform="web" {apiOptions} onLocaleChange={syncLocale} />
15
+ {{/if}}
@@ -5,4 +5,4 @@
5
5
  import '@h-ai/ui/auto-import'
6
6
 
7
7
  declare module '*.css'
8
- {{/if}}
8
+ {{/if}}
@@ -11,4 +11,4 @@ if (!target)
11
11
  const app = mount(App, { target })
12
12
 
13
13
  export default app
14
- {{/if}}
14
+ {{/if}}