@h-ai/cli 1.0.0-beta.18 → 1.0.0-beta.19

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 (194) hide show
  1. package/README.en.md +4 -0
  2. package/README.ja.md +4 -0
  3. package/README.md +4 -0
  4. package/dist/{chunk-6YZBC5MO.js → chunk-2ZL5ORQ2.js} +85 -25
  5. package/dist/chunk-2ZL5ORQ2.js.map +1 -0
  6. package/dist/{chunk-7NVRYYHN.js → chunk-L53P43B2.js} +129 -31
  7. package/dist/chunk-L53P43B2.js.map +1 -0
  8. package/dist/cli-config-templates-LWMD2I6V.js +5 -0
  9. package/dist/{cli-config-templates-QG5HOYR5.js.map → cli-config-templates-LWMD2I6V.js.map} +1 -1
  10. package/dist/{cli-skill-templates-W4I6ZKYW.js → cli-skill-templates-D6S2OQ6X.js} +3 -3
  11. package/dist/{cli-skill-templates-W4I6ZKYW.js.map → cli-skill-templates-D6S2OQ6X.js.map} +1 -1
  12. package/dist/index.d.ts +1 -1
  13. package/dist/index.js +2747 -671
  14. package/dist/index.js.map +1 -1
  15. package/dist/metafile-esm.json +1 -1
  16. package/package.json +22 -22
  17. package/templates/apps/admin/src/routes/+layout.svelte.hbs +16 -10
  18. package/templates/apps/admin/src/routes/+page.svelte.hbs +4 -4
  19. package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +17 -7
  20. package/templates/apps/admin/src/routes/admin/+page.svelte.hbs +26 -6
  21. package/templates/apps/admin/src/routes/admin/settings/+page.svelte.hbs +2 -2
  22. package/templates/apps/api/apps/{{projectName}}-contract/src/app-schemas.ts.hbs +6 -1
  23. package/templates/apps/api/apps/{{projectName}}-contract/src/{{projectName}}-contract.ts.hbs +13 -5
  24. package/templates/apps/api/apps/{{projectName}}-contract/tests/contract.test.ts.hbs +13 -5
  25. package/templates/apps/api/apps/{{projectName}}-contract/tsup.config.ts.hbs +3 -1
  26. package/templates/apps/api/apps/{{projectName}}-serv/src/app.ts.hbs +71 -32
  27. package/templates/apps/api/apps/{{projectName}}-serv/src/build-metadata.ts.hbs +0 -1
  28. package/templates/apps/api/apps/{{projectName}}-serv/src/lib/server/init.ts.hbs +131 -54
  29. package/templates/apps/api/apps/{{projectName}}-serv/src/server/procedures/index.ts.hbs +39 -13
  30. package/templates/apps/api/apps/{{projectName}}-serv/tests/service.test.ts.hbs +78 -31
  31. package/templates/apps/api/apps/{{projectName}}-serv/tsup.config.ts.hbs +3 -1
  32. package/templates/apps/api/apps/{{projectName}}-serv/vitest.config.ts.hbs +3 -1
  33. package/templates/apps/api/e2e/api-serv.spec.ts.hbs +20 -3
  34. package/templates/apps/api/e2e/capture-evidence.ts.hbs +4 -1
  35. package/templates/apps/api/eslint.config.js.hbs +3 -1
  36. package/templates/apps/api/images/serv.Dockerfile.hbs +3 -4
  37. package/templates/apps/api/playwright.config.ts.hbs +23 -19
  38. package/templates/apps/api/pnpm-workspace.yaml.hbs +27 -16
  39. package/templates/apps/fullstack/apps/{{projectName}}-app/capacitor.config.ts.hbs +1 -3
  40. package/templates/apps/fullstack/apps/{{projectName}}-app/eslint.config.js.hbs +10 -2
  41. package/templates/apps/fullstack/apps/{{projectName}}-app/src/App.svelte.hbs +10 -2
  42. package/templates/apps/fullstack/apps/{{projectName}}-app/src/build-metadata.ts.hbs +0 -1
  43. package/templates/apps/fullstack/apps/{{projectName}}-app/src/lib/capacitor.ts.hbs +0 -1
  44. package/templates/apps/fullstack/apps/{{projectName}}-app/svelte.config.js.hbs +4 -1
  45. package/templates/apps/fullstack/apps/{{projectName}}-app/vite.config.ts.hbs +16 -4
  46. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/App.svelte.hbs +8 -2
  47. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/build-metadata.ts.hbs +0 -1
  48. package/templates/apps/fullstack/apps/{{projectName}}-desktop/svelte.config.js.hbs +4 -1
  49. package/templates/apps/fullstack/apps/{{projectName}}-desktop/vite.config.ts.hbs +16 -4
  50. package/templates/apps/fullstack/apps/{{projectName}}-web/eslint.config.js.hbs +10 -2
  51. package/templates/apps/fullstack/apps/{{projectName}}-web/src/build-metadata.ts.hbs +0 -1
  52. package/templates/apps/fullstack/apps/{{projectName}}-web/src/main.ts.hbs +0 -2
  53. package/templates/apps/fullstack/apps/{{projectName}}-web/svelte.config.js.hbs +4 -1
  54. package/templates/apps/fullstack/apps/{{projectName}}-web/vite.config.ts.hbs +19 -5
  55. package/templates/apps/fullstack/e2e/fullstack.spec.ts.hbs +111 -26
  56. package/templates/apps/fullstack/e2e/session-close.spec.ts.hbs +19 -5
  57. package/templates/apps/fullstack/eslint.config.js.hbs +3 -1
  58. package/templates/apps/fullstack/images/serv.Dockerfile.hbs +3 -4
  59. package/templates/apps/fullstack/images/web.Dockerfile.hbs +0 -2
  60. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/admin-contract.ts.hbs +114 -23
  61. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/admin-schemas.ts.hbs +57 -11
  62. package/templates/apps/fullstack/packages/{{projectName}}-contract/tsup.config.ts.hbs +3 -1
  63. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/app-server.ts.hbs +65 -30
  64. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/build-metadata.ts.hbs +0 -1
  65. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/admin-service.ts.hbs +69 -21
  66. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/business-settings.ts.hbs +21 -5
  67. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/admin-procedures.ts.hbs +63 -11
  68. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/app-procedures.ts.hbs +6 -1
  69. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/index.ts.hbs +3 -1
  70. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/runtime.ts.hbs +139 -49
  71. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/security-roles.ts.hbs +43 -12
  72. package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/app-server.test.ts.hbs +139 -28
  73. package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/runtime.test.ts.hbs +33 -10
  74. package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/security.test.ts.hbs +141 -25
  75. package/templates/apps/fullstack/packages/{{projectName}}-serv/tsup.config.ts.hbs +6 -2
  76. package/templates/apps/fullstack/packages/{{projectName}}-serv/vitest.config.ts.hbs +3 -1
  77. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/api-client.ts.hbs +9 -2
  78. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/feedback-client.ts.hbs +0 -3
  79. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/sensitive-actions.svelte.ts.hbs +15 -3
  80. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AppShell.svelte.hbs +33 -7
  81. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/FeedbackEntry.svelte.hbs +16 -2
  82. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/audit.svelte.hbs +104 -13
  83. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/feedback.svelte.hbs +37 -7
  84. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/roles.svelte.hbs +9 -3
  85. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/settings.svelte.hbs +25 -3
  86. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/users.svelte.hbs +133 -19
  87. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/security/role-label.ts.hbs +14 -2
  88. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/guide-store.ts.hbs +66 -34
  89. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/management-store.svelte.ts.hbs +132 -30
  90. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/theme-store.svelte.ts.hbs +8 -2
  91. package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/api-client.test.ts.hbs +23 -5
  92. package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/management-store.test.ts.hbs +143 -21
  93. package/templates/apps/fullstack/packages/{{projectName}}-shared/vitest.config.ts.hbs +7 -2
  94. package/templates/apps/fullstack/playwright.config.ts.hbs +9 -3
  95. package/templates/apps/fullstack/pnpm-workspace.yaml.hbs +30 -15
  96. package/templates/apps/h5/src/routes/+layout.svelte.hbs +57 -21
  97. package/templates/apps/h5/src/routes/+page.svelte.hbs +2 -2
  98. package/templates/apps/h5/src/routes/discover/+page.svelte.hbs +2 -2
  99. package/templates/apps/h5/src/routes/profile/+page.svelte.hbs +2 -2
  100. package/templates/apps/mobile-app/src/App.svelte.hbs +17 -5
  101. package/templates/apps/mobile-app/src/lib/api.ts.hbs +14 -3
  102. package/templates/apps/mobile-app/src/lib/app-config.ts.hbs +8 -1
  103. package/templates/apps/mobile-app/src/lib/pages/home.svelte.hbs +6 -2
  104. package/templates/apps/mobile-app/src/lib/pages/tasks.svelte.hbs +5 -1
  105. package/templates/apps/website/scripts/static-website.mjs.hbs +16 -3
  106. package/templates/apps/website/src/routes/+layout.svelte.hbs +44 -23
  107. package/templates/apps/website/src/routes/+page.svelte.hbs +4 -4
  108. package/templates/apps/website/src/routes/about/+page.svelte.hbs +2 -2
  109. package/templates/apps/website/src/routes/contact/+page.svelte.hbs +2 -2
  110. package/templates/apps/website/src/routes/services/+page.svelte.hbs +20 -5
  111. package/templates/base/e2e/app.spec.ts.hbs +49 -16
  112. package/templates/base/eslint-rules.js +44 -25
  113. package/templates/base/eslint.config.js.hbs +3 -1
  114. package/templates/base/images/web.Dockerfile.hbs +3 -4
  115. package/templates/base/package.json.hbs +5 -4
  116. package/templates/base/patches/daisyui-5.7.50.patch +8 -0
  117. package/templates/base/patches/deepmerge-4.3.1.patch +51 -0
  118. package/templates/base/playwright.config.ts +3 -1
  119. package/templates/base/pnpm-workspace.yaml.hbs +33 -16
  120. package/templates/base/src/app.d.ts.hbs +1 -1
  121. package/templates/base/src/hooks.server.ts.hbs +36 -27
  122. package/templates/base/src/lib/build-metadata.ts.hbs +0 -1
  123. package/templates/base/src/lib/server/init.ts.hbs +124 -51
  124. package/templates/base/src/lib/server/kit-config.ts.hbs +7 -4
  125. package/templates/base/src/routes/+layout.server.ts.hbs +2 -2
  126. package/templates/base/svelte.config.js.hbs +10 -100
  127. package/templates/base/tests/scaffold.test.ts.hbs +12 -3
  128. package/templates/base/tsconfig.json.hbs +7 -4
  129. package/templates/base/vite.config.ts.hbs +108 -14
  130. package/templates/base/vitest.config.ts.hbs +6 -2
  131. package/templates/features/ai/routes/api/chat/+server.ts +3 -1
  132. package/templates/features/iam/routes-admin/(auth)/auth/forgot-password/+page.svelte.hbs +3 -3
  133. package/templates/features/iam/routes-admin/(auth)/auth/login/+page.svelte.hbs +3 -3
  134. package/templates/features/iam/routes-admin/(auth)/auth/register/+page.svelte.hbs +3 -3
  135. package/templates/features/iam/routes-admin/(auth)/auth/reset-password/+page.svelte.hbs +3 -3
  136. package/templates/features/iam/routes-h5/auth/forgot-password/+page.svelte.hbs +3 -3
  137. package/templates/features/iam/routes-h5/auth/login/+page.svelte.hbs +3 -3
  138. package/templates/features/iam/routes-h5/auth/register/+page.svelte.hbs +3 -3
  139. package/templates/features/iam/routes-h5/auth/reset-password/+page.svelte.hbs +3 -3
  140. package/templates/features/iam/routes-website/auth/forgot-password/+page.svelte.hbs +3 -3
  141. package/templates/features/iam/routes-website/auth/login/+page.svelte.hbs +3 -3
  142. package/templates/features/iam/routes-website/auth/register/+page.svelte.hbs +3 -3
  143. package/templates/features/iam/routes-website/auth/reset-password/+page.svelte.hbs +3 -3
  144. package/templates/features/payment/routes/api/v1/payment/create/+server.ts +11 -2
  145. package/templates/shared/browser-check/startup.js +32 -6
  146. package/templates/shared/browser-startup.spec.ts +3 -1
  147. package/templates/shared/build-metadata.ts +18 -4
  148. package/templates/shared/e2e-env.ts +22 -6
  149. package/templates/shared/native-name.mjs +9 -2
  150. package/templates/shared/public-base-path.mjs +17 -4
  151. package/templates/shared/run-e2e.mjs +40 -9
  152. package/templates/shared/run-node.mjs +15 -4
  153. package/templates/shared/run-tauri.mjs +37 -8
  154. package/templates/shared/vite-runtime-config.ts +9 -3
  155. package/templates/skills/AGENTS.md +10 -73
  156. package/templates/skills/bridges/admin/AGENTS.md +9 -65
  157. package/templates/skills/bridges/api/AGENTS.md +8 -59
  158. package/templates/skills/bridges/fullstack/AGENTS.md.hbs +9 -54
  159. package/templates/skills/bridges/h5/AGENTS.md +8 -63
  160. package/templates/skills/bridges/mobile-app/AGENTS.md +8 -62
  161. package/templates/skills/bridges/website/AGENTS.md +8 -63
  162. package/templates/skills/hai-ai/acp.md +2 -0
  163. package/templates/skills/hai-ai/guide.md +17 -6
  164. package/templates/skills/hai-ai/reference.md +21 -12
  165. package/templates/skills/hai-api-client/reference.md +1 -1
  166. package/templates/skills/hai-app-create/development.md +3 -1
  167. package/templates/skills/hai-app-create/project.md +33 -0
  168. package/templates/skills/hai-app-create/reference.md +8 -8
  169. package/templates/skills/hai-app-tests/reference.md +1 -1
  170. package/templates/skills/hai-build/SKILL.md +2 -2
  171. package/templates/skills/hai-build/paths.md +1 -1
  172. package/templates/skills/hai-build/reference.md +11 -7
  173. package/templates/skills/hai-capacitor/reference.md +2 -0
  174. package/templates/skills/hai-ci/SKILL.md +1 -0
  175. package/templates/skills/hai-core/reference.md +3 -0
  176. package/templates/skills/hai-crypto/reference.md +2 -0
  177. package/templates/skills/hai-deploy/SKILL.md +7 -1
  178. package/templates/skills/hai-deploy/middleware.md +3 -1
  179. package/templates/skills/hai-framework-sync/sync.md +2 -0
  180. package/templates/skills/hai-kit/reference.md +16 -4
  181. package/templates/skills/hai-payment/reference.md +2 -0
  182. package/templates/skills/hai-reach/SKILL.md +2 -1
  183. package/templates/skills/hai-reach/reference.md +1 -1
  184. package/templates/skills/hai-reldb/SKILL.md +1 -1
  185. package/templates/skills/hai-reldb/reference.md +4 -0
  186. package/templates/skills/hai-serv/reference.md +12 -2
  187. package/templates/skills/hai-storage/reference.md +12 -3
  188. package/templates/skills/hai-ui/SKILL.md +3 -2
  189. package/templates/skills/hai-ui/guide.md +1 -1
  190. package/templates/skills/hai-ui/reference.md +23 -35
  191. package/templates/skills/hai-vecdb/reference.md +1 -1
  192. package/dist/chunk-6YZBC5MO.js.map +0 -1
  193. package/dist/chunk-7NVRYYHN.js.map +0 -1
  194. package/dist/cli-config-templates-QG5HOYR5.js +0 -5
