@h-ai/cli 0.1.0-alpha9 → 1.0.0-beta.2

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 (438) hide show
  1. package/README.en.md +229 -0
  2. package/README.ja.md +229 -0
  3. package/README.md +175 -113
  4. package/dist/chunk-AKV2CQZV.js +1497 -0
  5. package/dist/chunk-AKV2CQZV.js.map +1 -0
  6. package/dist/chunk-EF7WOFWZ.js +7557 -0
  7. package/dist/chunk-EF7WOFWZ.js.map +1 -0
  8. package/dist/chunk-MUHRBJSW.js +29272 -0
  9. package/dist/chunk-MUHRBJSW.js.map +1 -0
  10. package/dist/chunk-ZSDEVXZ7.js +38 -0
  11. package/dist/{chunk-2H7UOFLK.js.map → chunk-ZSDEVXZ7.js.map} +1 -1
  12. package/dist/cli-config-templates-HHFHNXBN.js +5 -0
  13. package/dist/cli-config-templates-HHFHNXBN.js.map +1 -0
  14. package/dist/cli-skill-templates-PN4FLGBC.js +5 -0
  15. package/dist/cli-skill-templates-PN4FLGBC.js.map +1 -0
  16. package/dist/index.js +4444 -554
  17. package/dist/index.js.map +1 -1
  18. package/dist/metafile-esm.json +1 -0
  19. package/dist/src-TEBHR5I5.js +5 -0
  20. package/dist/src-TEBHR5I5.js.map +1 -0
  21. package/package.json +35 -15
  22. package/templates/README.md +56 -114
  23. package/templates/apps/admin/messages/en-US.json +7 -0
  24. package/templates/apps/admin/messages/ja-JP.json +40 -0
  25. package/templates/apps/admin/messages/zh-CN.json +7 -0
  26. package/templates/apps/admin/src/routes/+layout.svelte.hbs +65 -8
  27. package/templates/apps/admin/src/routes/+page.svelte.hbs +35 -14
  28. package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +54 -22
  29. package/templates/apps/admin/src/routes/admin/+page.svelte.hbs +33 -24
  30. package/templates/apps/admin/src/routes/admin/settings/+page.svelte.hbs +16 -13
  31. package/templates/apps/api/.dockerignore.hbs +25 -0
  32. package/templates/apps/api/.gitignore.hbs +22 -0
  33. package/templates/apps/api/.npmrc.hbs +1 -0
  34. package/templates/apps/api/apps/{{projectName}}-contract/README.md.hbs +39 -0
  35. package/templates/apps/api/apps/{{projectName}}-contract/package.json.hbs +41 -0
  36. package/templates/apps/api/apps/{{projectName}}-contract/src/app-contract.ts.hbs +27 -0
  37. package/templates/apps/api/apps/{{projectName}}-contract/src/app-schemas.ts.hbs +28 -0
  38. package/templates/apps/api/apps/{{projectName}}-contract/src/index.ts.hbs +5 -0
  39. package/templates/apps/api/apps/{{projectName}}-contract/src/{{projectName}}-contract.ts.hbs +16 -0
  40. package/templates/apps/api/apps/{{projectName}}-contract/tests/contract.test.ts.hbs +18 -0
  41. package/templates/apps/api/apps/{{projectName}}-contract/tsconfig.json.hbs +12 -0
  42. package/templates/apps/api/apps/{{projectName}}-contract/tsup.config.ts.hbs +11 -0
  43. package/templates/apps/api/apps/{{projectName}}-contract/vitest.config.ts.hbs +9 -0
  44. package/templates/apps/api/apps/{{projectName}}-serv/README.md.hbs +60 -0
  45. package/templates/apps/api/apps/{{projectName}}-serv/config/_core.yml.hbs +17 -0
  46. package/templates/apps/api/apps/{{projectName}}-serv/config/_serv.yml.hbs +54 -0
  47. package/templates/apps/api/apps/{{projectName}}-serv/data/.gitkeep.hbs +1 -0
  48. package/templates/apps/api/apps/{{projectName}}-serv/package.json.hbs +66 -0
  49. package/templates/apps/api/apps/{{projectName}}-serv/src/app.ts.hbs +119 -0
  50. package/templates/apps/api/apps/{{projectName}}-serv/src/build-metadata.ts.hbs +7 -0
  51. package/templates/apps/api/apps/{{projectName}}-serv/src/index.ts.hbs +41 -0
  52. package/templates/apps/api/apps/{{projectName}}-serv/src/lib/server/init.ts.hbs +165 -0
  53. package/templates/apps/api/apps/{{projectName}}-serv/src/server/procedures/app-procedures.ts.hbs +57 -0
  54. package/templates/apps/api/apps/{{projectName}}-serv/src/server/procedures/index.ts.hbs +41 -0
  55. package/templates/apps/api/apps/{{projectName}}-serv/tests/service.test.ts.hbs +176 -0
  56. package/templates/apps/api/apps/{{projectName}}-serv/tsconfig.json.hbs +16 -0
  57. package/templates/apps/api/apps/{{projectName}}-serv/tsup.config.ts.hbs +20 -0
  58. package/templates/apps/api/apps/{{projectName}}-serv/vitest.config.ts.hbs +12 -0
  59. package/templates/apps/api/e2e/api-serv.spec.ts.hbs +113 -0
  60. package/templates/apps/api/e2e/capture-evidence.ts.hbs +23 -0
  61. package/templates/apps/api/eslint.config.js.hbs +30 -0
  62. package/templates/apps/api/hai.json.hbs +4 -0
  63. package/templates/apps/api/images/serv.Dockerfile.hbs +37 -0
  64. package/templates/apps/api/package.json.hbs +53 -0
  65. package/templates/apps/api/playwright.config.ts.hbs +67 -0
  66. package/templates/apps/api/pnpm-workspace.yaml.hbs +40 -0
  67. package/templates/apps/api/tsconfig.base.json +14 -0
  68. package/templates/apps/fullstack/.dockerignore.hbs +25 -0
  69. package/templates/apps/fullstack/.gitignore.hbs +38 -0
  70. package/templates/apps/fullstack/.npmrc.hbs +1 -0
  71. package/templates/apps/fullstack/apps/{{projectName}}-app/.env.example.hbs +10 -0
  72. package/templates/apps/fullstack/apps/{{projectName}}-app/README.md.hbs +67 -0
  73. package/templates/apps/fullstack/apps/{{projectName}}-app/capacitor.config.ts.hbs +20 -0
  74. package/templates/apps/fullstack/apps/{{projectName}}-app/eslint.config.js.hbs +20 -0
  75. package/templates/apps/fullstack/apps/{{projectName}}-app/index.html.hbs +22 -0
  76. package/templates/apps/fullstack/apps/{{projectName}}-app/messages/en-US.json.hbs +7 -0
  77. package/templates/apps/fullstack/apps/{{projectName}}-app/messages/ja-JP.json.hbs +7 -0
  78. package/templates/apps/fullstack/apps/{{projectName}}-app/messages/zh-CN.json.hbs +7 -0
  79. package/templates/apps/fullstack/apps/{{projectName}}-app/package.json.hbs +86 -0
  80. package/templates/apps/fullstack/apps/{{projectName}}-app/project.inlang/settings.json.hbs +17 -0
  81. package/templates/apps/fullstack/apps/{{projectName}}-app/public/runtime-config.js.hbs +4 -0
  82. package/templates/apps/fullstack/apps/{{projectName}}-app/src/App.svelte.hbs +59 -0
  83. package/templates/apps/fullstack/apps/{{projectName}}-app/src/app.css.hbs +20 -0
  84. package/templates/apps/fullstack/apps/{{projectName}}-app/src/app.d.ts.hbs +8 -0
  85. package/templates/apps/fullstack/apps/{{projectName}}-app/src/build-metadata.ts.hbs +9 -0
  86. package/templates/apps/fullstack/apps/{{projectName}}-app/src/lib/capacitor.ts.hbs +19 -0
  87. package/templates/apps/fullstack/apps/{{projectName}}-app/src/main.ts.hbs +21 -0
  88. package/templates/apps/fullstack/apps/{{projectName}}-app/svelte.config.js.hbs +16 -0
  89. package/templates/apps/fullstack/apps/{{projectName}}-app/tsconfig.json.hbs +23 -0
  90. package/templates/apps/fullstack/apps/{{projectName}}-app/vite.config.ts.hbs +74 -0
  91. package/templates/apps/fullstack/apps/{{projectName}}-desktop/.env.example.hbs +6 -0
  92. package/templates/apps/fullstack/apps/{{projectName}}-desktop/README.md.hbs +64 -0
  93. package/templates/apps/fullstack/apps/{{projectName}}-desktop/eslint.config.js.hbs +20 -0
  94. package/templates/apps/fullstack/apps/{{projectName}}-desktop/index.html.hbs +20 -0
  95. package/templates/apps/fullstack/apps/{{projectName}}-desktop/messages/en-US.json.hbs +7 -0
  96. package/templates/apps/fullstack/apps/{{projectName}}-desktop/messages/ja-JP.json.hbs +7 -0
  97. package/templates/apps/fullstack/apps/{{projectName}}-desktop/messages/zh-CN.json.hbs +7 -0
  98. package/templates/apps/fullstack/apps/{{projectName}}-desktop/package.json.hbs +66 -0
  99. package/templates/apps/fullstack/apps/{{projectName}}-desktop/project.inlang/settings.json.hbs +17 -0
  100. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/App.svelte.hbs +25 -0
  101. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/app.css.hbs +18 -0
  102. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/app.d.ts.hbs +8 -0
  103. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/build-metadata.ts.hbs +9 -0
  104. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/main.ts.hbs +20 -0
  105. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/Cargo.toml.hbs +33 -0
  106. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/build.rs.hbs +6 -0
  107. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/capabilities/default.json.hbs +16 -0
  108. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/128x128.png +0 -0
  109. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/128x128@2x.png +0 -0
  110. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/32x32.png +0 -0
  111. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/icon.icns +0 -0
  112. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/icon.ico +0 -0
  113. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/src/lib.rs.hbs +91 -0
  114. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/src/main.rs.hbs +8 -0
  115. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/tauri.conf.json.hbs +46 -0
  116. package/templates/apps/fullstack/apps/{{projectName}}-desktop/svelte.config.js.hbs +14 -0
  117. package/templates/apps/fullstack/apps/{{projectName}}-desktop/tsconfig.json.hbs +22 -0
  118. package/templates/apps/fullstack/apps/{{projectName}}-desktop/vite.config.ts.hbs +89 -0
  119. package/templates/apps/fullstack/apps/{{projectName}}-miniapp/README.md.hbs +25 -0
  120. package/templates/apps/fullstack/apps/{{projectName}}-miniapp/messages/en-US.json.hbs +12 -0
  121. package/templates/apps/fullstack/apps/{{projectName}}-miniapp/messages/ja-JP.json.hbs +12 -0
  122. package/templates/apps/fullstack/apps/{{projectName}}-miniapp/messages/zh-CN.json.hbs +12 -0
  123. package/templates/apps/fullstack/apps/{{projectName}}-miniapp/project.inlang/settings.json.hbs +17 -0
  124. package/templates/apps/fullstack/apps/{{projectName}}-web/README.md.hbs +54 -0
  125. package/templates/apps/fullstack/apps/{{projectName}}-web/eslint.config.js.hbs +20 -0
  126. package/templates/apps/fullstack/apps/{{projectName}}-web/index.html.hbs +21 -0
  127. package/templates/apps/fullstack/apps/{{projectName}}-web/messages/en-US.json.hbs +7 -0
  128. package/templates/apps/fullstack/apps/{{projectName}}-web/messages/ja-JP.json.hbs +7 -0
  129. package/templates/apps/fullstack/apps/{{projectName}}-web/messages/zh-CN.json.hbs +7 -0
  130. package/templates/apps/fullstack/apps/{{projectName}}-web/package.json.hbs +53 -0
  131. package/templates/apps/fullstack/apps/{{projectName}}-web/project.inlang/settings.json.hbs +17 -0
  132. package/templates/apps/fullstack/apps/{{projectName}}-web/public/runtime-config.js.hbs +1 -0
  133. package/templates/apps/fullstack/apps/{{projectName}}-web/src/App.svelte.hbs +18 -0
  134. package/templates/apps/fullstack/apps/{{projectName}}-web/src/app.css.hbs +18 -0
  135. package/templates/apps/fullstack/apps/{{projectName}}-web/src/app.d.ts.hbs +8 -0
  136. package/templates/apps/fullstack/apps/{{projectName}}-web/src/build-metadata.ts.hbs +9 -0
  137. package/templates/apps/fullstack/apps/{{projectName}}-web/src/main.ts.hbs +14 -0
  138. package/templates/apps/fullstack/apps/{{projectName}}-web/svelte.config.js.hbs +16 -0
  139. package/templates/apps/fullstack/apps/{{projectName}}-web/tsconfig.json.hbs +23 -0
  140. package/templates/apps/fullstack/apps/{{projectName}}-web/vite.config.ts.hbs +76 -0
  141. package/templates/apps/fullstack/docs/security-configuration.md.hbs +349 -0
  142. package/templates/apps/fullstack/e2e/fullstack.spec.ts.hbs +988 -0
  143. package/templates/apps/fullstack/e2e/session-close.spec.ts.hbs +119 -0
  144. package/templates/apps/fullstack/eslint.config.js.hbs +41 -0
  145. package/templates/apps/fullstack/hai.json.hbs +11 -0
  146. package/templates/apps/fullstack/images/serv.Dockerfile.hbs +38 -0
  147. package/templates/apps/fullstack/images/web/19-runtime-config.envsh.hbs +5 -0
  148. package/templates/apps/fullstack/images/web/nginx.conf.hbs +24 -0
  149. package/templates/apps/fullstack/images/web/runtime-config.js.template.hbs +3 -0
  150. package/templates/apps/fullstack/images/web.Dockerfile.hbs +37 -0
  151. package/templates/apps/fullstack/package.json.hbs +61 -0
  152. package/templates/apps/fullstack/packages/{{projectName}}-contract/README.md.hbs +40 -0
  153. package/templates/apps/fullstack/packages/{{projectName}}-contract/package.json.hbs +30 -0
  154. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/admin-contract.ts.hbs +78 -0
  155. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/admin-schemas.ts.hbs +134 -0
  156. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/app-contract.ts.hbs +20 -0
  157. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/app-schemas.ts.hbs +35 -0
  158. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/index.ts.hbs +7 -0
  159. package/templates/apps/fullstack/packages/{{projectName}}-contract/src/{{projectName}}-contract.ts.hbs +23 -0
  160. package/templates/apps/fullstack/packages/{{projectName}}-contract/tests/contract.test.ts.hbs +31 -0
  161. package/templates/apps/fullstack/packages/{{projectName}}-contract/tsconfig.json.hbs +9 -0
  162. package/templates/apps/fullstack/packages/{{projectName}}-contract/tsup.config.ts.hbs +9 -0
  163. package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +84 -0
  164. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_ai.yml.hbs +1 -0
  165. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_audit.yml.hbs +1 -0
  166. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_cache.yml.hbs +1 -0
  167. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_core.yml.hbs +22 -0
  168. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_db.yml.hbs +1 -0
  169. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_feedback.yml.hbs +1 -0
  170. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_iam.yml.hbs +1 -0
  171. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_payment.yml.hbs +1 -0
  172. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_reach.yml.hbs +60 -0
  173. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_scheduler.yml.hbs +1 -0
  174. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_serv.yml.hbs +64 -0
  175. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_storage.yml.hbs +1 -0
  176. package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_vecdb.yml.hbs +1 -0
  177. package/templates/apps/fullstack/packages/{{projectName}}-serv/data/.gitkeep.hbs +1 -0
  178. package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +62 -0
  179. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/app-server.ts.hbs +115 -0
  180. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/build-metadata.ts.hbs +7 -0
  181. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/index.ts.hbs +40 -0
  182. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/admin-service.ts.hbs +294 -0
  183. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/audit-jobs.ts.hbs +28 -0
  184. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/business-settings.ts.hbs +50 -0
  185. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/messages.ts.hbs +50 -0
  186. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/admin-procedures.ts.hbs +106 -0
  187. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/app-procedures.ts.hbs +49 -0
  188. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/index.ts.hbs +34 -0
  189. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/runtime.ts.hbs +159 -0
  190. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/security-roles.ts.hbs +73 -0
  191. package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/app-server.test.ts.hbs +505 -0
  192. package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/runtime.test.ts.hbs +72 -0
  193. package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/security.test.ts.hbs +183 -0
  194. package/templates/apps/fullstack/packages/{{projectName}}-serv/tsconfig.json.hbs +10 -0
  195. package/templates/apps/fullstack/packages/{{projectName}}-serv/tsup.config.ts.hbs +18 -0
  196. package/templates/apps/fullstack/packages/{{projectName}}-serv/vitest.config.ts.hbs +12 -0
  197. package/templates/apps/fullstack/packages/{{projectName}}-shared/.gitignore.hbs +10 -0
  198. package/templates/apps/fullstack/packages/{{projectName}}-shared/README.md.hbs +97 -0
  199. package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/en-US.json.hbs +164 -0
  200. package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/ja-JP.json.hbs +164 -0
  201. package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/zh-CN.json.hbs +164 -0
  202. package/templates/apps/fullstack/packages/{{projectName}}-shared/package.json.hbs +55 -0
  203. package/templates/apps/fullstack/packages/{{projectName}}-shared/project.inlang/settings.json.hbs +11 -0
  204. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/index.ts.hbs +7 -0
  205. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/api-client.ts.hbs +94 -0
  206. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/feedback-client.ts.hbs +36 -0
  207. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/sensitive-actions.svelte.ts.hbs +16 -0
  208. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/session-recovery.svelte.ts.hbs +4 -0
  209. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AdminWorkspace.svelte.hbs +122 -0
  210. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AppShell.svelte.hbs +90 -0
  211. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/FeedbackEntry.svelte.hbs +86 -0
  212. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/audit.svelte.hbs +94 -0
  213. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/configuration.svelte.hbs +25 -0
  214. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/feedback.svelte.hbs +157 -0
  215. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/roles.svelte.hbs +77 -0
  216. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/settings.svelte.hbs +44 -0
  217. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/users.svelte.hbs +216 -0
  218. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/security/role-label.ts.hbs +12 -0
  219. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/guide-store.ts.hbs +55 -0
  220. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/management-store.svelte.ts.hbs +614 -0
  221. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/theme-store.svelte.ts.hbs +23 -0
  222. package/templates/apps/fullstack/packages/{{projectName}}-shared/svelte.config.js.hbs +1 -0
  223. package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/api-client.test.ts.hbs +150 -0
  224. package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/management-store.test.ts.hbs +253 -0
  225. package/templates/apps/fullstack/packages/{{projectName}}-shared/tsconfig.json.hbs +17 -0
  226. package/templates/apps/fullstack/packages/{{projectName}}-shared/vitest.config.ts.hbs +7 -0
  227. package/templates/apps/fullstack/playwright.config.ts.hbs +114 -0
  228. package/templates/apps/fullstack/playwright.session-close.config.ts.hbs +18 -0
  229. package/templates/apps/fullstack/pnpm-workspace.yaml.hbs +38 -0
  230. package/templates/apps/fullstack/tsconfig.base.json +14 -0
  231. package/templates/apps/h5/messages/en-US.json +3 -0
  232. package/templates/apps/h5/messages/ja-JP.json +40 -0
  233. package/templates/apps/h5/messages/zh-CN.json +3 -0
  234. package/templates/apps/h5/src/routes/+layout.svelte.hbs +85 -30
  235. package/templates/apps/h5/src/routes/+page.svelte.hbs +20 -8
  236. package/templates/apps/h5/src/routes/discover/+page.svelte.hbs +17 -6
  237. package/templates/apps/h5/src/routes/profile/+page.svelte.hbs +17 -6
  238. package/templates/apps/mobile-app/.env.hbs +3 -0
  239. package/templates/apps/{android-app → mobile-app}/capacitor.config.ts.hbs +2 -2
  240. package/templates/apps/mobile-app/index.html.hbs +14 -0
  241. package/templates/apps/mobile-app/messages/en-US.json +36 -0
  242. package/templates/apps/mobile-app/messages/ja-JP.json +36 -0
  243. package/templates/apps/mobile-app/messages/zh-CN.json +36 -0
  244. package/templates/apps/mobile-app/public/runtime-config.js +1 -0
  245. package/templates/apps/mobile-app/src/App.svelte.hbs +153 -0
  246. package/templates/apps/mobile-app/src/lib/api.ts.hbs +213 -0
  247. package/templates/apps/mobile-app/src/lib/app-config.ts.hbs +14 -0
  248. package/templates/apps/{android-app → mobile-app}/src/lib/capacitor.ts +6 -7
  249. package/templates/apps/mobile-app/src/lib/pages/home.svelte.hbs +58 -0
  250. package/templates/apps/mobile-app/src/lib/pages/profile.svelte.hbs +13 -0
  251. package/templates/apps/mobile-app/src/lib/pages/tasks.svelte.hbs +16 -0
  252. package/templates/apps/mobile-app/src/main.ts.hbs +11 -0
  253. package/templates/apps/website/messages/en-US.json +4 -2
  254. package/templates/apps/website/messages/ja-JP.json +34 -0
  255. package/templates/apps/website/messages/zh-CN.json +4 -2
  256. package/templates/apps/website/scripts/static-website.mjs.hbs +67 -0
  257. package/templates/apps/website/src/routes/+layout.svelte.hbs +77 -26
  258. package/templates/apps/website/src/routes/+layout.ts +3 -0
  259. package/templates/apps/website/src/routes/+page.svelte.hbs +31 -12
  260. package/templates/apps/website/src/routes/about/+page.svelte.hbs +11 -6
  261. package/templates/apps/website/src/routes/api/health/+server.ts +3 -0
  262. package/templates/apps/website/src/routes/contact/+page.svelte.hbs +44 -34
  263. package/templates/apps/website/src/routes/services/+page.svelte.hbs +27 -40
  264. package/templates/base/.dockerignore.hbs +27 -0
  265. package/templates/base/.gitignore.hbs +41 -0
  266. package/templates/base/.npmrc.hbs +1 -0
  267. package/templates/base/e2e/app.spec.ts.hbs +213 -0
  268. package/templates/base/e2e/helpers.ts +1 -1
  269. package/templates/base/eslint-rules.js +45 -0
  270. package/templates/base/eslint.config.js.hbs +34 -0
  271. package/templates/base/hai.json.hbs +4 -0
  272. package/templates/base/images/web/nginx.conf.hbs +24 -0
  273. package/templates/base/images/web.Dockerfile.hbs +72 -0
  274. package/templates/base/package.json.hbs +125 -49
  275. package/templates/base/playwright.config.ts +44 -6
  276. package/templates/base/pnpm-workspace.yaml.hbs +40 -0
  277. package/templates/base/src/app.css.hbs +40 -0
  278. package/templates/base/src/app.d.ts.hbs +14 -1
  279. package/templates/base/src/app.html.hbs +13 -0
  280. package/templates/base/src/hooks.server.ts.hbs +115 -43
  281. package/templates/base/src/lib/build-metadata.ts.hbs +7 -0
  282. package/templates/base/src/lib/server/init.ts.hbs +125 -152
  283. package/templates/base/src/lib/server/kit-config.ts.hbs +40 -0
  284. package/templates/base/src/routes/+layout.server.ts.hbs +35 -0
  285. package/templates/base/static/favicon.png +0 -0
  286. package/templates/base/svelte.config.js.hbs +84 -5
  287. package/templates/base/tests/scaffold.test.ts.hbs +102 -0
  288. package/templates/base/tsconfig.json.hbs +50 -0
  289. package/templates/base/vite.config.ts.hbs +117 -12
  290. package/templates/base/vitest.config.ts.hbs +19 -0
  291. package/templates/features/ai/routes/api/chat/+server.ts +6 -7
  292. package/templates/features/iam/routes-admin/(auth)/+layout.svelte.hbs +3 -17
  293. package/templates/features/iam/routes-admin/(auth)/auth/forgot-password/+page.svelte.hbs +10 -0
  294. package/templates/features/iam/routes-admin/(auth)/auth/login/+page.svelte.hbs +9 -96
  295. package/templates/features/iam/routes-admin/(auth)/auth/register/+page.svelte.hbs +9 -122
  296. package/templates/features/iam/routes-admin/(auth)/auth/reset-password/+page.svelte.hbs +10 -0
  297. package/templates/features/iam/routes-h5/auth/forgot-password/+page.svelte.hbs +10 -0
  298. package/templates/features/iam/routes-h5/auth/login/+page.svelte.hbs +9 -96
  299. package/templates/features/iam/routes-h5/auth/register/+page.svelte.hbs +9 -112
  300. package/templates/features/iam/routes-h5/auth/reset-password/+page.svelte.hbs +10 -0
  301. package/templates/features/iam/routes-shared/api/auth/captcha/+server.ts.hbs +4 -0
  302. package/templates/features/iam/routes-shared/api/auth/config/+server.ts +4 -0
  303. package/templates/features/iam/routes-shared/api/auth/login/+server.ts +1 -29
  304. package/templates/features/iam/routes-shared/api/auth/login/ldap/+server.ts +4 -0
  305. package/templates/features/iam/routes-shared/api/auth/login/otp/+server.ts +4 -0
  306. package/templates/features/iam/routes-shared/api/auth/logout/+server.ts +13 -6
  307. package/templates/features/iam/routes-shared/api/auth/otp/send/+server.ts +4 -0
  308. package/templates/features/iam/routes-shared/api/auth/password/renew/+server.ts +5 -0
  309. package/templates/features/iam/routes-shared/api/auth/password-reset/confirm/+server.ts +4 -0
  310. package/templates/features/iam/routes-shared/api/auth/password-reset/request/+server.ts +4 -0
  311. package/templates/features/iam/routes-shared/api/auth/reauthenticate/+server.ts +5 -0
  312. package/templates/features/iam/routes-shared/api/auth/register/+server.ts +1 -23
  313. package/templates/features/iam/routes-shared/api/auth/session/close/+server.ts.hbs +4 -0
  314. package/templates/features/iam/routes-website/auth/forgot-password/+page.svelte.hbs +10 -0
  315. package/templates/features/iam/routes-website/auth/login/+page.svelte.hbs +11 -0
  316. package/templates/features/iam/routes-website/auth/register/+page.svelte.hbs +11 -0
  317. package/templates/features/iam/routes-website/auth/reset-password/+page.svelte.hbs +10 -0
  318. package/templates/features/payment/routes/api/v1/payment/create/+server.ts +25 -23
  319. package/templates/features/payment/routes/api/v1/payment/notify/[provider]/+server.ts +5 -2
  320. package/templates/features/storage/routes/api/upload/+server.ts +10 -8
  321. package/templates/i18n/project.inlang/settings.json +2 -2
  322. package/templates/shared/.gitattributes +11 -0
  323. package/templates/shared/build-metadata.ts +42 -0
  324. package/templates/shared/container-runtime-config.sh +30 -0
  325. package/templates/shared/e2e-env.ts +98 -0
  326. package/templates/shared/hash-router.svelte.ts +83 -0
  327. package/templates/shared/public-base-path.mjs +19 -0
  328. package/templates/shared/run-e2e.mjs +104 -0
  329. package/templates/shared/vite-runtime-config.ts +56 -0
  330. package/templates/skills/AGENTS.md +75 -16
  331. package/templates/skills/CLAUDE.md +0 -11
  332. package/templates/skills/bridges/admin/AGENTS.md +89 -0
  333. package/templates/skills/bridges/api/AGENTS.md +83 -0
  334. package/templates/skills/bridges/fullstack/AGENTS.md.hbs +102 -0
  335. package/templates/skills/bridges/h5/AGENTS.md +88 -0
  336. package/templates/skills/bridges/mobile-app/AGENTS.md +100 -0
  337. package/templates/skills/bridges/website/AGENTS.md +88 -0
  338. package/templates/skills/copilot-instructions.md +3 -59
  339. package/templates/skills/hai-ai/SKILL.md +44 -715
  340. package/templates/skills/hai-ai/guide.md +457 -0
  341. package/templates/skills/hai-ai/reference.md +292 -0
  342. package/templates/skills/hai-api-client/SKILL.md +26 -339
  343. package/templates/skills/hai-api-client/reference.md +180 -0
  344. package/templates/skills/hai-api-contract/SKILL.md +36 -0
  345. package/templates/skills/hai-api-contract/reference.md +280 -0
  346. package/templates/skills/hai-app-create/SKILL.md +38 -351
  347. package/templates/skills/hai-app-create/collaboration.md +52 -0
  348. package/templates/skills/hai-app-create/development.md +243 -0
  349. package/templates/skills/hai-app-create/reference.md +376 -0
  350. package/templates/skills/hai-app-review/SKILL.md +57 -126
  351. package/templates/skills/hai-app-review/differential.md +34 -0
  352. package/templates/skills/hai-app-tests/SKILL.md +34 -454
  353. package/templates/skills/hai-app-tests/reference.md +462 -0
  354. package/templates/skills/hai-app-tests/validation.md +42 -0
  355. package/templates/skills/hai-audit/SKILL.md +37 -122
  356. package/templates/skills/hai-audit/reference.md +184 -0
  357. package/templates/skills/hai-build/SKILL.md +62 -315
  358. package/templates/skills/hai-build/paths.md +30 -0
  359. package/templates/skills/hai-build/reference.md +353 -0
  360. package/templates/skills/hai-cache/SKILL.md +26 -175
  361. package/templates/skills/hai-cache/reference.md +229 -0
  362. package/templates/skills/hai-capacitor/SKILL.md +24 -364
  363. package/templates/skills/hai-capacitor/reference.md +358 -0
  364. package/templates/skills/hai-change-plan/SKILL.md +46 -0
  365. package/templates/skills/hai-ci/SKILL.md +114 -0
  366. package/templates/skills/hai-core/SKILL.md +31 -469
  367. package/templates/skills/hai-core/reference.md +557 -0
  368. package/templates/skills/hai-core/request-access.md +65 -0
  369. package/templates/skills/hai-crypto/SKILL.md +29 -180
  370. package/templates/skills/hai-crypto/reference.md +317 -0
  371. package/templates/skills/hai-datapipe/SKILL.md +24 -207
  372. package/templates/skills/hai-datapipe/reference.md +204 -0
  373. package/templates/skills/hai-deploy/SKILL.md +53 -178
  374. package/templates/skills/hai-deploy/credentials.md +19 -0
  375. package/templates/skills/hai-deploy/middleware.md +129 -0
  376. package/templates/skills/hai-feedback/SKILL.md +85 -0
  377. package/templates/skills/hai-framework-sync/SKILL.md +105 -0
  378. package/templates/skills/hai-framework-sync/sync.md +49 -0
  379. package/templates/skills/hai-iam/SKILL.md +53 -325
  380. package/templates/skills/hai-iam/reference.md +535 -0
  381. package/templates/skills/hai-kit/SKILL.md +33 -329
  382. package/templates/skills/hai-kit/reference.md +202 -0
  383. package/templates/skills/hai-payment/SKILL.md +28 -262
  384. package/templates/skills/hai-payment/reference.md +295 -0
  385. package/templates/skills/hai-pr-review/SKILL.md +41 -0
  386. package/templates/skills/hai-reach/SKILL.md +28 -300
  387. package/templates/skills/hai-reach/reference.md +363 -0
  388. package/templates/skills/hai-reldb/SKILL.md +28 -449
  389. package/templates/skills/hai-reldb/reference.md +500 -0
  390. package/templates/skills/hai-scheduler/SKILL.md +26 -174
  391. package/templates/skills/hai-scheduler/reference.md +216 -0
  392. package/templates/skills/hai-serv/SKILL.md +60 -0
  393. package/templates/skills/hai-serv/reference.md +792 -0
  394. package/templates/skills/hai-spec-implement/SKILL.md +50 -0
  395. package/templates/skills/hai-spec-implement/changes.md +67 -0
  396. package/templates/skills/hai-spec-implement/evaluation.md +18 -0
  397. package/templates/skills/hai-spec-implement/handoff.md +47 -0
  398. package/templates/skills/hai-spec-implement/templates.md +117 -0
  399. package/templates/skills/hai-spec-implement/workflow.md +56 -0
  400. package/templates/skills/hai-spec-review/SKILL.md +57 -0
  401. package/templates/skills/hai-spec-review/checklist.md +71 -0
  402. package/templates/skills/hai-storage/SKILL.md +31 -262
  403. package/templates/skills/hai-storage/reference.md +284 -0
  404. package/templates/skills/hai-ui/SKILL.md +62 -238
  405. package/templates/skills/hai-ui/guide.md +81 -0
  406. package/templates/skills/hai-ui/reference.md +705 -0
  407. package/templates/skills/hai-ui-design/SKILL.md +31 -0
  408. package/templates/skills/hai-ui-design/patterns.md +31 -0
  409. package/templates/skills/hai-ui-review/SKILL.md +32 -0
  410. package/templates/skills/hai-ui-review/checklist.md +29 -0
  411. package/templates/skills/hai-vecdb/SKILL.md +25 -267
  412. package/templates/skills/hai-vecdb/reference.md +325 -0
  413. package/templates/skills/opencode.json +0 -5
  414. package/dist/chunk-2H7UOFLK.js +0 -10
  415. package/dist/chunk-LANIDJC7.js +0 -659
  416. package/dist/chunk-LANIDJC7.js.map +0 -1
  417. package/dist/chunk-YV7WPUI6.js +0 -206
  418. package/dist/chunk-YV7WPUI6.js.map +0 -1
  419. package/dist/config-templates-S5RI2MC6.js +0 -5
  420. package/dist/config-templates-S5RI2MC6.js.map +0 -1
  421. package/dist/skill-templates-N5DU5FNX.js +0 -5
  422. package/dist/skill-templates-N5DU5FNX.js.map +0 -1
  423. package/dist/src-XJ6YXNAF.js +0 -15030
  424. package/dist/src-XJ6YXNAF.js.map +0 -1
  425. package/templates/apps/android-app/.env.hbs +0 -3
  426. package/templates/apps/android-app/messages/en-US.json +0 -24
  427. package/templates/apps/android-app/messages/zh-CN.json +0 -24
  428. package/templates/apps/android-app/src/lib/api.ts.hbs +0 -30
  429. package/templates/apps/android-app/src/routes/+layout.svelte.hbs +0 -42
  430. package/templates/apps/android-app/src/routes/+layout.ts +0 -7
  431. package/templates/apps/android-app/src/routes/+page.svelte.hbs +0 -27
  432. package/templates/apps/api/src/routes/+layout.svelte +0 -14
  433. package/templates/apps/api/src/routes/+page.svelte +0 -11
  434. package/templates/apps/api/src/routes/api/v1/health/+server.ts +0 -14
  435. package/templates/apps/api/src/routes/api/v1/items/+server.ts +0 -37
  436. package/templates/apps/api/src/routes/api/v1/items/[id]/+server.ts +0 -30
  437. package/templates/base/src/app.css +0 -2
  438. package/templates/base/tsconfig.json +0 -8
