@h-ai/cli 0.1.0-alpha.57 → 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 (175) hide show
  1. package/README.en.md +37 -3
  2. package/README.ja.md +37 -3
  3. package/README.md +37 -3
  4. package/dist/chunk-2H7UOFLK.js +0 -0
  5. package/dist/{chunk-MJGUBOAV.js → chunk-F4IBPVZ5.js} +6 -42
  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-ZYXES3NT.js → cli-skill-templates-45CK4RQ2.js} +3 -3
  12. package/dist/{cli-skill-templates-ZYXES3NT.js.map → cli-skill-templates-45CK4RQ2.js.map} +1 -1
  13. package/dist/index.js +107 -61
  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/.npmrc.hbs +1 -2
  23. package/templates/apps/api/Dockerfile.hbs +6 -5
  24. package/templates/apps/api/apps/{{projectName}}-contract/package.json.hbs +1 -1
  25. package/templates/apps/api/apps/{{projectName}}-contract/src/app-schemas.ts.hbs +2 -0
  26. package/templates/apps/api/apps/{{projectName}}-contract/tsup.config.ts.hbs +1 -1
  27. package/templates/apps/api/apps/{{projectName}}-service/config/_core.yml.hbs +8 -0
  28. package/templates/apps/api/apps/{{projectName}}-service/package.json.hbs +1 -1
  29. package/templates/apps/api/apps/{{projectName}}-service/src/app.ts.hbs +7 -8
  30. package/templates/apps/api/apps/{{projectName}}-service/src/index.ts.hbs +4 -3
  31. package/templates/apps/api/apps/{{projectName}}-service/src/lib/server/init.ts.hbs +0 -1
  32. package/templates/apps/api/apps/{{projectName}}-service/src/server/procedures/app-procedures.ts.hbs +4 -0
  33. package/templates/apps/api/apps/{{projectName}}-service/tests/service.test.ts.hbs +3 -1
  34. package/templates/apps/api/e2e/api-service.spec.ts.hbs +3 -1
  35. package/templates/apps/api/package.json.hbs +2 -2
  36. package/templates/apps/api/pnpm-workspace.yaml.hbs +26 -0
  37. package/templates/apps/api/tsconfig.base.json +0 -1
  38. package/templates/apps/fullstack/.dockerignore.hbs +3 -0
  39. package/templates/apps/fullstack/.npmrc.hbs +1 -2
  40. package/templates/apps/fullstack/Dockerfile.hbs +6 -5
  41. package/templates/apps/fullstack/apps/{{projectName}}-app/README.md.hbs +2 -2
  42. package/templates/apps/fullstack/apps/{{projectName}}-app/capacitor.config.ts.hbs +1 -1
  43. package/templates/apps/fullstack/apps/{{projectName}}-app/index.html.hbs +7 -2
  44. package/templates/apps/fullstack/apps/{{projectName}}-app/messages/en-US.json.hbs +1 -34
  45. package/templates/apps/fullstack/apps/{{projectName}}-app/messages/zh-CN.json.hbs +1 -34
  46. package/templates/apps/fullstack/apps/{{projectName}}-app/package.json.hbs +2 -2
  47. package/templates/apps/fullstack/apps/{{projectName}}-app/src/App.svelte.hbs +30 -170
  48. package/templates/apps/fullstack/apps/{{projectName}}-app/src/app.d.ts.hbs +1 -1
  49. package/templates/apps/fullstack/apps/{{projectName}}-app/src/lib/capacitor.ts.hbs +6 -5
  50. package/templates/apps/fullstack/apps/{{projectName}}-app/src/main.ts.hbs +1 -1
  51. package/templates/apps/fullstack/apps/{{projectName}}-app/vite.config.ts.hbs +48 -22
  52. package/templates/apps/fullstack/apps/{{projectName}}-desktop/README.md.hbs +3 -1
  53. package/templates/apps/fullstack/apps/{{projectName}}-desktop/index.html.hbs +6 -1
  54. package/templates/apps/fullstack/apps/{{projectName}}-desktop/messages/en-US.json.hbs +1 -28
  55. package/templates/apps/fullstack/apps/{{projectName}}-desktop/messages/zh-CN.json.hbs +1 -28
  56. package/templates/apps/fullstack/apps/{{projectName}}-desktop/package.json.hbs +5 -4
  57. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/App.svelte.hbs +10 -141
  58. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/Cargo.toml.hbs +5 -5
  59. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/tauri.conf.json.hbs +3 -3
  60. package/templates/apps/fullstack/apps/{{projectName}}-desktop/vite.config.ts.hbs +21 -2
  61. package/templates/apps/fullstack/apps/{{projectName}}-web/README.md.hbs +2 -2
  62. package/templates/apps/fullstack/apps/{{projectName}}-web/index.html.hbs +6 -1
  63. package/templates/apps/fullstack/apps/{{projectName}}-web/messages/en-US.json.hbs +1 -28
  64. package/templates/apps/fullstack/apps/{{projectName}}-web/messages/zh-CN.json.hbs +1 -28
  65. package/templates/apps/fullstack/apps/{{projectName}}-web/package.json.hbs +2 -2
  66. package/templates/apps/fullstack/apps/{{projectName}}-web/src/App.svelte.hbs +5 -143
  67. package/templates/apps/fullstack/apps/{{projectName}}-web/src/app.d.ts.hbs +1 -1
  68. package/templates/apps/fullstack/apps/{{projectName}}-web/src/main.ts.hbs +1 -1
  69. package/templates/apps/fullstack/apps/{{projectName}}-web/vite.config.ts.hbs +48 -22
  70. package/templates/apps/fullstack/e2e/fullstack.spec.ts.hbs +206 -16
  71. package/templates/apps/fullstack/package.json.hbs +2 -2
  72. package/templates/apps/fullstack/packages/{{projectName}}-contract/README.md.hbs +2 -0
  73. package/templates/apps/fullstack/packages/{{projectName}}-contract/package.json.hbs +1 -1
  74. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/admin-contract.ts.hbs +66 -0
  75. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/admin-schemas.ts.hbs +96 -0
  76. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/app-schemas.ts.hbs +3 -0
  77. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/index.ts.hbs +3 -1
  78. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/{{projectName}}-contract.ts.hbs +5 -0
  79. package/templates/apps/fullstack/packages/{{projectName}}-contract/tests/contract.test.ts.hbs +3 -0
  80. package/templates/apps/fullstack/packages/{{projectName}}-contract/tsup.config.ts.hbs +1 -1
  81. package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +13 -3
  82. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_audit.yml.hbs +3 -0
  83. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_cache.yml.hbs +2 -0
  84. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_core.yml.hbs +10 -3
  85. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_db.yml.hbs +3 -0
  86. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_iam.yml.hbs +21 -0
  87. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_serv.yml.hbs +10 -3
  88. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_storage.yml.hbs +3 -0
  89. package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +10 -3
  90. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/app-server.ts.hbs +63 -28
  91. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/index.ts.hbs +26 -11
  92. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/admin-service.ts.hbs +276 -0
  93. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/messages.ts.hbs +29 -0
  94. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/admin-procedures.ts.hbs +94 -0
  95. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/app-procedures.ts.hbs +6 -0
  96. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/index.ts.hbs +5 -1
  97. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/runtime.ts.hbs +98 -0
  98. package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/app-server.test.ts.hbs +446 -33
  99. package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/runtime.test.ts.hbs +48 -0
  100. package/templates/apps/fullstack/packages/{{projectName}}-serv/tsup.config.ts.hbs +1 -1
  101. package/templates/apps/fullstack/packages/{{projectName}}-shared/README.md.hbs +19 -26
  102. package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/en-US.json.hbs +78 -15
  103. package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/zh-CN.json.hbs +78 -15
  104. package/templates/apps/fullstack/packages/{{projectName}}-shared/package.json.hbs +4 -1
  105. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/index.ts.hbs +3 -4
  106. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/api-client.ts.hbs +53 -27
  107. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AdminWorkspace.svelte.hbs +73 -0
  108. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AppShell.svelte.hbs +55 -45
  109. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AuditManagement.svelte.hbs +61 -0
  110. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/ProfileSettings.svelte.hbs +57 -0
  111. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/RoleManagement.svelte.hbs +49 -0
  112. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/UserManagement.svelte.hbs +174 -0
  113. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/management-store.svelte.ts.hbs +399 -0
  114. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/theme-store.svelte.ts.hbs +7 -39
  115. package/templates/apps/fullstack/packages/{{projectName}}-shared/svelte.config.js.hbs +1 -0
  116. package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/api-client.test.ts.hbs +151 -0
  117. package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/management-store.test.ts.hbs +101 -0
  118. package/templates/apps/fullstack/packages/{{projectName}}-shared/vitest.config.ts.hbs +7 -0
  119. package/templates/apps/fullstack/playwright.config.ts.hbs +6 -0
  120. package/templates/apps/fullstack/pnpm-workspace.yaml.hbs +24 -0
  121. package/templates/apps/fullstack/tsconfig.base.json +0 -1
  122. package/templates/apps/h5/src/routes/+layout.svelte.hbs +4 -0
  123. package/templates/apps/h5/src/routes/+page.svelte.hbs +3 -2
  124. package/templates/apps/mobile-app/index.html.hbs +2 -2
  125. package/templates/apps/mobile-app/src/App.svelte.hbs +6 -2
  126. package/templates/apps/mobile-app/src/lib/app-config.ts.hbs +13 -0
  127. package/templates/apps/website/src/routes/+layout.svelte.hbs +8 -2
  128. package/templates/apps/website/src/routes/+page.svelte.hbs +4 -3
  129. package/templates/base/.npmrc.hbs +1 -15
  130. package/templates/base/Dockerfile.hbs +9 -8
  131. package/templates/base/e2e/app.spec.ts.hbs +1 -0
  132. package/templates/base/package.json.hbs +39 -42
  133. package/templates/base/pnpm-workspace.yaml.hbs +26 -0
  134. package/templates/base/src/app.d.ts.hbs +4 -0
  135. package/templates/base/src/hooks.server.ts.hbs +0 -8
  136. package/templates/base/src/lib/server/init.ts.hbs +26 -5
  137. package/templates/base/src/routes/+layout.server.ts.hbs +18 -0
  138. package/templates/base/tests/scaffold.test.ts.hbs +21 -1
  139. package/templates/base/vite.config.ts.hbs +21 -0
  140. package/templates/features/ai/routes/api/chat/+server.ts +6 -7
  141. package/templates/features/iam/routes-admin/(auth)/auth/login/+page.svelte.hbs +1 -1
  142. package/templates/features/iam/routes-h5/auth/login/+page.svelte.hbs +1 -1
  143. package/templates/features/iam/routes-shared/api/auth/login/+server.ts +14 -10
  144. package/templates/features/iam/routes-shared/api/auth/logout/+server.ts +6 -4
  145. package/templates/features/storage/routes/api/upload/+server.ts +10 -8
  146. package/templates/skills/CLAUDE.md +0 -14
  147. package/templates/skills/bridges/fullstack/AGENTS.md.hbs +13 -2
  148. package/templates/skills/bridges/fullstack/copilot-instructions.md.hbs +3 -0
  149. package/templates/skills/hai-api-client/SKILL.md +1 -1
  150. package/templates/skills/hai-app-create/development.md +6 -0
  151. package/templates/skills/hai-build/reference.md +4 -2
  152. package/templates/skills/hai-core/SKILL.md +2 -0
  153. package/templates/skills/hai-core/reference.md +6 -4
  154. package/templates/skills/hai-framework-sync/SKILL.md +1 -2
  155. package/templates/skills/hai-serv/SKILL.md +1 -0
  156. package/templates/skills/hai-serv/reference.md +3 -1
  157. package/templates/skills/hai-ui/SKILL.md +6 -0
  158. package/templates/skills/hai-ui/reference.md +7 -4
  159. package/templates/skills/hai-vecdb/reference.md +53 -49
  160. package/dist/chunk-MJGUBOAV.js.map +0 -1
  161. package/dist/chunk-O3ANVICQ.js.map +0 -1
  162. package/dist/cli-config-templates-OWBEGBZQ.js +0 -5
  163. package/dist/src-TBIET7YU.js.map +0 -1
  164. package/templates/apps/fullstack/apps/{{projectName}}-app/tests/api.test.ts.hbs +0 -28
  165. package/templates/apps/fullstack/apps/{{projectName}}-desktop/tests/api.test.ts.hbs +0 -28
  166. package/templates/apps/fullstack/apps/{{projectName}}-web/tests/api.test.ts.hbs +0 -55
  167. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/LanguageSwitcher.svelte.hbs +0 -27
  168. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/ThemeSwitcher.svelte.hbs +0 -18
  169. package/templates/skills/bridges/admin/CLAUDE.md +0 -15
  170. package/templates/skills/bridges/api/CLAUDE.md +0 -15
  171. package/templates/skills/bridges/fullstack/CLAUDE.md.hbs +0 -9
  172. package/templates/skills/bridges/h5/CLAUDE.md +0 -15
  173. package/templates/skills/bridges/mobile-app/CLAUDE.md +0 -15
  174. package/templates/skills/bridges/website/CLAUDE.md +0 -15
  175. package/templates/skills/claude-skill.md.hbs +0 -7