@@ -7,9 +7,13 @@ import { resolveBuildMetadata } from './scripts/build-metadata.js'
7
7
 
8
8
  export default defineConfig({
9
9
  {{#unless isSvelteOnlyApp}}
10
- plugins: [sveltekit()],
10
+ plugins: [
11
+ sveltekit(),
12
+ ],
11
13
  {{/unless}}
12
- define: { __HAI_BUILD_METADATA__: JSON.stringify(resolveBuildMetadata(fileURLToPath(new URL('.', import.meta.url)))) },
14
+ define: {
15
+ __HAI_BUILD_METADATA__: JSON.stringify(resolveBuildMetadata(fileURLToPath(new URL('.', import.meta.url)))),
16
+ },
13
17
  test: {
14
18
  globals: true,
15
19
  environment: 'node',
@@ -6,7 +6,9 @@ import { ai } from '@h-ai/ai'
6
6
  import { kit } from '@h-ai/kit'
7
7
  import { z } from 'zod'
8
8
 
9
- const ChatInputSchema = z.object({ message: z.string().trim().min(1).max(4000) }).strict()
9
+ const ChatInputSchema = z.object({
10
+ message: z.string().trim().min(1).max(4000),
11
+ }).strict()
10
12
 
11
13
  export const POST: RequestHandler = kit.handler(async ({ request, locals }) => {
12
14
  const { message } = await kit.validate.body(request, ChatInputSchema)
@@ -1,10 +1,10 @@
1
1
  <script lang='ts'>
2
- import { base, resolve } from '$app/paths'
2
+ import { resolve } from '$app/paths'
3
3
  import { page } from '$app/state'
4
4
  import { kit } from '@h-ai/kit'
5
5
  import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
6
6
 
7
- const actions = kit.client.createAuthActions({ basePath: `${base}/api/auth` })
7
+ const actions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
8
8
  </script>
9
9
 
10
- <AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='forgot' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('/auth/login', {})} />
10
+ <AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='forgot' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('auth/login')} />
@@ -1,11 +1,11 @@
1
1
  <script lang='ts'>
2
2
  import { goto } from '$app/navigation'
3
- import { base, resolve } from '$app/paths'
3
+ import { resolve } from '$app/paths'
4
4
  import { page } from '$app/state'
5
5
  import { kit } from '@h-ai/kit'
6
6
  import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
7
7
 
8
- const actions = kit.client.createAuthActions({ basePath: `${base}/api/auth` })
8
+ const actions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
9
9
  </script>
10
10
 
11
- <AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='login' loginUrl={resolve('/auth/login', {})} registerUrl={resolve('/auth/register', {})} onauthenticated={() => goto(resolve('/admin', {}))} />
11
+ <AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='login' loginUrl={resolve('auth/login')} registerUrl={resolve('auth/register')} onauthenticated={() => goto(resolve('admin'))} />
@@ -1,11 +1,11 @@
1
1
  <script lang='ts'>
2
2
  import { goto } from '$app/navigation'
3
- import { base, resolve } from '$app/paths'
3
+ import { resolve } from '$app/paths'
4
4
  import { page } from '$app/state'
5
5
  import { kit } from '@h-ai/kit'
6
6
  import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
7
7
 
8
- const actions = kit.client.createAuthActions({ basePath: `${base}/api/auth` })
8
+ const actions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
9
9
  </script>
10
10
 
11
- <AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='register' loginUrl={resolve('/auth/login', {})} registerUrl={resolve('/auth/register', {})} onauthenticated={() => goto(resolve('/admin', {}))} />
11
+ <AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='register' loginUrl={resolve('auth/login')} registerUrl={resolve('auth/register')} onauthenticated={() => goto(resolve('admin'))} />
@@ -1,10 +1,10 @@
1
1
  <script lang='ts'>
2
- import { base, resolve } from '$app/paths'
2
+ import { resolve } from '$app/paths'
3
3
  import { page } from '$app/state'
4
4
  import { kit } from '@h-ai/kit'
5
5
  import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
6
6
 
7
- const actions = kit.client.createAuthActions({ basePath: `${base}/api/auth` })
7
+ const actions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
8
8
  </script>
9
9
 
10
- <AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='reset' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('/auth/login', {})} />
10
+ <AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='reset' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('auth/login')} />
@@ -1,10 +1,10 @@
1
1
  <script lang='ts'>
2
- import { base, resolve } from '$app/paths'
2
+ import { resolve } from '$app/paths'
3
3
  import { page } from '$app/state'
4
4
  import { kit } from '@h-ai/kit'
5
5
  import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
6
6
 
7
- const actions = kit.client.createAuthActions({ basePath: `${base}/api/auth` })
7
+ const actions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
8
8
  </script>
9
9
 
10
- <AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='forgot' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('/auth/login', {})} />
10
+ <AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='forgot' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('auth/login')} />
@@ -1,11 +1,11 @@
1
1
  <script lang='ts'>
2
2
  import { goto } from '$app/navigation'
3
- import { base, resolve } from '$app/paths'
3
+ import { resolve } from '$app/paths'
4
4
  import { page } from '$app/state'
5
5
  import { kit } from '@h-ai/kit'
6
6
  import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
7
7
 
8
- const authActions = kit.client.createAuthActions({ basePath: `${base}/api/auth` })
8
+ const authActions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
9
9
  </script>
10
10
 
11
- <AuthPanel config={page.data.iamPublicConfig} actions={authActions} initialMode='login' loginUrl={resolve('/auth/login', {})} registerUrl={resolve('/auth/register', {})} onauthenticated={() => goto(resolve('/', {}))} />
11
+ <AuthPanel config={page.data.iamPublicConfig} actions={authActions} initialMode='login' loginUrl={resolve('auth/login')} registerUrl={resolve('auth/register')} onauthenticated={() => goto(resolve('/'))} />
@@ -1,11 +1,11 @@
1
1
  <script lang='ts'>
2
2
  import { goto } from '$app/navigation'
3
- import { base, resolve } from '$app/paths'
3
+ import { resolve } from '$app/paths'
4
4
  import { page } from '$app/state'
5
5
  import { kit } from '@h-ai/kit'
6
6
  import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
7
7
 
8
- const authActions = kit.client.createAuthActions({ basePath: `${base}/api/auth` })
8
+ const authActions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
9
9
  </script>
10
10
 
11
- <AuthPanel config={page.data.iamPublicConfig} actions={authActions} initialMode='register' loginUrl={resolve('/auth/login', {})} registerUrl={resolve('/auth/register', {})} onauthenticated={() => goto(resolve('/', {}))} />
11
+ <AuthPanel config={page.data.iamPublicConfig} actions={authActions} initialMode='register' loginUrl={resolve('auth/login')} registerUrl={resolve('auth/register')} onauthenticated={() => goto(resolve('/'))} />
@@ -1,10 +1,10 @@
1
1
  <script lang='ts'>
2
- import { base, resolve } from '$app/paths'
2
+ import { resolve } from '$app/paths'
3
3
  import { page } from '$app/state'
4
4
  import { kit } from '@h-ai/kit'
5
5
  import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
6
6
 
7
- const actions = kit.client.createAuthActions({ basePath: `${base}/api/auth` })
7
+ const actions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
8
8
  </script>
9
9
 
10
- <AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='reset' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('/auth/login', {})} />
10
+ <AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='reset' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('auth/login')} />
@@ -1,10 +1,10 @@
1
1
  <script lang='ts'>