@@ -21,8 +21,7 @@ export const POST: RequestHandler = async ({ request, params }) => {
21
21
  headers[key] = value
22
22
  })
23
23
 
24
- const result = await payment.handleNotify({
25
- provider,
24
+ const result = await payment.handleNotify(provider, {
26
25
  headers,
27
26
  body,
28
27
  })
@@ -31,6 +30,10 @@ export const POST: RequestHandler = async ({ request, params }) => {
31
30
  return new Response('FAIL', { status: 500 })
32
31
  }
33
32
 
33
+ // 此模板仅确认已验签解析;success 不代表已付款,Stripe 延迟付款会返回 pending。
34
+ // 业务接入时须在响应成功前,用共享数据库核对订单/金额/币种,按 eventId 去重并防止状态倒退;
35
+ // 仅 status=paid 可触发履约,不在进程内 Set/Map 中维护通知去重。
36
+
34
37
  // 微信支付要求返回 JSON,支付宝要求返回 "success"
35
38
  if (provider === 'wechat') {
36
39
  return new Response(JSON.stringify({ code: 'SUCCESS', message: '' }), {
@@ -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,9 +1,9 @@
1
1
  {
2
2
  "$schema": "https://inlang.com/schema/project-settings",
3
3
  "baseLocale": "zh-CN",
4
- "locales": ["zh-CN", "en-US"],
4
+ "locales": ["zh-CN", "en-US", "ja-JP"],
5
5
  "modules": [
6
- "../../node_modules/@inlang/plugin-message-format/dist/index.js"
6
+ "./node_modules/@inlang/plugin-message-format/dist/index.js"
7
7
  ],
8
8
  "plugin.inlang.messageFormat": {
9
9
  "pathPattern": "./messages/{locale}.json"
@@ -0,0 +1,11 @@
1
+ # Windows 构建机交付 Linux 启动脚本时必须保留 LF,避免 /bin/sh 解释器失效。
2
+ *.sh text eol=lf
3
+ *.sh.hbs text eol=lf
4
+ *.envsh text eol=lf
5
+ *.envsh.hbs text eol=lf
6
+
7
+ # Linux 容器引擎读取忽略规则和构建文件时统一使用 LF。
8
+ .dockerignore text eol=lf
9
+ *.dockerignore text eol=lf
10
+ Dockerfile text eol=lf
11
+ *.Dockerfile text eol=lf
@@ -0,0 +1,42 @@
1
+ import { execFileSync } from 'node:child_process'
2
+ import { randomUUID } from 'node:crypto'
3
+ import { readFileSync } from 'node:fs'
4
+ import { join, relative } from 'node:path'
5
+ import process from 'node:process'
6
+
7
+ /** 当前编译目标的私有产物身份;同一 SSR 构建重入复用身份,各端版本来自自己的 manifest。 */
8
+ export function resolveBuildMetadata(directory: string): { appVersion: string, buildId: string, commit: string } {
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'
11
+ if (appVersion.length > 128)
12
+ throw new Error('Invalid package.json version: maximum length is 128')
13
+ const suppliedId = process.env.HAI_BUILD_ID?.trim()
14
+ if (process.env.HAI_BUILD_ID !== undefined && !/^[\w.+-]{1,128}$/.test(suppliedId ?? ''))
15
+ throw new Error('Invalid HAI_BUILD_ID: expected 1–128 letters, digits, underscores, dots, plus or minus signs')
16
+ const buildId = suppliedId ?? randomUUID()
17
+ const suppliedCommit = process.env.HAI_BUILD_COMMIT?.trim()
18
+ if (process.env.HAI_BUILD_COMMIT !== undefined && !/^(?:[a-f\d]{40}|[a-f\d]{64}|unknown)$/i.test(suppliedCommit ?? ''))
19
+ throw new Error('Invalid HAI_BUILD_COMMIT: expected a full Git SHA or unknown')
20
+ const commit = suppliedCommit ?? sourceCommit(directory)
21
+ // SvelteKit 在同一构建进程内重新求值 Vite 配置;不依赖临时配置模块缓存。
22
+ process.env.HAI_BUILD_ID = buildId
23
+ process.env.HAI_BUILD_COMMIT = commit
24
+ return { appVersion, buildId, commit }
25
+ }
26
+
27
+ /** 未跟踪的生成工程不能把临时目录的父框架提交冒充自身源码。 */
28
+ function sourceCommit(directory: string): string {
29
+ try {
30
+ const options = { cwd: directory, encoding: 'utf8' as const, stdio: 'pipe' as const, windowsHide: true }
31
+ const root = execFileSync('git', ['rev-parse', '--show-toplevel'], options).trim()
32
+ const manifest = relative(root, join(directory, 'package.json')).replaceAll('\\', '/')
33
+ if (manifest.startsWith('../'))
34
+ return 'unknown'
35
+ execFileSync('git', ['ls-files', '--error-unmatch', '--', manifest], { ...options, cwd: root })
36
+ const commit = execFileSync('git', ['rev-parse', 'HEAD'], options).trim()
37
+ return /^(?:[a-f\d]{40}|[a-f\d]{64})$/i.test(commit) ? commit : 'unknown'
38
+ }
39
+ catch {
40
+ return 'unknown'
41
+ }
42
+ }
@@ -0,0 +1,30 @@
1
+ #!/bin/sh
2
+ set -eu
3
+
4
+ # 只编码公开白名单;Base64 不会把环境值中的引号或换行解释为 JavaScript。
5
+ encode() { printf '%s' "$1" | base64 | tr -d '\n'; }
6
+ mkdir -p /tmp/hai-runtime-config
7
+ cat > /tmp/hai-runtime-config/runtime-config.js <<EOF
8
+ {
9
+ const decode = value => new TextDecoder().decode(Uint8Array.from(atob(value), character => character.charCodeAt(0)));
10
+ const nonempty = object => Object.fromEntries(Object.entries(object).filter(([, value]) => value !== ''));
11
+ const core = nonempty({
12
+ name: decode('$(encode "${HAI_CORE_NAME:-}")'),
13
+ version: decode('$(encode "${HAI_CORE_VERSION:-}")'),
14
+ env: decode('$(encode "${HAI_CORE_ENV:-}")'),
15
+ defaultLocale: decode('$(encode "${HAI_CORE_DEFAULTLOCALE:-}")')
16
+ });
17
+ const logging = nonempty({
18
+ level: decode('$(encode "${HAI_CORE_LOGGING_LEVEL:-}")'),
19
+ format: decode('$(encode "${HAI_CORE_LOGGING_FORMAT:-}")')
20
+ });
21
+ if (Object.keys(logging).length) core.logging = logging;
22
+ const config = nonempty({
23
+ apiBase: decode('$(encode "${PUBLIC_API_BASE:-}")'),
24
+ apiTransport: decode('$(encode "${PUBLIC_API_TRANSPORT:-}")'),
25
+ apiKeyExchangePath: decode('$(encode "${PUBLIC_API_KEY_EXCHANGE_PATH:-}")')
26
+ });
27
+ if (Object.keys(core).length) config.core = core;
28
+ globalThis.__HAI_PUBLIC_CONFIG__ = { ...globalThis.__HAI_PUBLIC_CONFIG__, ...config };
29
+ }
30
+ EOF
@@ -0,0 +1,98 @@
1
+ import { createECDH } from 'node:crypto'
2
+ import { isAbsolute } from 'node:path'
3
+ import process from 'node:process'
4
+
5
+ /**
6
+ * 仅给 Playwright 的服务子进程装配环境;不修改测试进程和 pnpm/Turbo 的环境。
7
+ * @param profile - 本轮测试明确选择的模块配置和可信控制值。
8
+ * @returns Playwright webServer.env;undefined 项由 Node spawn 从子进程环境中移除。
9
+ * @throws 缺少绝对数据目录,或 API 指向非本轮 loopback HTTP 夹具时抛错。
10
+ * @example
11
+ * ```ts
12
+ * // 测试内部上下文;数据目录由 run-e2e 为本轮分配。
13
+ * const env = createE2eServerEnv({
14
+ * HAI_E2E_DATA_ROOT: process.cwd(),
15
+ * HAI_CACHE: JSON.stringify({ type: 'memory' }),
16
+ * })
17
+ * if (env.HAI_E2E !== '1') throw new Error('E2E profile was not applied')
18
+ * ```
19
+ */
20
+ export function createE2eServerEnv(profile: Record<string, string>): Record<string, string> {
21
+ const dataRoot = profile.HAI_E2E_DATA_ROOT || process.env.HAI_E2E_DATA_ROOT
22
+ if (!dataRoot || !isAbsolute(dataRoot))
23
+ throw new Error('Run E2E through the managed entrypoint with its own absolute HAI_E2E_DATA_ROOT')
24
+ if (profile.PUBLIC_API_BASE) {
25
+ const api = new URL(profile.PUBLIC_API_BASE)
26
+ if (api.protocol !== 'http:' || !['127.0.0.1', 'localhost', '[::1]'].includes(api.hostname) || api.username || api.password)
27
+ throw new Error('E2E API must use an unauthenticated loopback HTTP fixture')
28
+ }
29
+ const environment: Record<string, string | undefined> = Object.fromEntries(
30
+ Object.keys(process.env).filter(key => /^(?:HAI_|PUBLIC_|VITE_)/i.test(key)).map(key => [key, undefined]),
31
+ )
32
+ for (const name of ['HAI_E2E_DATA_ROOT', 'HAI_AUTH_EVIDENCE_DIR', 'HAI_CORE_NAME', 'HAI_CORE_VERSION']) {
33
+ if (process.env[name] !== undefined)
34
+ environment[name] = process.env[name]
35
+ }
36
+ Object.assign(environment, { HAI_E2E: '1', NODE_ENV: 'test', HAI_E2E_DATA_ROOT: dataRoot }, profile)
37
+ // Playwright 声明仅接受 string,但其 WebServer 合并 env 后直接交 Node spawn;
38
+ // 已用安装版真实 WebServer 验证 undefined 会删除继承项,因此仅在第三方类型边界使用窄断言。
39
+ return environment as Record<string, string>
40
+ }
41
+
42
+ /**
43
+ * 每轮生成独立可信 SM2 ring;私钥只传服务子进程,不进入公开配置或报告。
44
+ * @returns 符合 transport serverKeyRing 配置的 JSON 字符串。
45
+ * @throws 当前 Node/OpenSSL 不支持 SM2 时抛错,不降级为不可信握手。
46
+ * @example
47
+ * ```ts
48
+ * // 测试内部上下文;仅交给本轮服务子进程。
49
+ * const env = createE2eServerEnv({
50
+ * HAI_E2E_DATA_ROOT: process.cwd(),
51
+ * HAI_CRYPTO_TRANSPORT_SERVERKEYRING: createE2eTransportRing(),
52
+ * })
53
+ * if (!env.HAI_CRYPTO_TRANSPORT_SERVERKEYRING) throw new Error('Trusted ring is required')
54
+ * ```
55
+ */
56
+ export function createE2eTransportRing(): string {
57
+ const key = createECDH('SM2')
58
+ 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
+ } } })
63
+ }
64
+
65
+ /**
66
+ * 只把既有的本轮 loopback 通知夹具控制地址转成明确 Reach 配置。
67
+ * @returns 未启用通知夹具时为空对象;启用时包含 OTP、模板及协议配置。
68
+ * @throws IAM_NOTIFICATION_URL 不是无凭据的 loopback HTTP 地址时抛错。
69
+ * @example
70
+ * ```ts
71
+ * // 测试内部上下文;IAM_NOTIFICATION_URL 由样板门禁启动的通知夹具提供。
72
+ * const env = createE2eServerEnv({
73
+ * ...createE2eNotificationEnv(),
74
+ * HAI_E2E_DATA_ROOT: process.cwd(),
75
+ * })
76
+ * if (env.HAI_E2E !== '1') throw new Error('Notification profile was not isolated')
77
+ * ```
78
+ */
79
+ export function createE2eNotificationEnv(): Record<string, string> {
80
+ const address = process.env.IAM_NOTIFICATION_URL
81
+ if (!address)
82
+ return {}
83
+ const url = new URL(address)
84
+ if (url.protocol !== 'http:' || !['127.0.0.1', 'localhost', '[::1]'].includes(url.hostname) || url.username || url.password)
85
+ throw new Error('E2E notification fixture must use an unauthenticated loopback HTTP address')
86
+ return {
87
+ HAI_IAM_LOGIN_OTP: 'true',
88
+ HAI_IAM_PASSWORDRESET_ENABLED: 'true',
89
+ HAI_REACH_PROVIDERS: JSON.stringify(['email', 'sms'].map(name => ({ name, type: 'api', url: new URL('/send', url).href }))),
90
+ HAI_REACH_TEMPLATES: JSON.stringify([
91
+ { name: 'otp_email', provider: 'email', body: 'Code: {code}' },
92
+ { name: 'otp_sms', provider: 'sms', body: 'Code: {code}' },
93
+ { name: 'password_reset', provider: 'email', body: 'Reset: {token}' },
94
+ { name: 'password_reset_sms', provider: 'sms', body: 'Reset: {token}' },
95
+ ]),
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 }),
97
+ }
98
+ }
@@ -0,0 +1,83 @@
1
+ import { SvelteMap, SvelteURL } from 'svelte/reactivity'
2
+
3
+ /**
4
+ * 页面目录驱动的 hash 导航;仅管理 URL,不包含业务权限或页面加载逻辑。
5
+ * @example
6
+ * ```ts
7
+ * const pages = import.meta.glob('../pages/*.svelte')
8
+ * const router = new HashRouter(Object.keys(pages), '/home')
9
+ * const stop = router.start(() => void loadCurrentPage())
10
+ * router.navigate('/reports/weekly?period=month')
11
+ * stop()
12
+ * ```
13
+ */
14
+ export class HashRouter {
15
+ /** 当前页面路径,例如 `/reports/weekly`。 */
16
+ path = $state('')
17
+ /** 当前页面查询串,例如 `?period=month`。 */
18
+ search = $state('')
19
+ private readonly files = new SvelteMap<string, string>()
20
+
21
+ private readonly fallback: string
22
+
23
+ /**
24
+ * 建立页面文件到 URL 的映射,新增页面无需维护路由表。
25
+ * @param pageFiles - import.meta.glob 返回的文件名
26
+ * @param fallback - 空路径和未知页面的回退路径
27
+ * @example new HashRouter(Object.keys(import.meta.glob('../pages/*.svelte')), '/home')
28
+ */
29
+ constructor(pageFiles: string[], fallback: string) {
30
+ this.fallback = fallback
31
+ for (const file of pageFiles) {
32
+ const route = file.replace(/^.*\/pages/, '').replace(/\.svelte$/, '').replace(/\/index$/, '') || '/'
33
+ this.files.set(route, file)
34
+ }
35
+ if (!this.files.has(fallback))
36
+ throw new Error('Hash router fallback page is missing')
37
+ this.path = fallback
38
+ }
39
+
40
+ /** 当前路径对应的页面文件;可用于索引 import.meta.glob 的惰性加载器。 */
41
+ get file(): string {
42
+ return this.files.get(this.path) ?? this.files.get(this.fallback)!
43
+ }
44
+
45
+ /**
46
+ * 恢复地址栏状态并监听链接、前进与后退;卸载时调用返回的清理函数。
47
+ * @param onChange - URL 导航完成后的业务通知
48
+ * @returns 移除事件监听器的函数
49
+ * @example const stop = router.start(() => void store.navigate(router.path.slice(1)))
50
+ */
51
+ start(onChange: () => void = () => {}): () => void {
52
+ const synchronize = () => {
53
+ this.navigate(location.hash.slice(1), true)
54
+ onChange()
55
+ }
56
+ synchronize()
57
+ window.addEventListener('hashchange', synchronize)
58
+ return () => {
59
+ window.removeEventListener('hashchange', synchronize)
60
+ }
61
+ }
62
+
63
+ /**
64
+ * 导航到页面;未知路径回退,查询串随 hash 保留并可在刷新后恢复。
65
+ * @param target - 以 `/` 开头的本地页面路径和查询串
66
+ * @param replace - 是否替换当前历史项
67
+ * @example router.navigate('/settings?section=profile')
68
+ */
69
+ navigate(target: string, replace = false): void {
70
+ const local = target.startsWith('/') && !target.startsWith('//') && !target.includes('\\')
71
+ const url = new SvelteURL(local ? target : this.fallback, 'https://hash.invalid')
72
+ const known = this.files.has(url.pathname)
73
+ this.path = known ? url.pathname : this.fallback
74
+ this.search = known ? url.search : ''
75
+ const hash = `#${this.path}${this.search}`
76
+ if (location.hash !== hash) {
77
+ if (replace)
78
+ history.replaceState(history.state, '', hash)
79
+ else
80
+ history.pushState(history.state, '', hash)
81
+ }
82
+ }
83
+ }
@@ -0,0 +1,19 @@
1
+ /** 公开的网站挂载目录;只读取显式构建值,不加载私有环境文件。 */
2
+ import process from 'node:process'
3
+ import { core } from '@h-ai/core'
4
+
5
+ const basePathMessage = core.i18n.createMessageGetter({
6
+ 'zh-CN': { invalid: 'PUBLIC_BASE_PATH须为空或以/开头的站内目录;不允许外部地址、末尾/、查询、片段或路径逃逸。' },
7
+ 'en-US': { invalid: 'PUBLIC_BASE_PATH must be empty or a site-local directory beginning with /. External URLs, trailing /, queries, fragments and path traversal are not allowed.' },
8
+ 'ja-JP': { invalid: 'PUBLIC_BASE_PATHは空、または/で始まるサイト内ディレクトリーです。外部URL、末尾の/、クエリー、フラグメント、パス逸脱は使えません。' },
9
+ })
10
+
11
+ /** @param {string} [value] - 无末尾斜杠的公开目录;空字符串表示域名根目录。 */
12
+ export function resolvePublicBasePath(value = process.env.PUBLIC_BASE_PATH ?? '') {
13
+ 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'
16
+ throw new Error(basePathMessage('invalid', { locale }))
17
+ }
18
+ return value
19
+ }
@@ -0,0 +1,104 @@
1
+ /** 运行浏览器验收,保留本轮证据;退出后仅回收本轮服务数据,失败和中断同样处理。 */
2
+ import { spawn } from 'node:child_process'
3
+ import { mkdirSync, mkdtempSync, rmSync } from 'node:fs'
4
+ import { createRequire } from 'node:module'
5
+ import { tmpdir } from 'node:os'
6
+ import { join, resolve } from 'node:path'
7
+ import process from 'node:process'
8
+
9
+ const cwd = process.cwd()
10
+ const require = createRequire(resolve(cwd, 'package.json'))
11
+ const cli = require.resolve('@playwright/test/cli')
12
+ const dataParent = resolve(process.env.HAI_E2E_DATA_ROOT || tmpdir())
13
+ mkdirSync(dataParent, { recursive: true })
14
+ const dataRoot = mkdtempSync(join(dataParent, 'hai-browser-e2e-'))
15
+ const groups = [[]]
16
+ for (const argument of process.argv.slice(2)) {
17
+ if (argument === '--next')
18
+ groups.push([])
19
+ else
20
+ groups.at(-1).push(argument)
21
+ }
22
+ let child
23
+ let interrupted = false
24
+ let stopping
25
+ /**
26
+ * 结束本轮 Playwright;Windows 同时结束其进程树,finally 等待该命令退出后才清理数据。
27
+ * @returns {void} 终止请求由 child 退出事件和 stopping Promise 确认。
28
+ * @example 模块内部信号处理
29
+ * ```js
30
+ * process.once('SIGTERM', stop)
31
+ * ```
32
+ */
33
+ function stop() {
34
+ if (interrupted)
35
+ return
36
+ interrupted = true
37
+ if (process.platform === 'win32' && child?.pid && child.exitCode === null) {
38
+ // Windows 的 kill 不传递 SIGTERM;同时结束本次 Playwright 创建的浏览器与服务进程。
39
+ stopping = new Promise((resolve) => {
40
+ const killer = spawn('taskkill', ['/pid', String(child.pid), '/t', '/f'], { windowsHide: true, stdio: 'ignore' })
41
+ killer.once('error', () => {
42
+ child?.kill()
43
+ resolve()
44
+ })
45
+ killer.once('exit', resolve)
46
+ })
47
+ }
48
+ else {
49
+ child?.kill()
50
+ }
51
+ }
52
+ process.once('SIGINT', stop)
53
+ process.once('SIGTERM', stop)
54
+ try {
55
+ // 证据与临时业务数据分开;每组使用独立输出,后续 Playwright 不会清空前组证据。
56
+ const evidenceParent = resolve(process.env.HAI_AUTH_EVIDENCE_DIR || join(cwd, 'test-results'))
57
+ mkdirSync(evidenceParent, { recursive: true })
58
+ const runRoot = mkdtempSync(join(evidenceParent, 'run-'))
59
+ for (const [index, args] of groups.entries()) {
60
+ const groupRoot = join(runRoot, `group-${index + 1}`)
61
+ const groupDataRoot = join(dataRoot, `group-${index + 1}`)
62
+ mkdirSync(groupDataRoot)
63
+ const hasOutput = args.some(argument => argument === '--output' || argument.startsWith('--output='))
64
+ const outputArgs = hasOutput ? [] : ['--output', join(groupRoot, 'results')]
65
+ const html = process.env.PLAYWRIGHT_HTML_OUTPUT_DIR || process.env.PLAYWRIGHT_HTML_REPORT
66
+ const code = await new Promise((resolve, reject) => {
67
+ child = spawn(process.execPath, [cli, 'test', ...args, ...outputArgs], {
68
+ cwd,
69
+ windowsHide: true,
70
+ stdio: 'inherit',
71
+ env: {
72
+ ...process.env,
73
+ ...(!html ? { PLAYWRIGHT_HTML_OUTPUT_DIR: join(groupRoot, 'html') } : {}),
74
+ HAI_AUTH_EVIDENCE_DIR: process.env.HAI_AUTH_EVIDENCE_DIR || join(groupRoot, 'evidence'),
75
+ HAI_E2E_DATA_ROOT: groupDataRoot,
76
+ },
77
+ })
78
+ child.once('error', reject)
79
+ child.once('exit', resolve)
80
+ })
81
+ // 配置组互相独立,普通失败继续收集;保留首个失败码,中断才停止后续组。
82
+ if (code !== 0)
83
+ process.exitCode ||= typeof code === 'number' && code !== 0 ? code : 1
84
+ if (interrupted) {
85
+ process.exitCode ||= 1
86
+ break
87
+ }
88
+ }
89
+ }
90
+ finally {
91
+ process.removeListener('SIGINT', stop)
92
+ process.removeListener('SIGTERM', stop)
93
+ await stopping
94
+ // Playwright 退出后服务进程已关闭,此时删除 SQLite / storage,避免 Windows 文件锁。
95
+ try {
96
+ rmSync(dataRoot, { recursive: true, force: true, maxRetries: 3, retryDelay: 100 })
97
+ }
98
+ catch (error) {
99
+ process.stderr.write(`E2E data cleanup failed: ${error instanceof Error ? error.message : String(error)}\n`)
100
+ // 清理错误不能把原始失败(如 exit 7)覆盖成另一状态,也不能让成功变为假成功。
101
+ if (!process.exitCode)
102
+ process.exitCode = 1
103
+ }
104
+ }
@@ -0,0 +1,56 @@
1
+ /** Vite 开发与预览的公开运行配置;同一份静态构建可连接不同环境的 API。 */
2
+ import type { CoreConfig } from '@h-ai/core'
3
+ import type { IncomingMessage, ServerResponse } from 'node:http'
4
+ import type { Plugin } from 'vite'
5
+
6
+ /** 只允许浏览器可见的地址、开关和品牌字段,禁止传入 process.env 或完整服务配置。 */
7
+ export interface PublicRuntimeConfig {
8
+ /** 包含 API 前缀的公开地址,例如 https://example.test/api/v1。 */
9
+ apiBase?: string
10
+ /** 客户端传输开关,与服务端一致。 */
11
+ apiTransport?: string
12
+ /** 公开密钥交换端点。 */
13
+ apiKeyExchangePath?: string
14
+ /** 客户端公开元数据;不含密钥或连接参数。 */
15
+ core?: Pick<CoreConfig, 'name' | 'version' | 'env' | 'defaultLocale'> & { logging?: Pick<NonNullable<CoreConfig['logging']>, 'level' | 'format'> }
16
+ }
17
+
18
+ /**
19
+ * 在加载应用前提供无缓存的公开配置;构建只复制空的占位文件。
20
+ * @example `plugins: [publicRuntimeConfig({ apiBase: process.env.PUBLIC_API_BASE })]`
21
+ */
22
+ export function publicRuntimeConfig(config: PublicRuntimeConfig): Plugin {
23
+ const metadata = config.core
24
+ // 明确投影字段,JavaScript 调用方即使误传完整配置也不能公开连接参数或密钥。
25
+ const publicConfig: PublicRuntimeConfig = {
26
+ apiBase: config.apiBase,
27
+ apiTransport: config.apiTransport,
28
+ apiKeyExchangePath: config.apiKeyExchangePath,
29
+ core: metadata
30
+ ? {
31
+ name: metadata.name,
32
+ version: metadata.version,
33
+ env: metadata.env,
34
+ defaultLocale: metadata.defaultLocale,
35
+ logging: metadata.logging ? { level: metadata.logging.level, format: metadata.logging.format } : undefined,
36
+ }
37
+ : undefined,
38
+ }
39
+ const body = `globalThis.__HAI_PUBLIC_CONFIG__ = { ...globalThis.__HAI_PUBLIC_CONFIG__, ...${JSON.stringify(publicConfig)} };\n`
40
+ const respond = (_request: IncomingMessage, response: ServerResponse): void => {
41
+ response.setHeader('Content-Type', 'application/javascript; charset=utf-8')
42
+ response.setHeader('Cache-Control', 'no-store')
43
+ response.end(body)
44
+ }
45
+ return {
46
+ name: 'hai-public-runtime-config',
47
+ configureServer(server) {
48
+ const base = server.config.base.startsWith('/') ? server.config.base : '/'
49
+ server.middlewares.use(`${base}runtime-config.js`, respond)
50
+ },
51
+ configurePreviewServer(server) {
52
+ const base = server.config.base.startsWith('/') ? server.config.base : '/'
53
+ server.middlewares.use(`${base}runtime-config.js`, respond)
54
+ },
55
+ }
56
+ }
@@ -1,26 +1,85 @@
1
1
  # AGENTS.md
