@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
@@ -0,0 +1,614 @@
1
+ import type { IamListUsersInput, IamPublicConfig } from '@h-ai/api-contract'
2
+ import type { HaiResult } from '@h-ai/core'
3
+ import type { ChangePasswordFormData, UserProfileSubmitData } from '@h-ai/ui'
4
+ import type { AdminAuditLog, AdminCreateUser, AdminInviteUser, AdminPermissionPolicy, AdminRole, AdminUpdateUser, AdminUser, AuditBackupReceipt, AvatarUpload, ProfileUpdate } from '{{fullstack.contractPackageName}}'
5
+ import type { AppInfo, ManagementApiOptions } from '../api/api-client.js'
6
+ import type { HashRouter } from '../navigation/hash-router.svelte.js'
7
+ import { HaiApiClientError } from '@h-ai/api-client'
8
+ import { IamSessionErrorCodeSchema } from '@h-ai/api-contract'
9
+ import { core, err, HaiCommonError, ok } from '@h-ai/core'
10
+ import { authErrorMessage, matchPermission } from '@h-ai/ui/components/scenes/iam/index'
11
+ import { setGlobalLocale } from '@h-ai/ui/i18n'
12
+ import { toast } from '@h-ai/ui/toast'
13
+ import { SvelteDate } from 'svelte/reactivity'
14
+ import { initializeManagementApi, managementApi, resolveAvatarUrl } from '../api/api-client.js'
15
+ import { requestSensitive } from '../api/sensitive-actions.svelte.js'
16
+ import * as m from '../paraglide/messages.js'
17
+ import { getLocale, locales, setLocale } from '../paraglide/runtime.js'
18
+ import { AVAILABLE_THEMES, DEFAULT_THEME, themeStore } from './theme-store.svelte.js'
19
+
20
+ type ResultData<T> = T extends { success: true, data: infer D } ? D : never
21
+ export type CurrentUser = ResultData<Awaited<ReturnType<typeof managementApi.iam.auth.currentUser>>>
22
+ /** 页面目录对应的相对路径;例如 `reports/weekly`,新增页面无需修改类型或路由表。 */
23
+ export type ManagementPage = string
24
+
25
+ /** 页面状态和业务操作在共享 store 中收敛,宿主端仅装配平台能力。 */
26
+ export class ManagementStore {
27
+ /**
28
+ * 绑定当前工作区的页面路由;服务端继续验证各 API 的权限。
29
+ * @example new ManagementStore(new HashRouter(Object.keys(pages), '/users'))
30
+ */
31
+ constructor(router: HashRouter) {
32
+ this.router = router
33
+ }
34
+
35
+ private readonly router: HashRouter
36
+ info = $state<AppInfo | null>(null)
37
+ authConfig = $state<IamPublicConfig | null>(null)
38
+ user = $state<CurrentUser | null>(null)
39
+ page = $state<ManagementPage>('settings')
40
+ locale = $state(getLocale())
41
+ initializing = $state(true)
42
+ loading = $state(false)
43
+ saving = $state(false)
44
+ error = $state('')
45
+ users = $state<AdminUser[]>([])
46
+ usersTotal = $state(0)
47
+ usersPage = $state(1)
48
+ usersSearch = $state('')
49
+ usersStatus = $state<'all' | AdminUser['accountStatus']>('all')
50
+ usersSortBy = $state<NonNullable<IamListUsersInput['sortBy']>>('createdAt')
51
+ usersSortDirection = $state<'asc' | 'desc'>('desc')
52
+ private appliedUsersQuery: Partial<Pick<Parameters<typeof managementApi.admin.users.list>[0], 'search' | 'accountStatus'>> = {}
53
+ private appliedAuditQuery: Partial<Parameters<typeof managementApi.admin.audit.list>[0]> = {}
54
+ roles = $state<AdminRole[]>([])
55
+ permissionPolicies = $state<AdminPermissionPolicy[]>([])
56
+ permissionPolicyPage = $state(1)
57
+ permissionPolicyTotal = $state(0)
58
+ audit = $state<AdminAuditLog[]>([])
59
+ auditTotal = $state(0)
60
+ auditPage = $state(1)
61
+ businessNotice = $state('')
62
+ auditCategory = $state<'system' | 'business' | ''>('')
63
+ auditOutcome = $state<'success' | 'failure' | 'denied' | ''>('')
64
+ auditSeverity = $state<'info' | 'warning' | 'error' | 'critical' | ''>('')
65
+ auditSortBy = $state<'createdAt' | 'action' | 'resource' | 'category' | 'outcome' | 'severity'>('createdAt')
66
+ auditSortDirection = $state<'asc' | 'desc'>('desc')
67
+ auditStats = $state<{ action: string, count: number }[]>([])
68
+ auditBackupEnabled = $state(false)
69
+ auditBackupReceipt = $state<AuditBackupReceipt | null>(null)
70
+ private auditBackupId = ''
71
+ auditAction = $state('')
72
+ auditResource = $state('')
73
+ auditStartDate = $state('')
74
+ auditEndDate = $state('')
75
+ readonly pageSize = 20
76
+ private requestVersion = 0
77
+ private sessionEpoch = 0
78
+ private onLocaleChange?: (locale: string) => void
79
+
80
+ localDateTime(value: string): string {
81
+ const date = new SvelteDate(value)
82
+ date.setMinutes(date.getMinutes() - date.getTimezoneOffset())
83
+ return date.toISOString().slice(0, 16)
84
+ }
85
+
86
+ hasPermission(permission: string): boolean {
87
+ return matchPermission(permission, this.user?.permissions ?? [])
88
+ }
89
+
90
+ canOpenPage(page: string): boolean {
91
+ const permissions: Record<string, string> = { users: 'app.users.manage', roles: 'app.roles.manage', audit: 'audit:read', configuration: 'app.config.manage', feedback: 'feedback:read' }
92
+ return !permissions[page] || this.hasPermission(permissions[page])
93
+ }
94
+
95
+ async initialize(options: ManagementApiOptions, onLocaleChange?: (locale: string) => void): Promise<void> {
96
+ this.onLocaleChange = onLocaleChange
97
+ this.initializing = true
98
+ this.error = ''
99
+ try {
100
+ const init = await initializeManagementApi({ ...options, onSessionExpired: () => this.expireSession() })
101
+ if (!init.success) {
102
+ this.error = init.error.code === HaiApiClientError.CONFIG_ERROR.code ? m.api_not_configured() : m.home_error()
103
+ return
104
+ }
105
+ const info = await managementApi.app.info()
106
+ if (!info.success) {
107
+ this.error = info.error.httpStatus === 400 ? info.error.message : m.home_error()
108
+ return
109
+ }
110
+ this.info = info.data
111
+ const authConfig = await managementApi.iam.auth.publicConfig()
112
+ if (!authConfig.success) {
113
+ this.error = authConfig.error.message
114
+ return
115
+ }
116
+ this.authConfig = authConfig.data
117
+ this.applyLocale(info.data.defaultLocale)
118
+ // 默认 Cookie 存储通过 api-client 的加密刷新链路恢复会话。
119
+ const me = await managementApi.iam.auth.currentUser()
120
+ if (me.success) {
121
+ this.setUser(me.data)
122
+ await this.navigate(this.router.path.slice(1))
123
+ }
124
+ else if (me.error.httpStatus !== 401) {
125
+ this.error = me.error.httpStatus === 400 ? me.error.message : m.operation_failed()
126
+ }
127
+ }
128
+ catch {
129
+ this.error = m.home_error()
130
+ }
131
+ finally {
132
+ this.initializing = false
133
+ }
134
+ }
135
+
136
+ async close(): Promise<void> {
137
+ this.requestVersion++
138
+ this.sessionEpoch++
139
+ this.loading = false
140
+ await managementApi.close()
141
+ }
142
+
143
+ async authenticated(): Promise<void> {
144
+ const me = await this.request(() => managementApi.iam.auth.currentUser())
145
+ if (!me?.success)
146
+ return
147
+ this.setUser(me.data)
148
+ await this.navigate(this.router.path.slice(1))
149
+ }
150
+
151
+ async logout(): Promise<void> {
152
+ await this.mutate(async () => {
153
+ const result = await this.request(() => managementApi.iam.auth.logout({}))
154
+ if (!result?.success)
155
+ return
156
+ await managementApi.auth.clear()
157
+ this.clearSession()
158
+ })
159
+ }
160
+
161
+ async navigate(page: ManagementPage): Promise<void> {
162
+ if (!this.user)
163
+ return
164
+ this.requestVersion++
165
+ this.loading = false
166
+ this.page = this.canOpenPage(page) ? page : 'settings'
167
+ if (this.router.path !== `/${this.page}`)
168
+ this.router.navigate(`/${this.page}`)
169
+ this.page = this.router.path.slice(1)
170
+ this.error = ''
171
+ if (this.page === 'users')
172
+ await this.loadUsers()
173
+ else if (this.page === 'roles')
174
+ await this.loadRoles()
175
+ else if (this.page === 'audit')
176
+ await this.loadAudit()
177
+ else if (this.page === 'configuration')
178
+ await this.loadConfiguration()
179
+ }
180
+
181
+ async loadConfiguration(): Promise<void> {
182
+ await this.load(async (version) => {
183
+ const result = await this.request(() => managementApi.admin.configuration.get(), version)
184
+ if (result?.success && version === this.requestVersion)
185
+ this.businessNotice = result.data.notice
186
+ })
187
+ }
188
+
189
+ async saveConfiguration(): Promise<void> {
190
+ await this.mutate(async () => {
191
+ const result = await this.request(() => requestSensitive('business.settings.update', options => managementApi.admin.configuration.update({ notice: this.businessNotice }, options)))
192
+ if (result?.success && this.info) {
193
+ this.info = { ...this.info, notice: result.data.notice }
194
+ toast.add({ 'message': m.saved(), 'variant': 'success', 'data-testid': 'notice' })
195
+ }
196
+ })
197
+ }
198
+
199
+ async queryUsers(): Promise<void> {
200
+ this.appliedUsersQuery = { search: this.usersSearch.trim() || undefined, accountStatus: this.usersStatus === 'all' ? undefined : this.usersStatus }
201
+ await this.loadUsers()
202
+ }
203
+
204
+ async sortUsers(key: string, direction: 'asc' | 'desc'): Promise<void> {
205
+ const field = (['username', 'email', 'accountStatus', 'createdAt'] as const).find(field => field === key)
206
+ if (!field)
207
+ return
208
+ this.usersSortBy = field
209
+ this.usersSortDirection = direction
210
+ await this.loadUsers()
211
+ }
212
+
213
+ async loadUsers(page = 1): Promise<void> {
214
+ await this.load(async (version) => {
215
+ const result = await this.request(() => managementApi.admin.users.list({
216
+ page,
217
+ pageSize: this.pageSize,
218
+ ...this.appliedUsersQuery,
219
+ sortBy: this.usersSortBy,
220
+ sortDirection: this.usersSortDirection,
221
+ }), version)
222
+ if (result?.success && version === this.requestVersion) {
223
+ this.users = result.data.items.map(user => ({ ...user, avatarUrl: resolveAvatarUrl(user.avatarUrl) }))
224
+ this.usersTotal = result.data.total
225
+ this.usersPage = result.data.page
226
+ }
227
+ })
228
+ }
229
+
230
+ async loadRoles(): Promise<void> {
231
+ await this.load(async (version) => {
232
+ const result = await this.request(() => managementApi.admin.roles.list(), version)
233
+ if (result?.success && version === this.requestVersion)
234
+ this.roles = result.data.items
235
+ if (this.authConfig?.reauthentication?.enabled)
236
+ await this.loadPermissionPolicies()
237
+ })
238
+ }
239
+
240
+ async loadPermissionPolicies(page = 1): Promise<void> {
241
+ const result = await this.request(() => managementApi.admin.permissions.list({ page, pageSize: this.pageSize }))
242
+ if (result?.success) {
243
+ this.permissionPolicies = result.data.items
244
+ this.permissionPolicyPage = page
245
+ this.permissionPolicyTotal = result.data.total
246
+ }
247
+ }
248
+
249
+ async savePermissionPolicy(id: string, operations: string[]): Promise<HaiResult<void>> {
250
+ if (this.saving)
251
+ return err(HaiCommonError.CONFLICT, m.operation_failed())
252
+ this.saving = true
253
+ this.error = ''
254
+ try {
255
+ // 表单持有本次保存失败;根布局只报告列表和配置刷新的独立失败,避免重复通知。
256
+ const result = await requestSensitive('iam.permissions.sensitiveOperations', options => managementApi.admin.permissions.update({ id, sensitiveOperations: operations }, options))
257
+ if (!result.success)
258
+ return result
259
+ await this.loadPermissionPolicies(this.permissionPolicyPage)
260
+ const config = await this.request(() => managementApi.iam.auth.publicConfig())
261
+ if (config?.success)
262
+ this.authConfig = config.data
263
+ return ok(undefined)
264
+ }
265
+ catch {
266
+ return err(HaiCommonError.SERVICE_UNAVAILABLE, m.network_error())
267
+ }
268
+ finally {
269
+ this.saving = false
270
+ }
271
+ }
272
+
273
+ async queryAudit(): Promise<void> {
274
+ if (this.auditStartDate && this.auditEndDate && this.auditStartDate > this.auditEndDate) {
275
+ this.error = m.audit_date_invalid()
276
+ return
277
+ }
278
+ this.appliedAuditQuery = {
279
+ category: this.auditCategory || undefined,
280
+ outcome: this.auditOutcome || undefined,
281
+ severity: this.auditSeverity || undefined,
282
+ action: this.auditAction.trim() || undefined,
283
+ resource: this.auditResource.trim() || undefined,
284
+ startDate: this.auditStartDate ? new SvelteDate(`${this.auditStartDate}T00:00:00`).toISOString() : undefined,
285
+ endDate: this.auditEndDate ? new SvelteDate(`${this.auditEndDate}T23:59:59.999`).toISOString() : undefined,
286
+ }
287
+ await this.loadAudit()
288
+ }
289
+
290
+ async sortAudit(key: string, direction: 'asc' | 'desc'): Promise<void> {
291
+ const field = (['createdAt', 'action', 'resource', 'category', 'outcome', 'severity'] as const).find(field => field === key)
292
+ if (!field)
293
+ return
294
+ this.auditSortBy = field
295
+ this.auditSortDirection = direction
296
+ await this.loadAudit()
297
+ }
298
+
299
+ async loadAudit(page = 1): Promise<void> {
300
+ await this.load(async (version) => {
301
+ const result = await this.request(() => managementApi.admin.audit.list({
302
+ ...this.appliedAuditQuery,
303
+ page,
304
+ pageSize: this.pageSize,
305
+ sortBy: this.auditSortBy,
306
+ sortDirection: this.auditSortDirection,
307
+ }), version)
308
+ if (result?.success && version === this.requestVersion) {
309
+ this.auditStats = result.data.stats
310
+ this.auditBackupEnabled = result.data.backupEnabled
311
+ this.audit = result.data.items
312
+ this.auditTotal = result.data.total
313
+ this.auditPage = result.data.page
314
+ }
315
+ })
316
+ }
317
+
318
+ async backupAudit(): Promise<void> {
319
+ await this.mutate(async () => {
320
+ this.auditBackupId ||= crypto.randomUUID()
321
+ const id = this.auditBackupId
322
+ const result = await this.request(() => requestSensitive('audit.backup', options => managementApi.admin.audit.backup({ id }, options)))
323
+ if (!result?.success) {
324
+ this.error = `${this.error} ${m.audit_backup_retry_hint()}`
325
+ return
326
+ }
327
+ this.auditBackupReceipt = result.data
328
+ this.auditBackupId = ''
329
+ toast.add({ 'message': m.audit_backup_private_hint(), 'variant': 'success', 'data-testid': 'notice' })
330
+ })
331
+ }
332
+
333
+ async saveUser(data: AdminCreateUser | AdminUpdateUser): Promise<boolean> {
334
+ let saved = false
335
+ await this.mutate(async () => {
336
+ const result = 'id' in data
337
+ ? await this.request(() => requestSensitive('iam.users.update', options => managementApi.admin.users.update(data, options)))
338
+ : await this.request(() => requestSensitive('iam.users.create', options => managementApi.admin.users.create(data, options)))
339
+ if (!result?.success)
340
+ return
341
+ saved = true
342
+ await this.loadUsers(this.usersPage)
343
+ toast.add({ 'message': m.saved(), 'variant': 'success', 'data-testid': 'notice' })
344
+ })
345
+ return saved
346
+ }
347
+
348
+ async inviteUser(data: AdminInviteUser): Promise<boolean> {
349
+ let invited = false
350
+ await this.mutate(async () => {
351
+ const result = await this.request(() => requestSensitive('iam.users.invite', options => managementApi.admin.users.invite(data, options)))
352
+ const failure = this.error
353
+ await this.loadUsers()
354
+ if (!result?.success) {
355
+ this.error = `${failure} ${m.invitation_check_existing()}`
356
+ return
357
+ }
358
+ invited = true
359
+ toast.add({ 'message': m.saved(), 'variant': 'success', 'data-testid': 'notice' })
360
+ })
361
+ return invited
362
+ }
363
+
364
+ async deleteUser(user: AdminUser): Promise<boolean> {
365
+ let deleted = false
366
+ await this.mutate(async () => {
367
+ const result = await this.request(() => requestSensitive('iam.users.delete', options => managementApi.admin.users.delete({ id: user.id }, options)))
368
+ if (!result?.success)
369
+ return
370
+ deleted = true
371
+ const page = this.users.length === 1 ? Math.max(1, this.usersPage - 1) : this.usersPage
372
+ await this.loadUsers(page)
373
+ toast.add({ 'message': m.user_deleted(), 'variant': 'success', 'data-testid': 'notice' })
374
+ })
375
+ return deleted
376
+ }
377
+
378
+ async resetUserPassword(user: AdminUser, newPassword: string): Promise<boolean> {
379
+ let reset = false
380
+ await this.mutate(async () => {
381
+ const result = await this.request(() => requestSensitive('iam.users.resetPassword', options => managementApi.admin.users.resetPassword({ id: user.id, newPassword }, options)))
382
+ if (!result?.success)
383
+ return
384
+ reset = true
385
+ if (user.id === this.user?.id) {
386
+ await managementApi.auth.clear()
387
+ this.clearSession()
388
+ }
389
+ toast.add({ 'message': m.user_password_reset_done(), 'variant': 'success', 'data-testid': 'notice' })
390
+ })
391
+ return reset
392
+ }
393
+
394
+ async saveRole(id: string, description: string): Promise<boolean> {
395
+ let saved = false
396
+ await this.mutate(async () => {
397
+ const result = await this.request(() => requestSensitive('iam.roles.update', options => managementApi.admin.roles.update({ id, description }, options)))
398
+ if (!result?.success)
399
+ return
400
+ saved = true
401
+ await this.loadRoles()
402
+ toast.add({ 'message': m.saved(), 'variant': 'success', 'data-testid': 'notice' })
403
+ })
404
+ return saved
405
+ }
406
+
407
+ async saveProfile(data: UserProfileSubmitData): Promise<void> {
408
+ await this.savePreferences({ displayName: data.displayName?.trim() ?? '', email: data.email?.trim() ?? '' })
409
+ }
410
+
411
+ async savePreferences(data: ProfileUpdate): Promise<void> {
412
+ await this.mutate(async () => {
413
+ const result = await this.request(() => requestSensitive('iam.profile.update', options => managementApi.profile.update(data, options)))
414
+ if (!result?.success)
415
+ return
416
+ const me = await this.request(() => managementApi.iam.auth.currentUser())
417
+ if (me?.success)
418
+ this.setUser(me.data)
419
+ toast.add({ 'message': m.saved(), 'variant': 'success', 'data-testid': 'notice' })
420
+ })
421
+ }
422
+
423
+ async changePassword(data: ChangePasswordFormData): Promise<void> {
424
+ await this.mutate(async () => {
425
+ if (!data.oldPassword) {
426
+ this.error = m.password_current_required()
427
+ return
428
+ }
429
+ if (!data.newPassword || data.newPassword !== data.confirmPassword) {
430
+ this.error = m.password_confirmation_mismatch()
431
+ return
432
+ }
433
+ const oldPassword = data.oldPassword
434
+ const result = await this.request(() => managementApi.iam.auth.changePassword({ oldPassword, newPassword: data.newPassword }))
435
+ if (!result?.success) {
436
+ if (result)
437
+ this.error = authErrorMessage(result.error)
438
+ return
439
+ }
440
+ await managementApi.auth.clear()
441
+ this.clearSession()
442
+ toast.add({ 'message': m.password_changed(), 'variant': 'success', 'data-testid': 'notice' })
443
+ })
444
+ }
445
+
446
+ async uploadAvatar(file: File, userId?: string): Promise<void> {
447
+ await this.mutate(async () => {
448
+ const payload = await this.readAvatar(file)
449
+ if (!payload)
450
+ return
451
+ const result = userId
452
+ ? await this.request(() => requestSensitive('iam.users.avatar', options => managementApi.admin.users.avatar({ id: userId, ...payload }, options)))
453
+ : await this.request(() => requestSensitive('iam.profile.avatar', options => managementApi.profile.avatar(payload, options)))
454
+ if (!result?.success)
455
+ return
456
+ if (!userId || userId === this.user?.id) {
457
+ const me = await this.request(() => managementApi.iam.auth.currentUser())
458
+ if (me?.success)
459
+ this.setUser(me.data)
460
+ }
461
+ if (userId)
462
+ await this.loadUsers(this.usersPage)
463
+ toast.add({ 'message': m.avatar_saved(), 'variant': 'success', 'data-testid': 'notice' })
464
+ })
465
+ }
466
+
467
+ formatDate(value: string): string {
468
+ return new Intl.DateTimeFormat(this.locale, { dateStyle: 'medium', timeStyle: 'short' }).format(new SvelteDate(value))
469
+ }
470
+
471
+ private async readAvatar(file: File): Promise<AvatarUpload | undefined> {
472
+ if (file.size > 512 * 1024 || !['image/png', 'image/jpeg', 'image/webp'].includes(file.type)) {
473
+ this.error = m.avatar_invalid()
474
+ return undefined
475
+ }
476
+ const bytes = new Uint8Array(await file.arrayBuffer())
477
+ let binary = ''
478
+ for (const byte of bytes)
479
+ binary += String.fromCharCode(byte)
480
+ return { contentType: file.type as AvatarUpload['contentType'], base64: btoa(binary) }
481
+ }
482
+
483
+ private setUser(user: CurrentUser): void {
484
+ if (this.user?.id !== user.id)
485
+ this.sessionEpoch++
486
+ this.user = { ...user, avatarUrl: resolveAvatarUrl(user.avatarUrl) }
487
+ if (!this.hasPermission('app.users.manage')) {
488
+ this.users = []
489
+ this.usersTotal = 0
490
+ this.usersPage = 1
491
+ this.appliedUsersQuery = {}
492
+ }
493
+ if (!this.hasPermission('app.roles.manage'))
494
+ this.roles = []
495
+ if (!this.hasPermission('audit:read')) {
496
+ this.audit = []
497
+ this.auditTotal = 0
498
+ this.auditPage = 1
499
+ this.appliedAuditQuery = {}
500
+ this.auditStats = []
501
+ this.auditBackupEnabled = false
502
+ }
503
+ if (!this.hasPermission('audit:backup')) {
504
+ this.auditBackupReceipt = null
505
+ this.auditBackupId = ''
506
+ }
507
+ this.applyLocale(typeof user.metadata?.locale === 'string' ? user.metadata.locale : this.info?.defaultLocale ?? getLocale())
508
+ if (typeof user.metadata?.theme === 'string' && AVAILABLE_THEMES.includes(user.metadata.theme))
509
+ themeStore.set(user.metadata.theme)
510
+ else
511
+ themeStore.set(DEFAULT_THEME)
512
+ }
513
+
514
+ private applyLocale(value: string): void {
515
+ const locale = locales.find(locale => locale === value)
516
+ if (!locale)
517
+ return
518
+ this.locale = locale
519
+ setLocale(locale, { reload: false })
520
+ setGlobalLocale(locale)
521
+ if (typeof document !== 'undefined')
522
+ document.documentElement.lang = locale
523
+ this.onLocaleChange?.(locale)
524
+ }
525
+
526
+ private clearSession(): void {
527
+ this.requestVersion++
528
+ this.sessionEpoch++
529
+ this.loading = false
530
+ this.user = null
531
+ this.users = []
532
+ this.roles = []
533
+ this.audit = []
534
+ this.auditStats = []
535
+ this.auditBackupEnabled = false
536
+ this.auditBackupReceipt = null
537
+ this.auditBackupId = ''
538
+ this.page = 'settings'
539
+ }
540
+
541
+ private expireSession(): void {
542
+ if (!this.user)
543
+ return
544
+ // 原地登录取消时保留页面和输入;显式退出仍由logout清空会话与页面。
545
+ this.error = m.session_expired()
546
+ }
547
+
548
+ private async request<T>(task: () => Promise<HaiResult<T>>, version?: number): Promise<HaiResult<T> | undefined> {
549
+ const epoch = this.sessionEpoch
550
+ const isCurrent = () => epoch === this.sessionEpoch && (version === undefined || version === this.requestVersion)
551
+ try {
552
+ const result = await task()
553
+ if (!isCurrent())
554
+ return undefined
555
+ if (!result.success) {
556
+ if (result.error.code === HaiCommonError.REQUEST_ACCESS_DENIED.code) {
557
+ this.error = authErrorMessage(result.error)
558
+ }
559
+ else if (result.error.httpStatus === 401 && this.user && (typeof result.error.code !== 'string' || !result.error.code.startsWith('hai:iam:') || IamSessionErrorCodeSchema.safeParse(result.error.code).success)) {
560
+ this.expireSession()
561
+ }
562
+ else if (result.error.httpStatus === 403 && this.user) {
563
+ const current = await managementApi.iam.auth.currentUser()
564
+ if (!isCurrent())
565
+ return undefined
566
+ if (current.success) {
567
+ this.setUser(current.data)
568
+ if (!this.canOpenPage(this.page)) {
569
+ this.requestVersion++
570
+ this.loading = false
571
+ this.page = 'settings'
572
+ }
573
+ }
574
+ this.error = m.forbidden()
575
+ }
576
+ else {
577
+ this.error = result.error.httpStatus === 403 ? m.forbidden() : result.error.httpStatus === 409 ? m.conflict() : result.error.httpStatus === 400 || result.error.httpStatus === 422 ? result.error.message || m.validation_failed() : m.operation_failed()
578
+ }
579
+ this.error = core.error.formatMessage({ message: this.error, traceId: result.error.traceId })
580
+ }
581
+ return result
582
+ }
583
+ catch {
584
+ if (isCurrent())
585
+ this.error = m.network_error()
586
+ return undefined
587
+ }
588
+ }
589
+
590
+ private async load(task: (version: number) => Promise<void>): Promise<void> {
591
+ const version = ++this.requestVersion
592
+ this.loading = true
593
+ this.error = ''
594
+ await task(version)
595
+ if (version === this.requestVersion)
596
+ this.loading = false
597
+ }
598
+
599
+ private async mutate(task: () => Promise<void>): Promise<void> {
600
+ if (this.saving)
601
+ return
602
+ this.saving = true
603
+ this.error = ''
604
+ try {
605
+ await task()
606
+ }
607
+ catch {
608
+ this.error = m.network_error()
609
+ }
610
+ finally {
611
+ this.saving = false
612
+ }
613
+ }
614
+ }
@@ -0,0 +1,23 @@
1
+ import { applyTheme, getSavedTheme } from '@h-ai/ui/theme'
2
+
3
+ export const DEFAULT_THEME = '{{fullstack.theme.defaultTheme}}'
4
+ export const AVAILABLE_THEMES: readonly string[] = [{{#each fullstack.theme.themes}}'{{this}}'{{#unless @last}}, {{/unless}}{{/each}}]
5
+
6
+ /** 只维护响应式状态和已编译主题白名单,DOM 与安全持久化复用 UI 公共工具。 */
7
+ class ThemeState {
8
+ current = $state<string>(DEFAULT_THEME)
9
+
10
+ constructor() {
11
+ const saved = getSavedTheme(DEFAULT_THEME)
12
+ this.set(AVAILABLE_THEMES.includes(saved) ? saved : DEFAULT_THEME)
13
+ }
14
+
15
+ set(value: string): void {
16
+ if (!AVAILABLE_THEMES.includes(value))
17
+ return
18
+ this.current = value
19
+ applyTheme(value)
20
+ }
21
+ }
22
+
23
+ export const themeStore = new ThemeState()