2
- import { base, resolve } from '$app/paths'
2
+ import { resolve } from '$app/paths'
3
3
  import { page } from '$app/state'
4
4
  import { kit } from '@h-ai/kit'
5
5
  import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
6
6
 
7
- const actions = kit.client.createAuthActions({ basePath: `${base}/api/auth` })
7
+ const actions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
8
8
  </script>
9
9
 
10
- <AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='forgot' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('/auth/login', {})} />
10
+ <AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='forgot' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('auth/login')} />
@@ -1,11 +1,11 @@
1
1
  <script lang='ts'>
2
2
  import { goto } from '$app/navigation'
3
- import { base, resolve } from '$app/paths'
3
+ import { resolve } from '$app/paths'
4
4
  import { page } from '$app/state'
5
5
  import { kit } from '@h-ai/kit'
6
6
  import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
7
7
 
8
- const authActions = kit.client.createAuthActions({ basePath: `${base}/api/auth` })
8
+ const authActions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
9
9
  </script>
10
10
 
11
- <AuthPanel config={page.data.iamPublicConfig} actions={authActions} initialMode='login' loginUrl={resolve('/auth/login', {})} registerUrl={resolve('/auth/register', {})} onauthenticated={() => goto(resolve('/', {}))} />
11
+ <AuthPanel config={page.data.iamPublicConfig} actions={authActions} initialMode='login' loginUrl={resolve('auth/login')} registerUrl={resolve('auth/register')} onauthenticated={() => goto(resolve('/'))} />
@@ -1,11 +1,11 @@
1
1
  <script lang='ts'>