2
2
 
3
- > 通用 AI 编程助手指引。详细 Skill 文件位于 `.agents/skills/` 目录。
3
+ > 通用 AI 编程助手入口。优先阅读 `README.md`、现有测试与 `.agents/skills/`;本文件同时作为 `hai add` / AI 支持回填时的 generic fallback。
4
+
5
+ ## 需求与模板
6
+
7
+ - 业务行为以用户当前明确要求及其指定的需求/设计文档为准。本文件、README、skills、示例、生成代码及其测试中的模板默认行为是起点,不是不可变的业务约束;角色代码、权限模型、页面流程、字段、限额、存储方式与架构均可按实际需求调整。
8
+ - 需求与模板不同,审查时记录为模板适配项,不据此判定需求错误或阻塞审查,也不要求用户额外授权“覆盖模板”;实施时在已有授权范围内修改或移除冲突逻辑,并同步 contract、鉴权、数据迁移、界面、配置、测试、文档及本文件中的过期规则。
9
+ - 未说明的行为可参考现有实现并注明假设,不能升级为强制需求。只有业务要求自身矛盾、与已确认项目决策的优先级不明,或存在真实技术/安全障碍时才提出具体问题;已明确的规则不重复要求选择。
10
+ - 业务规则与技术契约分别判断:可用 API 以当前安装版本的公开类型为准;输入校验、服务端授权、资源隔离和密钥保护仍须落实。需求涉及替换技术方案时说明影响并同步迁移,不能用保留模板默认值代替解决问题。
11
+
12
+ ## 行为契约
13
+
14
+ 涉及框架数据结构、配置、核心流程或模块边界的新增、修改、删除,先读 [变更影响与方案确认](.agents/skills/hai-change-plan/SKILL.md),说明实际影响并等待用户决定。已有具体确认不重复要求;普通应用私有实现按当前业务授权执行。确认后的变更成套更新文档、配置、网站内容源、注释、模板与调用方。
15
+
16
+ 需求/设计文档审查或从文档生成代码时,读取 [hai-spec-review](.agents/skills/hai-spec-review/SKILL.md),严格确认完备性、歧义、技术正确性与命名一致性;影响行为的问题未解决前不判定文档可生成。普通小改动不重审无关文档。
17
+
18
+ 升级 hai-framework 到最新/指定版本、比较版本差异或同步框架 skills 时,先读 [框架升级与同步 Skill](.agents/skills/hai-framework-sync/SKILL.md),执行版本发现、差异分析、用户选择/阻塞处理、迁移与验证;仅要求比较时不修改应用。
19
+
20
+ 根据文档规划、实施、继续、返修或按已提交文档变更同步实现时,读取 [hai-spec-implement](.agents/skills/hai-spec-implement/SKILL.md):维护 docs 清单与任务记录,比较已验收与目标文档 Git 快照,更新原任务或新建任务,每项独立分支 TDD、验证并本地合并;全部差异与整体验收通过后才推进基线。返修复用原任务与分支。仅规划不实施,指定任务先核验依赖。
21
+
22
+ 普通新增、修改、修复任务开始前,先读 [应用开发 Skill](.agents/skills/hai-app-create/SKILL.md) 和 [开发规范与框架能力路由](.agents/skills/hai-app-create/development.md);再按任务读取模块 Skill 及其相邻参考文件。架构/构建、审查、测试分别读取 hai-build、hai-app-review、hai-app-tests,不加载整个 skill 树。
23
+
24
+ - 对当前需求逐项检索 hai-framework 能力和已有实现,确认适用的公开 API 后优先复用;未安装模块先核对依赖与配置,不能因 Skill 已存在就假定已启用。框架不适用时说明具体限制与选用方案,不为覆盖清单引入无关模块。
25
+ - 按已安装版本的公开类型确认模块契约:生命周期模块按 init → use → close;core/serv/kit、纯函数/工厂与流按实际签名处理。返回 HaiResult 的操作先检查 success,不以 try/catch 代替判断;事务失败明确触发回滚。
26
+ - 边界输入做 schema 校验,服务端验证身份、租户与资源权限;SQL 动态值参数化,文件路径防逃逸。密钥不进入 PUBLIC_/VITE_ 变量、客户端代码和日志;敏感 token 不写 localStorage。
27
+ - 禁止 any、无说明的 as unknown as、console.log 和硬编码密钥;从包公开入口导入。注释中文、结构化日志英文并脱敏,用户文本走现有 i18n 并同步所有 locale。
28
+ - 完成时说明实际复用的框架能力、未采用的相关能力及原因、门禁结果;跨边界同步类型、配置、调用方、文档和测试。
29
+
30
+ 先读 README、package.json、相关实现/测试和所需 .agents/skills;不要加载整个 skill 树。新增抽象前确认复用路径与真实需求;保留用户改动。跨文件任务简述影响和验证计划,无须固定规模标签或重复问卷。
31
+
32
+ - 直接影响:修改 / 新建 / 删除哪些文件;哪些脚本、类型、配置或路由会变。
33
+ - 间接影响:哪些测试、README、i18n、示例、共享类型、依赖方需要同步更新。
4
34
 