@@ -0,0 +1,18 @@
1
+ {{! @skipIfEmpty }}
2
+ {{#unless isSvelteOnlyApp}}
3
+ import type { CoreConfig } from '@h-ai/core'
4
+ import { core } from '@h-ai/core'
5
+
6
+ /** 只向浏览器提供公开配置,避免暴露日志上下文、凭证或其它模块配置。 */
7
+ export function load() {
8
+ const config = core.config.getOrThrow<CoreConfig>('core')
9
+ return {
10
+ appConfig: {
11
+ name: config.name,
12
+ version: config.version,
13
+ env: config.env,
14
+ defaultLocale: config.defaultLocale,
15
+ },
16
+ }
17
+ }
18
+ {{/unless}}
@@ -1,7 +1,16 @@
1
+ {{#unless isSvelteOnlyApp}}
2
+ import type { CoreConfig } from '@h-ai/core'
3
+ {{/unless}}
1
4
  import { readFile } from 'node:fs/promises'
2
5
  import { join } from 'node:path'
3
6
  import { fileURLToPath } from 'node:url'
7
+ {{#unless isSvelteOnlyApp}}
8
+ import { core } from '@h-ai/core'
9
+ {{/unless}}
4
10
  import { describe, expect, it } from 'vitest'
11
+ {{#unless isSvelteOnlyApp}}
12
+ import { load } from '../src/routes/+layout.server'
13
+ {{/unless}}
5
14
 
6
15
  const rootDir = fileURLToPath(new URL('..', import.meta.url))
7
16
 
@@ -39,4 +48,15 @@ describe('generated scaffold', () => {
39
48
  expect(coreConfig).toContain('defaultLocale: {{defaultLocale}}')
40
49
  })
41
50
  {{/unless}}
42
- })
51
+ {{#unless isSvelteOnlyApp}}
52
+
53
+ it('publishes only public metadata from parsed core configuration', () => {
54
+ core.init({ configDir: './config' })
55
+ const config = core.config.getOrThrow<CoreConfig>('core')
56
+ expect(core.logger.getLevel()).toBe(config.logging?.level ?? 'info')
57
+ expect(load()).toEqual({
58
+ appConfig: { name: config.name, version: config.version, env: config.env, defaultLocale: config.defaultLocale },
59
+ })
60
+ })
61
+ {{/unless}}
62
+ })
@@ -1,8 +1,14 @@
1
1
  /**
2
2
  * {{projectName}} - Vite 配置
3
3
  */
4
+ {{#if isSvelteOnlyApp}}
5
+ import type { CoreConfig } from '@h-ai/core'
6
+ {{/if}}
4
7
  import path from 'node:path'
5
8
  import process from 'node:process'
9
+ {{#if isSvelteOnlyApp}}
10
+ import { core } from '@h-ai/core'
11
+ {{/if}}
6
12
  {{#if hasUi}}
7
13
  import { haiOptimizeExclude, haiPrebundledDeps } from '@h-ai/ui/vite'
8
14
  {{/if}}
@@ -22,8 +28,23 @@ import { defineConfig, loadEnv } from 'vite'
22
28
  export default defineConfig(({ mode }) => {
23
29
  const env = loadEnv(mode, process.cwd(), '')
24
30
  Object.assign(process.env, env)
31
+ {{#if isSvelteOnlyApp}}
32
+ // 浏览器无法读取 YAML;构建时通过 core 解析,仅注入明确可公开的字段。
33
+ core.init({ configDir: './config' })
34
+ const config = core.config.getOrThrow<CoreConfig>('core')
35
+ const appConfig = {
36
+ name: config.name,
37
+ version: config.version,
38
+ env: config.env,
39
+ defaultLocale: config.defaultLocale,
40
+ logging: config.logging ? { level: config.logging.level, format: config.logging.format } : undefined,
41
+ }
42
+ {{/if}}
25
43
 
26
44
  return {
45
+ {{#if isSvelteOnlyApp}}
46
+ define: { __APP_CORE_CONFIG__: JSON.stringify(appConfig) },
47
+ {{/if}}
27
48
  plugins: [
28
49
  {{#if isSvelteOnlyApp}}
29
50
  svelte(),
@@ -4,23 +4,22 @@
4
4
  import type { RequestHandler } from './$types'
5
5
  import { ai } from '@h-ai/ai'
6
6
  import { kit } from '@h-ai/kit'
7
+ import { z } from 'zod'
7
8
 
8
- export const POST: RequestHandler = async ({ request, locals }) => {
9
- const { message } = await request.json()
9
+ const ChatInputSchema = z.object({ message: z.string().trim().min(1).max(4000) }).strict()
10
10
 
11
- if (!message) {
12
- return kit.response.badRequest('message is required')
13
- }
11
+ export const POST: RequestHandler = kit.handler(async ({ request, locals }) => {
12
+ const { message } = await kit.validate.body(request, ChatInputSchema)
14
13
 
15
14
  const result = await ai.llm.ask(message, {
16
15
  systemPrompt: 'You are a helpful assistant.',
17
16
  })
18
17
 
19
18
  if (!result.success) {
20
- return kit.response.internalError(result.error.message)
19
+ return kit.response.fromError(result.error, locals.requestId)
21
20
  }
22
21
 
23
22
  return kit.response.ok({
24
23
  reply: result.data,
25
24
  }, locals.requestId)
26
- }
25
+ })
@@ -22,7 +22,7 @@
22
22
  const res = await fetch('/api/auth/login', {
23
23
  method: 'POST',
24
24
  headers: { 'Content-Type': 'application/json' },
25
- body: JSON.stringify({ username, password }),
25
+ body: JSON.stringify({ identifier: username, password }),
26
26
  })
27
27
  const data = await res.json()
28
28
  if (data.success) {
@@ -22,7 +22,7 @@
22
22
  const res = await fetch('/api/auth/login', {
23
23
  method: 'POST',
24
24
  headers: { 'Content-Type': 'application/json' },
25
- body: JSON.stringify({ username, password }),
25
+ body: JSON.stringify({ identifier: username, password }),
26
26
  })
27
27
  const data = await res.json()
28
28
  if (data.success) {
@@ -1,32 +1,36 @@
1
+ import type { CoreConfig } from '@h-ai/core'
1
2
  /**
2
3
  * 登录 API
3
4
  */
4
5
  import type { RequestHandler } from './$types'
6
+ import { core } from '@h-ai/core'
5
7
  import { iam } from '@h-ai/iam'
6
8
  import { kit } from '@h-ai/kit'
9
+ import { z } from 'zod'
7
10
 
8
- export const POST: RequestHandler = async ({ request, cookies, locals }) => {
9
- const body = await request.json()
10
- const { identifier, password } = body
11
+ const LoginInputSchema = z.object({
12
+ identifier: z.string().trim().min(1).max(254),
13
+ password: z.string().min(1).max(128),
14
+ }).strict()
11
15
 
12
- if (!identifier || !password) {
13
- return kit.response.badRequest('identifier and password are required')
14
- }
16
+ export const POST: RequestHandler = kit.handler(async ({ request, cookies, locals }) => {
17
+ const { identifier, password } = await kit.validate.body(request, LoginInputSchema)
15
18
 
16
19
  const result = await iam.auth.login({ identifier, password })
17
20
  if (!result.success) {
18
- return kit.response.unauthorized(result.error.message)
21
+ return kit.response.fromError(result.error, locals.requestId)
19
22
  }
20
23
 
21
24
  const { tokens } = result.data
25
+ const config = core.config.getOrThrow<CoreConfig>('core')
22
26
 
23
27
  cookies.set('session_token', tokens.accessToken, {
24
28
  path: '/',
25
29
  httpOnly: true,
26
30
  sameSite: 'lax',
27
- secure: false,
31
+ secure: config.env === 'production' || config.env === 'staging',
28
32
  maxAge: tokens.expiresIn,
29
33
  })
30
34
 
31
- return kit.response.ok({ message: 'Login successful' }, locals.requestId)
32
- }
35
+ return kit.response.ok({ authenticated: true }, locals.requestId)
36
+ })
@@ -5,11 +5,13 @@ import type { RequestHandler } from './$types'
5
5
  import { iam } from '@h-ai/iam'
6
6
  import { kit } from '@h-ai/kit'
7
7
 
8
- export const POST: RequestHandler = async ({ cookies, locals }) => {
8
+ export const POST: RequestHandler = kit.handler(async ({ cookies, locals }) => {
9
9
  const token = cookies.get('session_token')
10
10
  if (token) {
11
- await iam.auth.logout(token)
11
+ const result = await iam.auth.logout(token)
12
+ if (!result.success)
13
+ return kit.response.fromError(result.error, locals.requestId)
12
14
  }
13
15
  cookies.delete('session_token', { path: '/' })
14
- return kit.response.ok({ message: 'Logout successful' }, locals.requestId)
15
- }
16
+ return kit.response.ok({ authenticated: false }, locals.requestId)
17
+ })
@@ -2,28 +2,30 @@
2
2
  * 文件上传 API — storage 功能示例
3
3
  */
4
4
  import type { RequestHandler } from './$types'
5
+ import { core } from '@h-ai/core'
5
6
  import { kit } from '@h-ai/kit'
6
7
  import { storage } from '@h-ai/storage'
7
8
 
8
- export const POST: RequestHandler = async ({ request, locals }) => {
9
+ export const POST: RequestHandler = kit.handler(async ({ request, locals }) => {
9
10
  const formData = await request.formData()
10
- const file = formData.get('file') as File | null
11
+ const file = formData.get('file')
11
12
 
12
- if (!file) {
13
- return kit.response.badRequest('No file provided')
13
+ if (!(file instanceof File) || file.size === 0 || file.size > 10 * 1024 * 1024) {
14
+ return kit.response.badRequest(core.i18n.coreM('core_errorValidation'), locals.requestId)
14
15
  }
15
16
 
16
17
  const { Buffer } = await import('node:buffer')
17
18
  const buffer = Buffer.from(await file.arrayBuffer())
18
- const key = `uploads/${Date.now()}-${file.name}`
19
+ // 路径由服务端生成,用户文件名仅作为元数据保存。
20
+ const key = `uploads/${core.id.uuid()}`
19
21
 
20
- const result = await storage.put(key, buffer, {
22
+ const result = await storage.file.put(key, buffer, {
21
23
  contentType: file.type,
22
24
  metadata: { originalName: file.name },
23
25
  })
24
26
 
25
27
  if (!result.success) {
26
- return kit.response.internalError(result.error.message)
28
+ return kit.response.fromError(result.error, locals.requestId)
27
29
  }
28
30
 
29
31
  return kit.response.ok({
@@ -32,4 +34,4 @@ export const POST: RequestHandler = async ({ request, locals }) => {
32
34
  size: file.size,
33
35
  type: file.type,
34
36
  }, locals.requestId)
35
- }
37
+ })
@@ -1,15 +1 @@
1
- # CLAUDE.md
2
-
3
1
  @AGENTS.md
4
-
5
- > Claude Code 项目指引。共享规范通过 `@AGENTS.md` 复用;本文件用于 generic fallback 场景,模块和工作流参考资料位于 `.agents/skills/`。
6
-
7
- 共享规则见项目根 [AGENTS.md](AGENTS.md);若未自动加载,先读取该文件。模块/流程按需读取项目根 .agents/skills/<name>/SKILL.md 及其相邻参考文件。
8
-
9
- ## 质量门禁
10
-
11
- 按 AGENTS.md 和实际 package.json 选择 typecheck、lint、build、test、test:e2e;最终说明已执行结果、未运行原因及同步文档/依赖方。
12
-
13
- 普通新增、修改、修复任务先读 [应用开发 Skill](.agents/skills/hai-app-create/SKILL.md) 和 [开发规范与框架能力路由](.agents/skills/hai-app-create/development.md),依照 AGENTS.md 的默认规则复用框架并完成安全与质量验证。
14
-
15
- Claude Code 从 `.claude/skills/` 原生发现技能入口,再读取 `.agents/skills/` 的共享正文与相邻参考。项目规则通过 `@AGENTS.md` 加载;同名技能不在入口目录另维护一份规则。
@@ -29,7 +29,18 @@ Fullstack 多包工程入口。先读 README、根 workspace 脚本与相关 pac
29
29
 
30
30
  - 前端负责 UI 与请求编排;后端业务放 serv,共享能力放 shared。本样板默认不用 `@h-ai/kit`,不要混入 SvelteKit load / route 结构。
31
31
  - 用户文本按 shared 跨端文案与各 app 专属文案分工,同步现有 locale。
32
- - 认证接入前检查现有实现;样板不意味着已配好 Cookie 或安全 token 存储。新增认证时 Web 明确 Cookie/内存方案,App 原生端配置安全 TokenStorage,Desktop 按 Tauri 安全边界实现。
32
+ - 本样板默认启用 IAM、reldb、cache、audit、storage 和 crypto,复用现有初始化与关闭顺序;新增模块前先检查依赖、配置与公开契约。
33
+ - 应用名称、版本、环境、日志与 locale 配置通过 core 统一获取;浏览器显示来自服务端 `app.info`,不另写硬编码副本或将私有配置注入客户端。
34
+
35
+ ## 管理与安全边界
36
+
37
+ - `admin` / `user` 是固定角色代码。管理员进入用户、角色和审计管理;普通用户只进入个人设置。服务端为每个管理操作验证角色,个人资料、密码和头像按当前会话绑定用户,不能只靠导航隐藏保护权限。
38
+ - 角色管理更新说明并显示人数,用户管理负责角色分配;保留当前管理员的自删除、自禁用、自降级及最后管理员保护,并验证并发管理请求。
39
+ - JSON 业务请求与响应统一经 typed api-client 和 serv 的 crypto transport 加解密,包含登录与刷新;健康/就绪检查和公开头像二进制资源遵循已有例外,不能为新增业务 API 绕过传输加密。
40
+ - Web 使用内存 access token 和 HttpOnly refresh Cookie;App 原生端装配 `createCapacitorTokenStorage`,浏览器预览沿用 Cookie;Desktop 原生端使用内存 TokenStorage,重启后重新登录。原生 body 刷新通道同时验证 `X-HAI-Token-Transport: body`、端对应的 `x-request-client` 与受信完整 Origin,刷新请求沿用这些头。敏感 token 不写 localStorage,不擅自将其持久化到普通配置文件。
41
+ - 头像接受 PNG/JPEG/WebP,最大 512 KiB;contract、客户端与服务端校验保持一致。服务端验证实际图片数据并生成 storage key;普通用户仅更新自己的头像,管理员可替用户更新。
42
+ - 用户与审计查询按 contract 分页,`page >= 1`、`pageSize` 为 1–100;页面默认每页 20 条。新增筛选同步 schema、procedure、store 和测试,SQL 值参数化。
43
+ - 语言与主题偏好保存到当前用户 metadata,客户端只应用已支持的值。审计仅记录操作字段和资源标识,不记录密码、token、头像内容或联系信息。
33
44
 
34
45
  ## 质量门禁
35
46
 
@@ -52,4 +63,4 @@ pnpm test:e2e
52
63
 
53
64
  ## 优先 Skills
54
65
 
55
- 构建与验收:`hai-build`、`hai-app-review`、`hai-app-tests`。模块使用:`hai-core`、`hai-ui`、`hai-serv`、`hai-api-contract`、`hai-api-client`、`hai-capacitor`;其余按需选择。
66
+ 构建与验收:`hai-build`、`hai-app-review`、`hai-app-tests`。管理业务按需读取 `hai-iam`、`hai-reldb`、`hai-cache`、`hai-audit`、`hai-storage`、`hai-crypto`;配置与跨端读取 `hai-core`、`hai-ui`、`hai-serv`、`hai-api-contract`、`hai-api-client`、`hai-capacitor`。
@@ -4,6 +4,9 @@
4
4
 
5
5
  - `packages/{{projectName}}-contract` 定义 API;Fullstack 服务端 `packages/{{projectName}}-serv` 实现业务;`packages/{{projectName}}-shared` 共享 UI、i18n 和 typed client。
6
6
  - 前端按选择生成;App 使用 Capacitor,Desktop 使用 Tauri v2。miniapp 当前仅预留说明,不是可运行应用。
7
+ - 默认 mini 管理后台复用 IAM/reldb/cache/audit/storage/crypto。管理员管理用户、固定 admin/user 角色及审计;普通用户仅操作个人设置,服务端按角色和当前会话验证权限。
8
+ - typed api-client 与 serv 的 crypto transport 统一加解密 JSON 请求与响应,包含认证与刷新。Web 使用内存 access token + HttpOnly refresh Cookie,App 原生端使用 Capacitor 安全 TokenStorage,Desktop 使用内存 TokenStorage;具体边界与例外见根 AGENTS。
9
+ - 应用名称、版本、环境、日志与 locale 配置通过 core 获取;前端消费 `app.info`。头像、分页、偏好与管理员保护以 contract、服务端实现和根 AGENTS 为准,改动时同步各端。
7
10
 
8
11
  ## 质量门禁
9
12
 
@@ -126,7 +126,7 @@ Access token 存在内存中,refresh token 由服务端通过 `HttpOnly` cooki
126
126
 
127
127
  启用 `transport` 时,登录、业务请求以及 401 后的自动刷新都会复用同一个加密 fetch 链路;不要在业务代码中手写明文 `/auth/refresh` 请求。
128
128
 
129
- 自动刷新仅检查真实 HTTP 401(`Response.status`)。serv 普通 procedure 默认通过 HTTP 200 返回失败 HaiResult,其中 `error.httpStatus=401` 不会触发自动刷新;调用方仍须检查 `success` 与 `error.code` 并处理登录失效。
129
+ 自动刷新识别真实 HTTP 401(`Response.status`),以及 HTTP 200 的有效失败 HaiResult(`success=false`、字符串 `error.code/message`、`error.httpStatus=401`),成功后只重试一次原请求。内置登录、注册与配置的 `auth.refreshPath` 排除自动刷新,403/500 等其它失败也不刷新。serv 普通 procedure 的 HTTP 状态仍为 200;调用方须检查最终 `success/error.code` 并处理刷新失败后的登录失效。
130
130
 
131
131
  ```ts
132
132
  import { apiClient } from '@h-ai/api-client'
@@ -11,6 +11,8 @@
11
11
 
12
12
  ## 将需求映射到现有能力
13
13
 
14
+ 应用元信息只有一份配置来源:名称、版本、环境、默认语言与日志设置来自 `_core.yml`,使用 `core.config` 与 `core.logger`;Node 启动时不通过固定 `logging` 覆盖 YAML。SvelteKit 服务端 layout 和 fullstack `app.info` 仅公开必要元信息,不能下发整个 core 或模块配置。独立 Vite mobile-app 在 Node 构建阶段经 core 加载 YAML/环境覆盖并注入公开字段,配置变化需重新构建。环境覆盖使用 `HAI_CORE_NAME`、`HAI_CORE_VERSION`、`HAI_CORE_ENV`、`HAI_CORE_LOGGING_LEVEL` 等既有规则;容器明确配置生产环境,不能用另一个状态来源代替 `core.env`。
15
+
14
16
  开发前,对本次涉及的需求简述“需求 → 现有应用实现/框架能力 → 版本与契约依据 → 修改位置与验收”。简单任务可用几句话;跨模块任务用表格。查找顺序:已有应用实现 → 框架公开能力和配置 → 最小业务补充。
15
17
 
16
18
  下表技能名用于能力导航;先确认 `.agents/skills/<name>/SKILL.md` 存在再读取。CLI 按应用类型/已选模块交付技能,缺目录不代表框架没有该能力:继续查已安装包的公开 exports/types;确需补充模块/技能时按当前 CLI 帮助和项目依赖策略处理,不能跳过需求匹配或猜测不存在的 API。
@@ -39,6 +41,10 @@
39
41
 
40
42
  已有能力满足需求时使用它;已导入模块但仍手写其已有认证、缓存、上传、分页或 UI 功能,需要修正。确有缺口时记录缺失的具体能力、当前版本和最小补充方案,按需求增加依赖或应用代码;不为凑模块覆盖率增加服务和抽象。
41
43
 
44
+ 独立 fullstack 默认后台的 Web/App/Desktop 共用管理组件、状态与 typed client。`@h-ai/serv/features/iam` 默认 procedures 可按需选用并与 contract 对齐;仅为业务审计或资源策略覆写必要路由。主题的 DOM 更新和安全缓存使用 `@h-ai/ui/theme`(`applyTheme` / `getSavedTheme`),应用只保留响应式状态与已编译主题白名单。固定角色、管理员自我保护、头像资源范围及写失败补偿仍由应用按需求实现。
45
+
46
+ Fullstack 创建时在被 Git 与容器构建忽略的根 `.env` 写入独立随机 `HAI_ADMIN_DEFAULT_PASSWORD`,`.env.example` 保留空占位。`dev` / `start` 自动读取;已有用户不重设密码。启动边界保留模块错误的具体说明与错误码,失败后反序清理。不能把生成的本地凭据复制到前端配置、日志、源码或镜像。
47
+
42
48
  ## 落实契约与安全边界
43
49
 
44
50
  按本次真实输入、资源和副作用选取下面检查,并把适用项变成可观察验收。不能用“已遵循安全规范”或 lint 通过替代行为证据。
@@ -33,15 +33,17 @@
33
33
  | -------- | ------------------------------ |
34
34
  | UI | Svelte 5 (Runes);SvelteKit 或 Vite 以项目为准 |
35
35
  | 样式 | TailwindCSS 4 + DaisyUI 5 |
36
- | 语言 | TypeScript 5.7+ (strict) |
36
+ | 语言 | TypeScript 6 / 7 (strict) |
37
37
  | 构建 | Vite + tsup |
38
- | 包管理 | pnpm |
38
+ | 包管理 | pnpm 12 |
39
39
  | 单元测试 | Vitest |
40
40
  | E2E 测试 | Playwright |
41
41
  | 原生 App | Capacitor / Tauri / 小程序适配按当前项目选择 |
42
42
  | 公共 API | oRPC contract + Hono + typed client |
43
43
  | 认证 | Bearer access token + httpOnly refresh cookie(浏览器推荐) |
44
44
 
45
+ pnpm 专属配置放在 `pnpm-workspace.yaml`,`.npmrc` 仅用于注册表与认证。Docker 缓存层使用 `pnpm fetch` 读取锁文件;pnpm 12 的该命令不支持 `--frozen-lockfile`。后续仍通过 `pnpm install --offline --frozen-lockfile` 校验清单与锁文件一致。容器裁剪用 `pnpm pm deploy --filter <服务包> --prod <目标目录>`,确保执行内置命令,避免项目同名 `deploy` 脚本覆盖它。
46
+
45
47
  ### SvelteKit Adapter 模式
46
48
 
47
49
  仅在项目实际使用 SvelteKit 和 `@h-ai/kit/adapter` 时使用;Vite SPA 不配置 SvelteKit adapter,fullstack 各前端按自身 scripts 构建。
@@ -18,8 +18,10 @@ description: "使用 @h-ai/core 配置、日志、i18n、ID、Zod 错误本地
18
18
  ## 使用路径
19
19
 
20
20
  - Node 启动用 core.init({ configDir }) 加载配置;勿传 logging 覆盖 _core.yml 中的日志设置,除非任务明确要求。
21
+ - 应用名称、版本、环境、默认语言和日志设置统一从 `_core.yml` 经 core.config 获取,日志使用 core.logger;UI 不另维护硬编码副本。SvelteKit layout / fullstack app.info 仅下发公开字段白名单;独立 Vite mobile-app 在 Node 构建时解析并注入公开值,修改配置后重新构建。浏览器不加载 YAML,不接收完整模块配置、密钥或日志脱敏上下文。
21
22
  - HAI_<配置名>_<路径> 可整体覆盖根/对象/数组;父节点优先,未覆盖时才遍历已有叶子。camelCase 不拆词,约定变量优先于显式插值。
22
23
  - 配置 getter 与 ID/logger 方法不是 HaiResult;validate/load 等须检查 success。
24
+ - 初始化前创建的默认、模块与嵌套 child Logger 在后续输出中应用当前全局 logging;configure/setLevel 也作用于已有实例。create 的显式 level/format/context 优先,未指定项动态继承。浏览器 json/pretty 与附加 redact 路径实际生效,消息文本仍由调用方脱敏。
23
25
 
24
26
  ## 按需参考
25
27
 
@@ -140,6 +140,8 @@ feature:
140
140
 
141
141
  `core.logger` 既是默认 Logger 实例,也是日志管理的统一入口。
142
142
 
143
+ `core.init` 加载 `_core.yml.logging`、`configure` 和 `setLevel` 会改变已有默认、模块及嵌套 child Logger 的后续实际输出;不需要重新创建模块 Logger。`create` 显式指定的 level/format/context 保持优先,未指定选项动态继承全局配置;调用时 context 覆盖固定 context,附加 redact 规则统一生效。
144
+
143
145
  **日志记录**(实例方法):`trace` / `debug` / `info` / `warn` / `error` / `fatal`
144
146
 
145
147
  ```typescript
@@ -525,9 +527,9 @@ logger.debug('Data fetched', { count: items.length })
525
527
  | 功能 | 行为 |
526
528
  |------|------|
527
529
  | `core.config` 文件配置 | 不支持;文件相关方法返回 `SERVICE_UNAVAILABLE`,配置应由服务端读取后下发 |
528
- | `format: 'json' \| 'pretty'` | 被忽略(始终输出到 DevTools console) |
529
- | 自定义 `redact` 配置 | 浏览器不使用该配置,但默认 sanitizeSensitiveFields 仍会清理上下文敏感字段;消息文本需调用方脱敏 |
530
- | `fatal` 级别 | 映射为 `console.error`(带 `[FATAL]` 前缀) |
531
- | context 输出 | JSON 字符串追加到消息末尾(非结构化对象) |
530
+ | `format: 'json' \| 'pretty'` | 始终输出到 DevTools console;json 为包含 level/msg 的 JSON 字符串,pretty 为可读消息与上下文 |
531
+ | 自定义 `redact` 配置 | 与默认 sanitizeSensitiveFields 同时生效;支持嵌套点/括号路径与 `*`,不修改调用方对象;消息文本需调用方脱敏 |
532
+ | `fatal` 级别 | 映射为 console.error;pretty 带 `[FATAL]` 前缀,json 使用 `level: 'fatal'` |
533
+ | context 输出 | pretty 追加 JSON 上下文,json 合并上下文到结构化 JSON 字符串 |
532
534
 
533
535
  云资源输出格式与部署配置消费见 [hai-deploy](../hai-deploy/SKILL.md);这里的父节点覆盖规则同样适用。
@@ -57,8 +57,7 @@ description: "同步 hai-framework 通用 skills、AI 入口与应用依赖,
57
57
 
58
58
  - `AGENTS.md`
59
59
  - `.github/copilot-instructions.md`
60
- - `CLAUDE.md`(如存在)
61
- - `.claude/skills/<skill>/SKILL.md` 的原生发现入口;描述同步共享技能,正文和参考仍从 `.agents/skills/` 读取,保留已声明的本地覆盖
60
+ - `CLAUDE.md`(如存在,通过 `@AGENTS.md` 复用共享规则;不另复制 `.claude/skills/`,保留用户已有规则和技能)
62
61
  - `opencode.json`(如结构变化)
63
62
 
64
63
  新增/修改/修复任务入口必须能到达 `hai-app-create` 与其 `development.md`;审查入口能到达 `hai-app-review`。按目标架构/依赖交付所需模块技能,不把 SvelteKit 指令套到 API/Vite 项目。复制前比对应用私有覆盖,合并通用修正并保留差异,不能直接覆盖业务规则。
@@ -21,6 +21,7 @@ description: "使用 @h-ai/serv 装配 contract/procedures、认证守卫、Open
21
21
  - 认证绑定 route 的 auth/permission/role;启动配置错误与正常请求领域错误分别处理。
22
22
  - 普通 procedure 的失败 HaiResult 默认通过 HTTP 200 返回,必须检查 success 与 error.code;error.httpStatus 是领域错误元数据。contract 输入校验失败为 HTTP 400,HTTP middleware、刷新 cookie 等响应另按自身契约处理,不能混为同一种状态映射。
23
23
  - 浏览器 Cookie、CORS、apiPrefix、transport 须与 api-client 同步;语音 ticket 单独核验。
24
+ - 缺失路由返回本地化 HaiResult JSON 404;加密传输保留该状态。默认 feature 可按需选用,contract 与挂载的 procedures 保持一致。
24
25
 
25
26
  ## 按需参考
26
27
 
@@ -532,7 +532,7 @@ HTTP 审计、限流、CORS、租户头校验等跨 route 能力继续放在
532
532
  | oRPC contract 输入 schema 校验失败(handler 之前) | 400 | 本地化失败体,`error.httpStatus=400` 与字段错误 |
533
533
  | handler 内 `serv.validateInputOrFail(...)` 失败 | 200 | 失败 HaiResult,`error.httpStatus=400` 与字段错误 |
534
534
 
535
- HTTP middleware、自定义 Response、refresh-cookie、OpenAPI/RPC 入口权限和 transport 协议错误分别按自身响应契约处理,可返回真实 HTTP 4xx/5xx。`@h-ai/api-client` 的自动刷新只由真实 HTTP 401 触发,不会因 HTTP 200 失败包络中的 `error.httpStatus=401` 自动刷新。
535
+ HTTP middleware、自定义 Response、refresh-cookie、OpenAPI/RPC 入口权限和 transport 协议错误分别按自身响应契约处理,可返回真实 HTTP 4xx/5xx。`@h-ai/api-client` 在真实 HTTP 401 或 HTTP 200 的有效失败 HaiResult(`success=false`、字符串 `error.code/message`、`error.httpStatus=401`)后自动刷新,成功后只重试一次;内置登录、注册和配置的刷新路径除外,403/500 不刷新。启用 transport 时刷新和重试复用加密链路,不能手写明文刷新请求。
536
536
 
537
537
  SvelteKit 的 `kit.response.fromError` 根据 `error.httpStatus` 生成 HTTP Response;`kit.response.fromResult` 使用显式错误码映射,未命中默认 400。这些响应转换规则不能套用到 serv 普通 procedure。
538
538
 
@@ -612,6 +612,8 @@ http: {
612
612
 
613
613
  ## Feature Procedures(默认实现)
614
614
 
615
+ `serv.implement(...).context().route(...).build()` 同步返回普通 router,可直接按嵌套属性选取 `@h-ai/serv/features/iam` 等默认 procedures。挂载 contract 只包含实际选用的路由;不要为复用当前用户或刷新功能而同时开放注册、OTP 或通用管理入口。
616
+
615
617
  `@h-ai/serv` 内置了三个 feature 模块,开箱即用:
616
618
 
617
619
  | 导入路径 | 工厂函数 | 所需依赖 |
@@ -7,6 +7,8 @@ description: "使用 @h-ai/ui 构建 Svelte 5 表单、表格、弹窗、移动
7
7
 
8
8
  ## 能力契约
9
9
 
10
+ 主题 DOM 与安全缓存复用 `@h-ai/ui/theme` 的 `applyTheme` / `getSavedTheme(fallbackTheme?)`;默认主题取应用配置,选择范围与已编译 CSS 主题一致。
11
+
10
12
  | 项目 | 契约 |
11
13
  | --- | --- |
12
14
  | 能力 | 使用 @h-ai/ui 构建 Svelte 5 表单、表格、弹窗、移动界面、主题与 AI 内容展示 |
@@ -18,7 +20,11 @@ description: "使用 @h-ai/ui 构建 Svelte 5 表单、表格、弹窗、移动
18
20
  ## 使用路径
19
21
 
20
22
  - 先检查组件导入、Tailwind @source 和主题 CSS,再选场景 → 组合 → 原子组件,缺能力才自定义。
23
+ - 按安装版本的 exports 选择公开 components 目录入口;主题工具使用 `@h-ai/ui/theme`,避免仅为主题加载根入口的 AI/图表组件。禁止导入内部 src/dist;例如原子组件使用 `@h-ai/ui/components/primitives/index`。
24
+ - 自动导入识别无分号、跨行及别名的运行时 import;已绑定的本地组件名称不会重复注入。
21
25
  - 应用只提供页面级文案;组件内部中英文由 @h-ai/ui 维护。
26
+ - `UserProfile` 用 `avatarAccept` / `avatarHint` 对齐业务的头像格式与大小限制;文件最终校验和上传由业务回调完成。
27
+ - `BareInput type="file"` 通过 `onchange` 的 `currentTarget.files` 读取文件,不绑定文件路径 `value`;其他输入类型可 `bind:value`。
22
28
  - AI 文本视为不可信;Markdown/Mermaid 预览与允许执行 HTML/JS 的预览有不同边界。
23
29
 
24
30
  ## 按需参考
@@ -257,7 +257,7 @@ const p = usePlatform()
257
257
  | ------------ | ------------------------------------------------------------------ | ------------- |
258
258
  | `Form` | `loading`, `disabled`, `onsubmit` | 表单容器 |
259
259
  | `FormField` | `label`, `name`, `error`, `hint`, `required` | 表单字段 |
260
- | `Modal` | `open`, `title`, `size`, `closeOnBackdrop` | 模态框 |
260
+ | `Modal` | `open`, `title`, `size`, `closeOnBackdrop` | 模态框,内置对话框语义、焦点约束和关闭后焦点恢复 |
261
261
  | `Drawer` | `open`, `position`, `size`, `width`, `resizable`, `widthStorageKey` | 可选拖动并记忆宽度的抽屉 |
262
262
  | `DataTable` | `data`, `columns`, `keyField`, `sortKey`, `sortDir`, `onsort`, snippet slots | 数据表格(列定义 `sortable` 可排序) |
263
263
  | `Combobox` | `options`, `value`, `multiple`, `placeholder`, `error`, `onchange` | 可搜索选择 |
@@ -351,7 +351,7 @@ const p = usePlatform()
351
351
  | `AuthShell` | `variant`('card'/'split'), `title`, `brandTitle`, `brandText`, `illustration`, `description`, `highlights` | 认证页布局(包裹登录/注册表单) |
352
352
  | `LoginForm` | `showRememberMe`, `showRegisterLink`, `errors` | 登录表单 |
353
353
  | `RegisterForm` | `fields`, `minPasswordLength`, `errors` | 注册表单 |
354
- | `UserProfile` | `user`, `editable`, `fields`, `avatarUploadUrl` | 用户资料 |
354
+ | `UserProfile` | `user`, `editable`, `fields`, `avatarAccept`, `avatarHint` | 用户资料,选择器和提示对齐业务校验;最终验证和上传仍由回调负责 |
355
355
 
356
356
  #### 错误页 / 设置场景组件
357
357
 
@@ -532,10 +532,11 @@ form={{ variant: 'drawer', drawerWidth: '40rem' }}
532
532
  支持 15 个精选 DaisyUI 主题。
533
533
 
534
534
  ```typescript
535
- import { applyTheme, getCurrentTheme, isDarkTheme, THEMES, THEME_GROUPS } from '@h-ai/ui'
535
+ import { applyTheme, getCurrentTheme, getSavedTheme, isDarkTheme, THEMES, THEME_GROUPS } from '@h-ai/ui/theme'
536
536
 
537
537
  applyTheme('dark') // 应用主题(自动持久化 localStorage)
538
538
  getCurrentTheme() // 获取当前主题名
539
+ getSavedTheme('corporate') // 存储为空或不可用时使用应用默认主题
539
540
  isDarkTheme('dracula') // 检查是否暗色主题
540
541
  ```
541
542
 
@@ -583,8 +584,10 @@ typescript, javascript, python, java, go, rust, c, cpp, csharp, ruby, php, swift
583
584
  | 路径 | 用途 |
584
585
  | --------------------------- | -------------------------------------- |
585
586
  | `@h-ai/ui` | 主入口:所有组件、工具函数、类型 |
587
+ | `@h-ai/ui/theme` | 轻量主题元数据与工具,不经过组件根入口 |
586
588
  | `@h-ai/ui/auto-import` | Svelte 预处理器:组件自动导入 |
587
- | `@h-ai/ui/components/*` | 按路径引用单个组件 |
589
+ | `@h-ai/ui/components/*` | 公开组件目录的 JS 入口,按实际 exports/产物选择 |
590
+ | `@h-ai/ui/components/primitives/index` | 公开原子组件目录入口,如 Button/Input |
588
591
  | `@h-ai/ui/styles/global.css` | 全局基础样式(重置/滚动条/焦点) |
589
592
  | `@h-ai/ui/styles/theme.css` | Tailwind v4 `@theme` Token |
590
593
  | `@h-ai/ui/styles/design-tokens.css`| CSS 自定义属性(间距/圆角/z-index) |