2
2
  import { goto } from '$app/navigation'
3
- import { base, resolve } from '$app/paths'
3
+ import { resolve } from '$app/paths'
4
4
  import { page } from '$app/state'
5
5
  import { kit } from '@h-ai/kit'
6
6
  import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
7
7
 
8
- const authActions = kit.client.createAuthActions({ basePath: `${base}/api/auth` })
8
+ const authActions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
9
9
  </script>
10
10
 
11
- <AuthPanel config={page.data.iamPublicConfig} actions={authActions} initialMode='register' loginUrl={resolve('/auth/login', {})} registerUrl={resolve('/auth/register', {})} onauthenticated={() => goto(resolve('/', {}))} />
11
+ <AuthPanel config={page.data.iamPublicConfig} actions={authActions} initialMode='register' loginUrl={resolve('auth/login')} registerUrl={resolve('auth/register')} onauthenticated={() => goto(resolve('/'))} />
@@ -1,10 +1,10 @@
1
1
  <script lang='ts'>
2
- import { base, resolve } from '$app/paths'
2
+ import { resolve } from '$app/paths'
3
3
  import { page } from '$app/state'
4
4
  import { kit } from '@h-ai/kit'
5
5
  import { AuthPanel } from '@h-ai/ui/components/scenes/iam/index'