5
35
  ## 项目概述
6
36
 
7
- 本项目使用 hai-framework 构建,基于 SvelteKit 2 + Svelte 5 (Runes) + TailwindCSS 4 + DaisyUI 5 + TypeScript 5.7+。
37
+ 本项目由 hai-framework CLI 生成。单应用工程通常在 `src/` 下开发;多包工程会同时包含 `packages/*` 与 `apps/*`。实际结构以当前项目目录为准。
38
+
39
+ 如项目使用 SvelteKit,`+server.ts` 只能导出 HTTP handler 与 SvelteKit 允许的配置项;辅助函数放到 `src/lib/**`。
40
+
41
+ ## 工作流程
42
+
43
+ 开发、审查、测试和排错先读[沟通与同步维护](.agents/skills/hai-app-create/collaboration.md):结论优先,区分发现与待验证、计划与完成;按实际影响检查使用文档、配置示例、截图、测试、CLI 模板和调用方。每批说明解决什么、使用变化、验证及剩余问题。
44
+
45
+ 1. 先搜索现有实现、引用点、测试和 README。
46
+ 2. 小步修改,优先保持目录结构、公开 API 和脚本稳定。
47
+ 3. 改动公共类型、配置、模板或共享逻辑时,同步更新所有调用方与文档。
48
+ 4. 一轮修改完成后按影响范围收集全部可执行门禁结果,汇总问题再集中修复、复测;普通失败不立即从头重跑。
49
+
50
+ ## 代码注释与示例
51
+
52
+ - 尽可能补充有信息量的中文 JSDoc:所有 export 的函数/类/方法、核心算法与业务流程、所有数据库表/列、接口/type/schema 及其字段都必须说明用途、单位、约束和关联关系。核心逻辑解释决策原因、边界、权限与失败路径,不逐行复述代码。
53
+ - 函数按实际契约写 @param、@returns,仅确实抛错时写 @throws;异步、HaiResult 与事务失败行为须说明。类型/表结构说明字段含义、可空性、默认值、主外键和唯一约束。
54
+ - 上述函数和结构的 JSDoc 均提供可理解的 @example:函数给调用及结果判断,结构给合法数据,表给典型行或查询示例。省略上下文要标明,不使用真实凭据。示例随实现同步,不能只堆叠没有信息量的注释。
55
+ - 调用及结构示例见 [.agents/skills/hai-app-create/development.md](.agents/skills/hai-app-create/development.md) 的 JSDoc 注释一节。
56
+
57
+ ## 质量门禁
58
+
59
+ AI 先分析差异、调用方和受影响流程,默认只选择相关 test/E2E 与必要门禁,用户明确要求时才全量。核对 package.json,按 [分轮验证与集中修复](.agents/skills/hai-app-tests/validation.md) 收集所选检查与日志,再归并修复、复测失败及受影响项;普通失败不中断独立检查,真实前置阻塞才暂停依赖项。文档检查引用,UI/路由变更加相关 E2E,未运行项说明原因。
60
+
61
+ ```bash
62
+ pnpm typecheck
63
+ pnpm lint
64
+ pnpm build
65
+ pnpm test
66
+ pnpm test:e2e
67
+ ```
68
+
69
+ ## 完成条件
8
70
 
9
- ## 核心规范
71
+ - typecheck / lint / build / test / test:e2e 状态明确;整轮收集后集中修复,最终必需门禁对最终代码有效通过,未执行或阻塞明确原因,不能宣称完成。
72
+ - README、i18n、测试、代码注释与实现保持一致。
73
+ - 最终回复说明执行过的门禁、已同步的文档 / 依赖方,以及未完成项。
10
74
 
11
- - 统一模式:`module.init(config) → use → module.close()`,所有操作返回 `HaiResult<T>`
12
- - **TDD 驱动开发**:先写测试(Red)→ 确认失败 → 再实现(Green)→ 确认通过 → 重构(Refactor)
13
- - 禁止 `any`(使用 `unknown` + 缩窄),禁止 `console.log`(使用 `core.logger`)
14
- - 用户可见文本走 i18n,代码注释中文,日志英文
15
- - HaiResult 错误直接透传,不重新包装
16
- - 框架模块公共 API 不抛异常,统一返回 `HaiResult<T>`;不要用 `try/catch` 处理模块返回的错误
17
- - 质量门禁:`pnpm typecheck && pnpm lint && pnpm test && pnpm --filter <app> test:e2e`
75
+ ## Skills 路由
18
76
 
19
- ## Skills 参考
77
+ - `.agents/skills/hai-build/SKILL.md`:架构、构建和质量门禁。
78
+ - `.agents/skills/hai-app-create/SKILL.md`:应用骨架、路由、页面与 API 模板。
79
+ - `.agents/skills/hai-app-review/SKILL.md`:应用代码审查。
80
+ - `.agents/skills/hai-app-tests/SKILL.md`:Vitest / Playwright 测试策略。
81
+ - 具体模块按需读取对应 `hai-*` Skill。
20
82
 