6
6
 
7
- const actions = kit.client.createAuthActions({ basePath: `${base}/api/auth` })
7
+ const actions = kit.client.createAuthActions({ basePath: `${resolve('/').replace(/\/$/, '')}/api/auth` })
8
8
  </script>
9
9
 
10
- <AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='reset' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('/auth/login', {})} />
10
+ <AuthPanel config={page.data.iamPublicConfig} {actions} initialMode='reset' resetToken={page.url.searchParams.get('token') ?? ''} loginUrl={resolve('auth/login')} />
@@ -1,10 +1,13 @@
1
1
  /** 创建支付参数 API;渠道、场景与 openid 必须通过显式校验,禁止回落到其它支付模式。 */
2
2
  import type { RequestHandler } from './$types'
3
- import { base } from '$app/paths'
3
+ import { resolve } from '$app/paths'
4
4
  import { kit } from '@h-ai/kit'
5
5
  import { payment } from '@h-ai/payment'
6
6
  import { z } from 'zod'
7
7
 
8
+ // Vite 配置固定 paths.relative=false,HTTP 前缀不会随 SSR 页面深度改变。
9
+ const base = resolve('/').replace(/\/$/, '')
10
+
8
11
  /** 本模板的业务字段;服务端仍需从可信订单重新核对金额、描述、订单号和所属用户。 */
9
12
  const CreatePaymentSchema = z.object({
10
13
  provider: z.enum(['wechat', 'alipay', 'stripe']),
@@ -15,7 +18,13 @@ const CreatePaymentSchema = z.object({
15
18
  userId: z.string().trim().min(1).max(128).optional(),
16
19
  metadata: z.record(z.string(), z.string()).optional(),
17
20
  notifyUrl: z.url({ protocol: /^https?$/ }).optional(),
18
- }).strict().refine(input => input.tradeType === (input.provider === 'wechat' ? 'jsapi' : 'h5'), { path: ['tradeType'] }).refine(input => input.provider !== 'wechat' || input.userId !== undefined, { path: ['userId'] })
21
+ }).strict().refine(input => input.tradeType === (input.provider === 'wechat'
22
+ ? 'jsapi'
23
+ : 'h5'), {
24
+ path: ['tradeType'],
25
+ }).refine(input => input.provider !== 'wechat' || input.userId !== undefined, {
26
+ path: ['userId'],
27
+ })
19
28
 
20
29
  export const POST: RequestHandler = async ({ request, locals }) => {
21
30
  const { provider, tradeType, outTradeNo, totalAmount, subject, notifyUrl, userId, metadata } = await kit.validate.body(request, CreatePaymentSchema)
@@ -44,12 +44,21 @@
44
44
  var currentMinor = Number(parts[1] || 0)
45
45
  if (currentMajor > major || (currentMajor === major && currentMinor >= minor))
46
46
  return null
47
- return { name: name, version: version, minimum: minor ? major + '.' + minor : String(major), help: help }
47
+ return {
48
+ name: name,
49
+ version: version,
50
+ minimum: minor
51
+ ? major + '.' + minor
52
+ : String(major),
53
+ help: help,
54
+ }
48
55
  }
49
56
 
50
57
  function getLanguage(value) {
51
58
  var language = (value || '').toLowerCase().split(/[-_]/)[0]
52
- return language === 'zh' || language === 'ja' || language === 'en' ? language : ''
59
+ return language === 'zh' || language === 'ja' || language === 'en'
60
+ ? language
61
+ : ''
53
62
  }
54
63
 