21
- 所有详细指南位于 `.agents/skills/` 目录,按需阅读:
83
+ 前端项目已交付对应技能时,先按 hai-ui-design 确定任务、布局、状态与组件映射,使用 hai-ui 实现,再由 hai-ui-review 检查真实页面。窄范围修改复用已有设计;按实际语言/主题/尺寸验证。
22
84
 
23
- - **入口**:`hai-build/SKILL.md` — 项目架构总览与 Skill 导航
24
- - **框架模块**:`hai-core/`、`hai-kit/`、`hai-reldb/`、`hai-iam/`、`hai-crypto/`、`hai-cache/`、`hai-storage/`、`hai-ai/`
25
- - **UI 组件**:`hai-ui/SKILL.md`
26
- - **TDD 开发流程**:`hai-app-tests/`(TDD 测试先行)、`hai-app-create/`(TDD 实现)、`hai-app-review/`(TDD 重构审查)
85
+ 工作流技能按 hai-领域-动作 命名,能力使用类沿用领域名。需求、验收、发现与当前版本证据按 [工作交接契约](.agents/skills/hai-spec-implement/handoff.md) 传递,沿既有清单恢复任务。
@@ -1,12 +1 @@
1
- # CLAUDE.md
2
-
3
1
  @AGENTS.md
4
-
5
- > Claude Code 项目指引。共享规范通过 `@AGENTS.md` 复用;共享参考资料位于 `.agents/skills/` 目录。
6
-
7
- ## 使用说明
8
-
9
- - 本文件是 Claude Code 的原生项目级指引入口。
10
- - 项目概述、核心规范与工作流约定统一维护在 `AGENTS.md`;Claude Code 通过 `@AGENTS.md` 复用这些共享规范,避免双份文档漂移。
11
- - 共享的模块与工作流参考资料维护在 `.agents/skills/` 中;需要具体用法时,可按路径阅读对应 `SKILL.md`。
12
- - 当前模板为了保持单一 Skill 树,不额外生成 `.claude/skills/`;如需 Claude Code 的原生 project skills 自动发现,需要单独维护该目录。