55
64
  function openUpdatePage() {
@@ -62,13 +71,30 @@
62
71
  function showUpdateInstructions() {
63
72
  var locale = getLanguage(location.hash.slice(1)) || getLanguage(navigator.language) || 'en'
64
73
  var messages = {
65
- zh: ['浏览器版本过低', '当前使用 {name} {version}。此站点至少需要 {name} {minimum}。', '请更新到最新版本,然后重新打开此站点。', '查看官方更新说明'],
66
- en: ['Update your browser', 'You are using {name} {version}. This site requires {name} {minimum} or later.', 'Install the latest update, then reopen this site.', 'Official update instructions'],
67
- ja: ['ブラウザーを更新してください', '現在のバージョンは {name} {version} です。このサイトには {name} {minimum} 以降が必要です。', '最新版に更新してから、このサイトを開き直してください。', '公式の更新手順を見る'],
74
+ zh: [
75
+ '浏览器版本过低',
76
+ '当前使用 {name} {version}。此站点至少需要 {name} {minimum}。',
77
+ '请更新到最新版本,然后重新打开此站点。',
78
+ '查看官方更新说明',
79
+ ],
80
+ en: [
81
+ 'Update your browser',
82
+ 'You are using {name} {version}. This site requires {name} {minimum} or later.',
83
+ 'Install the latest update, then reopen this site.',
84
+ 'Official update instructions',
85
+ ],
86
+ ja: [
87
+ 'ブラウザーを更新してください',
88
+ '現在のバージョンは {name} {version} です。このサイトには {name} {minimum} 以降が必要です。',
89
+ '最新版に更新してから、このサイトを開き直してください。',
90
+ '公式の更新手順を見る',
91
+ ],
68
92
  }
69
93
  var message = messages[locale]
70
94
  var help = document.getElementById('browser-update-help')
71
- root.lang = locale === 'zh' ? 'zh-CN' : locale
95
+ root.lang = locale === 'zh'
96
+ ? 'zh-CN'
97
+ : locale
72
98
  document.title = message[0]
73
99
  document.getElementById('browser-update-title').textContent = message[0]
74
100
  document.getElementById('browser-update-version').textContent = message[1].replace(/\{(name|version|minimum)\}/g, function (_match, key) {
@@ -3,7 +3,9 @@ import { expect, test } from '@playwright/test'
3
3
  test('old browser sees upgrade instructions without the application bundles', async ({ page }) => {
4
4
  // 只改变浏览器脚本看到的版本,确保检测在客户端执行。
5
5
  await page.addInitScript(() => {
6
- Object.defineProperty(navigator, 'userAgent', { get: () => 'Mozilla/5.0 Gecko/20100101 Firefox/113.0' })
6
+ Object.defineProperty(navigator, 'userAgent', {
7
+ get: () => 'Mozilla/5.0 Gecko/20100101 Firefox/113.0',
8
+ })
7
9
  })
8
10
  await page.route('**/*', async (route) => {
9
11
  const { pathname } = new URL(route.request().url())
@@ -7,7 +7,9 @@ import process from 'node:process'
7
7
  /** 当前编译目标的私有产物身份;同一 SSR 构建重入复用身份,各端版本来自自己的 manifest。 */
8
8
  export function resolveBuildMetadata(directory: string): { appVersion: string, buildId: string, commit: string } {
9
9
  const manifest: { version?: unknown } = JSON.parse(readFileSync(join(directory, 'package.json'), 'utf8'))
10
- const appVersion = typeof manifest.version === 'string' && manifest.version.trim() ? manifest.version.trim() : 'unknown'
10
+ const appVersion = typeof manifest.version === 'string' && manifest.version.trim()
11
+ ? manifest.version.trim()
12
+ : 'unknown'
11
13
  if (appVersion.length > 128)
12
14
  throw new Error('Invalid package.json version: maximum length is 128')
13
15
  const suppliedId = process.env.HAI_BUILD_ID?.trim()
@@ -27,14 +29,26 @@ export function resolveBuildMetadata(directory: string): { appVersion: string, b
27
29
  /** 未跟踪的生成工程不能把临时目录的父框架提交冒充自身源码。 */
28
30
  function sourceCommit(directory: string): string {
29
31
  try {
30
- const options = { cwd: directory, encoding: 'utf8' as const, stdio: 'pipe' as const, windowsHide: true }
32
+ const options = {
33
+ cwd: directory,
34
+ encoding: 'utf8' as const,
35
+ stdio: 'pipe' as const,
36
+ windowsHide: true,
37
+ }
31
38
  const root = execFileSync('git', ['rev-parse', '--show-toplevel'], options).trim()
32
39
  const manifest = relative(root, join(directory, 'package.json')).replaceAll('\\', '/')
33
40
  if (manifest.startsWith('../'))
34
41
  return 'unknown'
35
- execFileSync('git', ['ls-files', '--error-unmatch', '--', manifest], { ...options, cwd: root })
42
+ execFileSync('git', [
43
+ 'ls-files',
44
+ '--error-unmatch',
45
+ '--',
46
+ manifest,
47
+ ], { ...options, cwd: root })
36
48
  const commit = execFileSync('git', ['rev-parse', 'HEAD'], options).trim()
37
- return /^(?:[a-f\d]{40}|[a-f\d]{64})$/i.test(commit) ? commit : 'unknown'
49
+ return /^(?:[a-f\d]{40}|[a-f\d]{64})$/i.test(commit)
50
+ ? commit
51
+ : 'unknown'
38
52
  }
39
53
  catch {
40
54
  return 'unknown'
@@ -29,7 +29,12 @@ export function createE2eServerEnv(profile: Record<string, string>): Record<stri
29
29
  const environment: Record<string, string | undefined> = Object.fromEntries(
30
30
  Object.keys(process.env).filter(key => /^(?:HAI_|PUBLIC_|VITE_)/i.test(key)).map(key => [key, undefined]),
31
31
  )
32
- for (const name of ['HAI_E2E_DATA_ROOT', 'HAI_AUTH_EVIDENCE_DIR', 'HAI_CORE_NAME', 'HAI_CORE_VERSION']) {
32
+ for (const name of [
33
+ 'HAI_E2E_DATA_ROOT',
34
+ 'HAI_AUTH_EVIDENCE_DIR',
35
+ 'HAI_CORE_NAME',
36
+ 'HAI_CORE_VERSION',
37
+ ]) {
33
38
  if (process.env[name] !== undefined)
34
39
  environment[name] = process.env[name]
35
40
  }
@@ -56,10 +61,15 @@ export function createE2eServerEnv(profile: Record<string, string>): Record<stri
56
61
  export function createE2eTransportRing(): string {
57
62
  const key = createECDH('SM2')
58
63
  key.generateKeys()
59
- return JSON.stringify({ activeKeyId: 'e2e-v1', keys: { 'e2e-v1': {
60
- publicKey: key.getPublicKey('hex'),
61
- privateKey: key.getPrivateKey('hex').padStart(64, '0'),
62
- } } })
64
+ return JSON.stringify({
65
+ activeKeyId: 'e2e-v1',
66
+ keys: {
67
+ 'e2e-v1': {
68
+ publicKey: key.getPublicKey('hex'),
69
+ privateKey: key.getPrivateKey('hex').padStart(64, '0'),
70
+ },
71
+ },
72
+ })
63
73
  }
64
74
 
65
75
  /**
@@ -93,6 +103,12 @@ export function createE2eNotificationEnv(): Record<string, string> {
93
103
  { name: 'password_reset', provider: 'email', body: 'Reset: {token}' },
94
104
  { name: 'password_reset_sms', provider: 'sms', body: 'Reset: {token}' },
95
105
  ]),
96
- HAI_IAM_AGREEMENTS: JSON.stringify({ showOnRegister: true, showOnLogin: true, userAgreementMarkdown: '# Configured registration agreement\n\n**Registration terms**\n\n- Keep your account credentials secure.', userAgreementUrl: new URL('/terms', url).href, privacyPolicyUrl: new URL('/privacy', url).href }),
106
+ HAI_IAM_AGREEMENTS: JSON.stringify({
107
+ showOnRegister: true,
108
+ showOnLogin: true,
109
+ userAgreementMarkdown: '# Configured registration agreement\n\n**Registration terms**\n\n- Keep your account credentials secure.',
110
+ userAgreementUrl: new URL('/terms', url).href,
111
+ privacyPolicyUrl: new URL('/privacy', url).href,
112
+ }),
97
113
  }
98
114
  }
@@ -8,7 +8,12 @@ import { core, CoreConfigSchema } from '@h-ai/core'
8
8
  * @returns {Record<string, unknown>} Core 环境覆盖值。
9
9
  */
10
10
  function resolveCoreInputs(environment) {
11
- const resolved = core.config.resolve({ name: 'core', value: {}, schema: CoreConfigSchema, environment })
11
+ const resolved = core.config.resolve({
12
+ name: 'core',
13
+ value: {},
14
+ schema: CoreConfigSchema,
15
+ environment,
16
+ })
12
17
  if (!resolved.success)
13
18
  throw new Error(resolved.error.message)
14
19
  const { data } = resolved
@@ -42,7 +47,9 @@ export function nativeNameEnvironment(envDir) {
42
47
  for (const key of ['name', 'env']) {
43
48
  if (value[key] === undefined)
44
49
  continue
45
- const schema = key === 'name' ? CoreConfigSchema.shape.name : CoreConfigSchema.shape.env
50
+ const schema = key === 'name'
51
+ ? CoreConfigSchema.shape.name
52
+ : CoreConfigSchema.shape.env
46
53
  const parsed = schema.safeParse(value[key])
47
54
  if (!parsed.success)
48
55
  throw new Error(`Invalid HAI_CORE_${key.toUpperCase()}`)
@@ -8,12 +8,25 @@ const basePathMessage = core.i18n.createMessageGetter({
8
8
  'ja-JP': { invalid: 'PUBLIC_BASE_PATHは空、または/で始まるサイト内ディレクトリーです。外部URL、末尾の/、クエリー、フラグメント、パス逸脱は使えません。' },
9
9
  })
10
10
 
11
- /** @param {string} [value] - 无末尾斜杠的公开目录;空字符串表示域名根目录。 */
11
+ /**
12
+ * @param {string} [value] - 无末尾斜杠的公开目录;空字符串表示域名根目录。
13
+ * @returns {'' | `/${string}`} 经校验的站内挂载目录,可直接用于 SvelteKit paths.base。
14
+ */
12
15
  export function resolvePublicBasePath(value = process.env.PUBLIC_BASE_PATH ?? '') {
13
16
  if (value && (!/^\/[\w.-]+(?:\/[\w.-]+)*$/.test(value) || value.split('/').some(segment => segment === '.' || segment === '..'))) {
14
- const language = [process.env.HAI_CORE_DEFAULTLOCALE, process.env.LC_ALL, process.env.LC_MESSAGES, process.env.LANG].find(item => item?.trim())?.split(/[_.-]/)[0]?.toLowerCase()
15
- const locale = language === 'en' || language === 'c' || language === 'posix' ? 'en-US' : language === 'ja' ? 'ja-JP' : 'zh-CN'
17
+ const language = [
18
+ process.env.HAI_CORE_DEFAULTLOCALE,
19
+ process.env.LC_ALL,
20
+ process.env.LC_MESSAGES,
21
+ process.env.LANG,
22
+ ].find(item => item?.trim())?.split(/[_.-]/)[0]?.toLowerCase()
23
+ const locale = language === 'en' || language === 'c' || language === 'posix'
24
+ ? 'en-US'
25
+ : language === 'ja'
26
+ ? 'ja-JP'
27
+ : 'zh-CN'
16
28
  throw new Error(basePathMessage('invalid', { locale }))
17
29
  }
18
- return value
30
+ // 已排除不以 / 开头的非空字符串;正则校验无法自动收窄 TypeScript 字符串类型。
31
+ return /** @type {'' | `/${string}`} */ (value)
19
32
  }
@@ -12,7 +12,9 @@ const cli = require.resolve('@playwright/test/cli')
12
12
  const dataParent = resolve(process.env.HAI_E2E_DATA_ROOT || tmpdir())
13
13
  mkdirSync(dataParent, { recursive: true })
14
14
  const dataRoot = mkdtempSync(join(dataParent, 'hai-browser-e2e-'))
15
- const groups = [{ args: [], name: undefined }]
15
+ const groups = [
16
+ { args: [], name: undefined },
17
+ ]
16
18
  for (const argument of process.argv.slice(2)) {
17
19
  if (argument === '--next')
18
20
  groups.push({ args: [], name: undefined })
@@ -39,7 +41,12 @@ function stop() {
39
41
  if (process.platform === 'win32' && child?.pid && child.exitCode === null) {
40
42
  // Windows 的 kill 不传递 SIGTERM;同时结束本次 Playwright 创建的浏览器与服务进程。
41
43
  stopping = new Promise((resolve) => {
42
- const killer = spawn('taskkill', ['/pid', String(child.pid), '/t', '/f'], { windowsHide: true, stdio: 'ignore' })
44
+ const killer = spawn('taskkill', [
45
+ '/pid',
46
+ String(child.pid),
47
+ '/t',
48
+ '/f',
49
+ ], { windowsHide: true, stdio: 'ignore' })
43
50
  killer.once('error', () => {
44
51
  child?.kill()
45
52
  resolve()
@@ -63,16 +70,30 @@ try {
63
70
  const groupDataRoot = join(dataRoot, `group-${index + 1}`)
64
71
  mkdirSync(groupDataRoot)
65
72
  const hasOutput = args.some(argument => argument === '--output' || argument.startsWith('--output='))
66
- const outputArgs = hasOutput ? [] : ['--output', join(groupRoot, 'results')]
73
+ const outputArgs = hasOutput
74
+ ? []
75
+ : [
76
+ '--output',
77
+ join(groupRoot, 'results'),
78
+ ]
67
79
  const html = process.env.PLAYWRIGHT_HTML_OUTPUT_DIR || process.env.PLAYWRIGHT_HTML_REPORT
68
80
  const code = await new Promise((resolve, reject) => {
69
- child = spawn(process.execPath, [cli, 'test', ...args, ...outputArgs], {
81
+ child = spawn(process.execPath, [
82
+ cli,
83
+ 'test',
84
+ ...args,
85
+ ...outputArgs,
86
+ ], {
70
87
  cwd,
71
88
  windowsHide: true,
72
89
  stdio: 'inherit',
73
90
  env: {
74
91
  ...process.env,
75
- ...(!html ? { PLAYWRIGHT_HTML_OUTPUT_DIR: join(groupRoot, 'html') } : {}),
92
+ ...(!html
93
+ ? {
94
+ PLAYWRIGHT_HTML_OUTPUT_DIR: join(groupRoot, 'html'),
95
+ }
96
+ : {}),
76
97
  HAI_AUTH_EVIDENCE_DIR: process.env.HAI_AUTH_EVIDENCE_DIR || join(groupRoot, 'evidence'),
77
98
  HAI_E2E_DATA_ROOT: groupDataRoot,
78
99
  HAI_E2E_GROUP: name,
@@ -82,8 +103,11 @@ try {
82
103
  child.once('exit', resolve)
83
104
  })
84
105
  // 配置组互相独立,普通失败继续收集;保留首个失败码,中断才停止后续组。
85
- if (code !== 0)
86
- process.exitCode ||= typeof code === 'number' && code !== 0 ? code : 1
106
+ if (code !== 0) {
107
+ process.exitCode ||= typeof code === 'number' && code !== 0
108
+ ? code
109
+ : 1
110
+ }
87
111
  if (interrupted) {
88
112
  process.exitCode ||= 1
89
113
  break
@@ -96,10 +120,17 @@ finally {
96
120
  await stopping
97
121
  // Playwright 退出后服务进程已关闭,此时删除 SQLite / storage,避免 Windows 文件锁。
98
122
  try {
99
- rmSync(dataRoot, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 })
123
+ rmSync(dataRoot, {
124
+ recursive: true,
125
+ force: true,
126
+ maxRetries: 3,
127
+ retryDelay: 100,
128
+ })
100
129
  }
101
130
  catch (error) {
102
- process.stderr.write(`E2E data cleanup failed: ${error instanceof Error ? error.message : String(error)}\n`)
131
+ process.stderr.write(`E2E data cleanup failed: ${error instanceof Error
132
+ ? error.message
133
+ : String(error)}\n`)
103
134
  // 清理错误不能把原始失败(如 exit 7)覆盖成另一状态,也不能让成功变为假成功。
104
135
  if (!process.exitCode)
105
136
  process.exitCode = 1
@@ -12,13 +12,22 @@ if (!mode || !environmentDirectory || !entry)
12
12
  // 从实际应用解析公开 Core 入口,脚本可以放在 workspace 根目录。
13
13
  const require = createRequire(resolve('package.json'))
14
14
  const { core } = await import(pathToFileURL(require.resolve('@h-ai/core')).href)
15
- const loaded = core.config.loadEnvFiles({ mode, envDir: resolve(environmentDirectory) })
15
+ const loaded = core.config.loadEnvFiles({
16
+ mode,
17
+ envDir: resolve(environmentDirectory),
18
+ })
16
19
  if (!loaded.success)
17
20
  throw new Error(loaded.error.message)
18
21
 
19
- const child = spawn(process.execPath, [resolve(entry), ...arguments_], {
22
+ const child = spawn(process.execPath, [
23
+ resolve(entry),
24
+ ...arguments_,
25
+ ], {
20
26
  cwd: process.cwd(),
21
- env: { ...process.env, ...loaded.data },
27
+ env: {
28
+ ...process.env,
29
+ ...loaded.data,
30
+ },
22
31
  stdio: 'inherit',
23
32
  windowsHide: true,
24
33
  })
@@ -35,7 +44,9 @@ try {
35
44
  child.once('error', reject)
36
45
  child.once('close', (code, signal) => resolve({ code, signal }))
37
46
  })
38
- process.exitCode = result.code ?? (result.signal === 'SIGINT' ? 130 : 143)
47
+ process.exitCode = result.code ?? (result.signal === 'SIGINT'
48
+ ? 130
49
+ : 143)
39
50
  }
40
51
  finally {
41
52
  process.off('SIGINT', interrupt)