@h-ai/cli 0.1.0-alpha.20 → 0.1.0-alpha.21

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 (181) hide show
  1. package/README.md +10 -7
  2. package/dist/{chunk-GSMXGUYF.js → chunk-5IGMJVV5.js} +56 -38
  3. package/dist/chunk-5IGMJVV5.js.map +1 -0
  4. package/dist/{chunk-3BBXDQ4Y.js → chunk-CFCXOKGV.js} +24 -2
  5. package/dist/chunk-CFCXOKGV.js.map +1 -0
  6. package/dist/cli-config-templates-5J5VKWWD.js +5 -0
  7. package/dist/{cli-config-templates-IGGO7P45.js.map → cli-config-templates-5J5VKWWD.js.map} +1 -1
  8. package/dist/cli-skill-templates-JMSV2SVW.js +5 -0
  9. package/dist/{cli-skill-templates-IMYZPQRG.js.map → cli-skill-templates-JMSV2SVW.js.map} +1 -1
  10. package/dist/index.js +567 -75
  11. package/dist/index.js.map +1 -1
  12. package/package.json +3 -2
  13. package/templates/README.md +40 -29
  14. package/templates/apps/api/apps/{{projectName}}-contract/README.md.hbs +16 -0
  15. package/templates/apps/api/apps/{{projectName}}-contract/package.json.hbs +38 -0
  16. package/templates/apps/api/apps/{{projectName}}-contract/src/app-contract.ts.hbs +27 -0
  17. package/templates/apps/api/apps/{{projectName}}-contract/src/app-schemas.ts.hbs +33 -0
  18. package/templates/apps/api/apps/{{projectName}}-contract/src/index.ts.hbs +3 -0
  19. package/templates/apps/api/apps/{{projectName}}-contract/src/{{projectName}}-contract.ts.hbs +12 -0
  20. package/templates/apps/api/apps/{{projectName}}-contract/tests/contract.test.ts.hbs +18 -0
  21. package/templates/apps/api/apps/{{projectName}}-contract/tsconfig.json.hbs +12 -0
  22. package/templates/apps/api/apps/{{projectName}}-contract/tsup.config.ts.hbs +11 -0
  23. package/templates/apps/api/apps/{{projectName}}-contract/vitest.config.ts.hbs +9 -0
  24. package/templates/apps/api/apps/{{projectName}}-service/README.md.hbs +17 -0
  25. package/templates/apps/api/apps/{{projectName}}-service/config/_core.yml.hbs +19 -0
  26. package/templates/apps/api/apps/{{projectName}}-service/config/_serv.yml.hbs +26 -0
  27. package/templates/apps/api/apps/{{projectName}}-service/package.json.hbs +55 -0
  28. package/templates/apps/api/apps/{{projectName}}-service/src/app.ts.hbs +98 -0
  29. package/templates/apps/api/apps/{{projectName}}-service/src/index.ts.hbs +21 -0
  30. package/templates/apps/api/apps/{{projectName}}-service/src/lib/server/init.ts.hbs +184 -0
  31. package/templates/apps/api/apps/{{projectName}}-service/src/server/procedures/app-procedures.ts.hbs +49 -0
  32. package/templates/apps/api/apps/{{projectName}}-service/src/server/procedures/index.ts.hbs +18 -0
  33. package/templates/apps/api/apps/{{projectName}}-service/tests/service.test.ts.hbs +168 -0
  34. package/templates/apps/api/apps/{{projectName}}-service/tsconfig.json.hbs +16 -0
  35. package/templates/apps/api/apps/{{projectName}}-service/tsup.config.ts.hbs +11 -0
  36. package/templates/apps/api/apps/{{projectName}}-service/vitest.config.ts.hbs +9 -0
  37. package/templates/apps/api/e2e/api-service.spec.ts.hbs +18 -0
  38. package/templates/apps/api/eslint.config.js +32 -0
  39. package/templates/apps/api/package.json.hbs +29 -0
  40. package/templates/apps/api/playwright.config.ts.hbs +58 -0
  41. package/templates/apps/api/pnpm-workspace.yaml.hbs +14 -0
  42. package/templates/apps/api/tsconfig.base.json +15 -0
  43. package/templates/apps/fullstack/apps/{{projectName}}-app/.env.example.hbs +10 -0
  44. package/templates/apps/fullstack/apps/{{projectName}}-app/README.md.hbs +24 -7
  45. package/templates/apps/fullstack/apps/{{projectName}}-app/capacitor.config.ts.hbs +18 -0
  46. package/templates/apps/fullstack/apps/{{projectName}}-app/eslint.config.js.hbs +1 -1
  47. package/templates/apps/fullstack/apps/{{projectName}}-app/index.html.hbs +16 -0
  48. package/templates/apps/fullstack/apps/{{projectName}}-app/messages/en-US.json.hbs +6 -0
  49. package/templates/apps/fullstack/apps/{{projectName}}-app/messages/zh-CN.json.hbs +6 -0
  50. package/templates/apps/fullstack/apps/{{projectName}}-app/package.json.hbs +51 -29
  51. package/templates/apps/fullstack/apps/{{projectName}}-app/src/App.svelte.hbs +186 -0
  52. package/templates/apps/fullstack/apps/{{projectName}}-app/src/app.css.hbs +2 -0
  53. package/templates/apps/fullstack/apps/{{projectName}}-app/src/app.d.ts.hbs +0 -1
  54. package/templates/apps/fullstack/apps/{{projectName}}-app/src/lib/capacitor.ts.hbs +18 -0
  55. package/templates/apps/fullstack/apps/{{projectName}}-app/src/main.ts.hbs +14 -0
  56. package/templates/apps/fullstack/apps/{{projectName}}-app/svelte.config.js.hbs +1 -5
  57. package/templates/apps/fullstack/apps/{{projectName}}-app/tsconfig.json.hbs +10 -4
  58. package/templates/apps/fullstack/apps/{{projectName}}-app/vite.config.ts.hbs +4 -3
  59. package/templates/apps/fullstack/apps/{{projectName}}-desktop/.env.example.hbs +6 -0
  60. package/templates/apps/fullstack/apps/{{projectName}}-desktop/README.md.hbs +20 -6
  61. package/templates/apps/fullstack/apps/{{projectName}}-desktop/eslint.config.js.hbs +1 -1
  62. package/templates/apps/fullstack/apps/{{projectName}}-desktop/index.html.hbs +15 -0
  63. package/templates/apps/fullstack/apps/{{projectName}}-desktop/package.json.hbs +33 -30
  64. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/App.svelte.hbs +152 -0
  65. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/app.d.ts.hbs +1 -2
  66. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/main.ts.hbs +13 -0
  67. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/Cargo.toml.hbs +22 -0
  68. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/build.rs.hbs +6 -0
  69. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/capabilities/default.json.hbs +12 -0
  70. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/128x128.png +0 -0
  71. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/128x128@2x.png +0 -0
  72. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/32x32.png +0 -0
  73. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/icon.icns +0 -0
  74. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/icons/icon.ico +0 -0
  75. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/src/lib.rs.hbs +16 -0
  76. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/src/main.rs.hbs +8 -0
  77. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/tauri.conf.json.hbs +41 -0
  78. package/templates/apps/fullstack/apps/{{projectName}}-desktop/svelte.config.js.hbs +2 -8
  79. package/templates/apps/fullstack/apps/{{projectName}}-desktop/tsconfig.json.hbs +9 -4
  80. package/templates/apps/fullstack/apps/{{projectName}}-desktop/vite.config.ts.hbs +44 -21
  81. package/templates/apps/fullstack/apps/{{projectName}}-web/README.md.hbs +15 -6
  82. package/templates/apps/fullstack/apps/{{projectName}}-web/eslint.config.js.hbs +1 -1
  83. package/templates/apps/fullstack/apps/{{projectName}}-web/index.html.hbs +15 -0
  84. package/templates/apps/fullstack/apps/{{projectName}}-web/package.json.hbs +25 -27
  85. package/templates/apps/fullstack/apps/{{projectName}}-web/src/App.svelte.hbs +153 -0
  86. package/templates/apps/fullstack/apps/{{projectName}}-web/src/app.d.ts.hbs +0 -1
  87. package/templates/apps/fullstack/apps/{{projectName}}-web/src/main.ts.hbs +14 -0
  88. package/templates/apps/fullstack/apps/{{projectName}}-web/svelte.config.js.hbs +1 -5
  89. package/templates/apps/fullstack/apps/{{projectName}}-web/tsconfig.json.hbs +10 -4
  90. package/templates/apps/fullstack/apps/{{projectName}}-web/vite.config.ts.hbs +3 -2
  91. package/templates/apps/fullstack/e2e/fullstack.spec.ts.hbs +2 -1
  92. package/templates/apps/fullstack/eslint.config.js +0 -1
  93. package/templates/apps/fullstack/package.json.hbs +18 -17
  94. package/templates/apps/fullstack/packages/{{projectName}}-contract/package.json.hbs +3 -3
  95. package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +2 -2
  96. package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +2 -2
  97. package/templates/apps/fullstack/packages/{{projectName}}-serv/src/index.ts.hbs +1 -1
  98. package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/{server-app.test.ts.hbs → app-server.test.ts.hbs} +1 -1
  99. package/templates/apps/fullstack/packages/{{projectName}}-shared/package.json.hbs +9 -8
  100. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/index.ts.hbs +1 -1
  101. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/api/api-client.ts.hbs +5 -1
  102. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/ThemeSwitcher.svelte.hbs +1 -1
  103. package/templates/apps/fullstack/packages/{{projectName}}-shared/tsconfig.json.hbs +1 -1
  104. package/templates/apps/fullstack/playwright.config.ts.hbs +41 -4
  105. package/templates/apps/fullstack/pnpm-workspace.yaml.hbs +15 -0
  106. package/templates/apps/mobile-app/.env.hbs +3 -0
  107. package/templates/apps/{android-app → mobile-app}/capacitor.config.ts.hbs +2 -2
  108. package/templates/apps/mobile-app/index.html.hbs +13 -0
  109. package/templates/apps/mobile-app/messages/en-US.json +36 -0
  110. package/templates/apps/mobile-app/messages/zh-CN.json +36 -0
  111. package/templates/apps/mobile-app/src/App.svelte.hbs +162 -0
  112. package/templates/apps/mobile-app/src/lib/api.ts.hbs +54 -0
  113. package/templates/apps/{android-app → mobile-app}/src/lib/capacitor.ts +5 -6
  114. package/templates/apps/mobile-app/src/main.ts.hbs +11 -0
  115. package/templates/base/.gitignore.hbs +16 -0
  116. package/templates/base/{eslint.config.js → eslint.config.js.hbs} +4 -1
  117. package/templates/base/package.json.hbs +52 -33
  118. package/templates/base/playwright.config.ts +30 -3
  119. package/templates/base/pnpm-workspace.yaml.hbs +14 -0
  120. package/templates/base/src/app.d.ts.hbs +3 -0
  121. package/templates/base/src/app.html.hbs +3 -0
  122. package/templates/base/svelte.config.js.hbs +43 -3
  123. package/templates/base/tests/scaffold.test.ts.hbs +7 -0
  124. package/templates/base/tsconfig.json.hbs +50 -0
  125. package/templates/base/vite.config.ts.hbs +10 -0
  126. package/templates/skills/AGENTS.md +57 -24
  127. package/templates/skills/CLAUDE.md +18 -7
  128. package/templates/skills/bridges/admin/AGENTS.md +66 -0
  129. package/templates/skills/bridges/admin/CLAUDE.md +19 -0
  130. package/templates/skills/bridges/admin/copilot-instructions.md +46 -0
  131. package/templates/skills/bridges/api/AGENTS.md +65 -0
  132. package/templates/skills/bridges/api/CLAUDE.md +19 -0
  133. package/templates/skills/bridges/api/copilot-instructions.md +46 -0
  134. package/templates/skills/bridges/fullstack/AGENTS.md +84 -0
  135. package/templates/skills/bridges/fullstack/CLAUDE.md +19 -0
  136. package/templates/skills/bridges/fullstack/copilot-instructions.md +54 -0
  137. package/templates/skills/bridges/h5/AGENTS.md +65 -0
  138. package/templates/skills/bridges/h5/CLAUDE.md +19 -0
  139. package/templates/skills/bridges/h5/copilot-instructions.md +44 -0
  140. package/templates/skills/bridges/mobile-app/AGENTS.md +77 -0
  141. package/templates/skills/bridges/mobile-app/CLAUDE.md +19 -0
  142. package/templates/skills/bridges/mobile-app/copilot-instructions.md +45 -0
  143. package/templates/skills/bridges/website/AGENTS.md +65 -0
  144. package/templates/skills/bridges/website/CLAUDE.md +19 -0
  145. package/templates/skills/bridges/website/copilot-instructions.md +44 -0
  146. package/templates/skills/copilot-instructions.md +27 -64
  147. package/templates/skills/hai-app-create/SKILL.md +1 -0
  148. package/templates/skills/hai-app-review/SKILL.md +1 -1
  149. package/templates/skills/hai-app-tests/SKILL.md +28 -3
  150. package/templates/skills/hai-capacitor/SKILL.md +14 -22
  151. package/templates/skills/opencode.json +1 -6
  152. package/dist/chunk-3BBXDQ4Y.js.map +0 -1
  153. package/dist/chunk-GSMXGUYF.js.map +0 -1
  154. package/dist/cli-config-templates-IGGO7P45.js +0 -5
  155. package/dist/cli-skill-templates-IMYZPQRG.js +0 -5
  156. package/templates/apps/android-app/.env.hbs +0 -3
  157. package/templates/apps/android-app/messages/en-US.json +0 -24
  158. package/templates/apps/android-app/messages/zh-CN.json +0 -24
  159. package/templates/apps/android-app/src/lib/api.ts.hbs +0 -32
  160. package/templates/apps/android-app/src/routes/+layout.svelte.hbs +0 -43
  161. package/templates/apps/android-app/src/routes/+layout.ts +0 -7
  162. package/templates/apps/android-app/src/routes/+page.svelte.hbs +0 -38
  163. package/templates/apps/api/src/routes/+layout.svelte +0 -14
  164. package/templates/apps/api/src/routes/+page.svelte +0 -11
  165. package/templates/apps/api/src/routes/api/v1/health/+server.ts +0 -14
  166. package/templates/apps/api/src/routes/api/v1/items/+server.ts +0 -37
  167. package/templates/apps/api/src/routes/api/v1/items/[id]/+server.ts +0 -30
  168. package/templates/apps/api/tests/health.test.ts.hbs +0 -26
  169. package/templates/apps/fullstack/apps/{{projectName}}-app/src/app.html.hbs +0 -14
  170. package/templates/apps/fullstack/apps/{{projectName}}-app/src/routes/+layout.svelte.hbs +0 -18
  171. package/templates/apps/fullstack/apps/{{projectName}}-app/src/routes/+page.svelte.hbs +0 -162
  172. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/app.html.hbs +0 -14
  173. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/routes/+layout.svelte.hbs +0 -18
  174. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src/routes/+page.svelte.hbs +0 -162
  175. package/templates/apps/fullstack/apps/{{projectName}}-web/src/app.html.hbs +0 -14
  176. package/templates/apps/fullstack/apps/{{projectName}}-web/src/routes/+layout.svelte.hbs +0 -18
  177. package/templates/apps/fullstack/apps/{{projectName}}-web/src/routes/+page.svelte.hbs +0 -162
  178. package/templates/apps/fullstack/pnpm-workspace.yaml +0 -7
  179. package/templates/base/tsconfig.json +0 -20
  180. /package/templates/apps/fullstack/packages/{{projectName}}-serv/src/{server-app.ts.hbs → app-server.ts.hbs} +0 -0
  181. /package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/stores/{theme.svelte.ts.hbs → theme-store.svelte.ts.hbs} +0 -0
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
- import { generateConfigFile } from './chunk-3BBXDQ4Y.js';
3
- import './chunk-GSMXGUYF.js';
2
+ import { generateConfigFile } from './chunk-CFCXOKGV.js';
3
+ import './chunk-5IGMJVV5.js';
4
4
  import './chunk-2H7UOFLK.js';
5
5
  import process3 from 'process';
6
6
  import { core } from '@h-ai/core';
@@ -12,6 +12,7 @@ import fse from 'fs-extra';
12
12
  import Handlebars from 'handlebars';
13
13
  import ora from 'ora';
14
14
  import prompts from 'prompts';
15
+ import { Buffer } from 'buffer';
15
16
  import { execSync, execFileSync } from 'child_process';
16
17
  import { existsSync, readFileSync } from 'fs';
17
18
  import { parse } from 'yaml';
@@ -98,7 +99,6 @@ registerHelpers();
98
99
  Handlebars.registerHelper("if_eq", function(a, b, options) {
99
100
  return a === b ? options.fn(this) : options.inverse(this);
100
101
  });
101
- var HAI_VERSION = `^${getCliVersion()}`;
102
102
  var TEMPLATE_SKIP_IF_EMPTY_MARKER = "@skipIfEmpty";
103
103
  var NORMALIZED_RENDER_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".js", ".svelte", ".json", ".css"]);
104
104
  var CAPACITOR_SKIPPED_SERVER_FILES = /* @__PURE__ */ new Set([
@@ -107,15 +107,22 @@ var CAPACITOR_SKIPPED_SERVER_FILES = /* @__PURE__ */ new Set([
107
107
  ]);
108
108
  var VERSIONS = {
109
109
  antfuEslintConfig: "^9.0.0",
110
- apiContract: HAI_VERSION,
111
- apiClient: HAI_VERSION,
112
- core: HAI_VERSION,
113
- serv: HAI_VERSION,
114
- ui: HAI_VERSION,
110
+ capacitorSecureStorage: "^8.0.0",
115
111
  // UI / Icon
116
112
  bitsUi: "^2.18.1",
117
113
  iconifyJsonTabler: "^1.2.35",
118
114
  iconifyTailwind: "^1.2.3",
115
+ // Capacitor
116
+ capacitorAndroid: "^8.3.4",
117
+ capacitorApp: "^8.0.1",
118
+ capacitorCamera: "^8.0.1",
119
+ capacitorCli: "^8.3.4",
120
+ capacitorCore: "^8.3.4",
121
+ capacitorDevice: "^8.0.1",
122
+ capacitorIos: "^8.3.4",
123
+ capacitorPreferences: "^8.0.1",
124
+ capacitorPushNotifications: "^8.0.1",
125
+ capacitorStatusBar: "^8.0.1",
119
126
  // Tailwind / DaisyUI
120
127
  daisyui: "^5.5.20",
121
128
  tailwindcss: "^4.3.0",
@@ -123,13 +130,10 @@ var VERSIONS = {
123
130
  // i18n
124
131
  inlangParaglide: "^2.18.1",
125
132
  inlangMessageFormat: "^4.4.0",
126
- // Svelte / Kit
133
+ // Svelte / Vite
127
134
  svelte: "^5.55.9",
128
- svelteKit: "^2.61.1",
129
135
  svelteCheck: "^4.4.8",
130
136
  sveltePlugin: "^7.1.2",
131
- adapterAuto: "^7.0.1",
132
- adapterStatic: "^3.0.10",
133
137
  // Build / Test
134
138
  vite: "^8.0.14",
135
139
  vitest: "^4.1.7",
@@ -146,12 +150,14 @@ var VERSIONS = {
146
150
  // E2E
147
151
  playwright: "^1.60.0",
148
152
  // Validation
149
- zod: "^4.4.3"
153
+ zod: "^4.4.3",
154
+ // Tauri
155
+ tauriCli: "^2.10.1"
150
156
  };
151
157
  var FRONTEND_PORTS_DEFAULT = {
152
158
  web: 4173,
153
- app: 4174,
154
- desktop: 4175
159
+ app: 5175,
160
+ desktop: 5176
155
161
  };
156
162
  var FRONTEND_LABELS = {
157
163
  web: "Web",
@@ -163,6 +169,277 @@ var IMPLEMENTED_FRONTENDS = ["web", "app", "desktop"];
163
169
  var DEFAULT_FULLSTACK_FRONTENDS = ["web", "app", "desktop"];
164
170
  var DEFAULT_THEMES = ["light", "dark"];
165
171
  var DEFAULT_THEME_NAME = "light";
172
+ var HAI_PACKAGE_VERSION = `^${getCliVersion()}`;
173
+ var HAI_PACKAGE_SPECIFIER_CATALOG = "catalog:";
174
+ var HAI_CATALOG_PACKAGE_NAMES = [
175
+ "@h-ai/ai",
176
+ "@h-ai/api-client",
177
+ "@h-ai/api-contract",
178
+ "@h-ai/audit",
179
+ "@h-ai/cache",
180
+ "@h-ai/capacitor",
181
+ "@h-ai/core",
182
+ "@h-ai/crypto",
183
+ "@h-ai/datapipe",
184
+ "@h-ai/deploy",
185
+ "@h-ai/iam",
186
+ "@h-ai/kit",
187
+ "@h-ai/payment",
188
+ "@h-ai/reach",
189
+ "@h-ai/reldb",
190
+ "@h-ai/scheduler",
191
+ "@h-ai/serv",
192
+ "@h-ai/storage",
193
+ "@h-ai/ui",
194
+ "@h-ai/vecdb"
195
+ ];
196
+ var HAI_CATALOG_PACKAGES = Object.fromEntries(
197
+ HAI_CATALOG_PACKAGE_NAMES.map((packageName) => [packageName, HAI_PACKAGE_VERSION])
198
+ );
199
+ var FULLSTACK_EXTERNAL_CATALOG_PACKAGES = {
200
+ "@antfu/eslint-config": VERSIONS.antfuEslintConfig,
201
+ "@aparajita/capacitor-secure-storage": VERSIONS.capacitorSecureStorage,
202
+ "@capacitor/android": VERSIONS.capacitorAndroid,
203
+ "@capacitor/app": VERSIONS.capacitorApp,
204
+ "@capacitor/camera": VERSIONS.capacitorCamera,
205
+ "@capacitor/cli": VERSIONS.capacitorCli,
206
+ "@capacitor/core": VERSIONS.capacitorCore,
207
+ "@capacitor/device": VERSIONS.capacitorDevice,
208
+ "@capacitor/ios": VERSIONS.capacitorIos,
209
+ "@capacitor/preferences": VERSIONS.capacitorPreferences,
210
+ "@capacitor/push-notifications": VERSIONS.capacitorPushNotifications,
211
+ "@capacitor/status-bar": VERSIONS.capacitorStatusBar,
212
+ "@iconify-json/tabler": VERSIONS.iconifyJsonTabler,
213
+ "@iconify/tailwind4": VERSIONS.iconifyTailwind,
214
+ "@inlang/paraglide-js": VERSIONS.inlangParaglide,
215
+ "@inlang/plugin-message-format": VERSIONS.inlangMessageFormat,
216
+ "@playwright/test": VERSIONS.playwright,
217
+ "@sveltejs/vite-plugin-svelte": VERSIONS.sveltePlugin,
218
+ "@tailwindcss/vite": VERSIONS.tailwindcssVite,
219
+ "@tauri-apps/cli": VERSIONS.tauriCli,
220
+ "@types/node": VERSIONS.nodeTypes,
221
+ "bits-ui": VERSIONS.bitsUi,
222
+ "daisyui": VERSIONS.daisyui,
223
+ "eslint": VERSIONS.eslint,
224
+ "eslint-plugin-format": VERSIONS.eslintPluginFormat,
225
+ "eslint-plugin-svelte": VERSIONS.eslintPluginSvelte,
226
+ "rimraf": VERSIONS.rimraf,
227
+ "svelte": VERSIONS.svelte,
228
+ "svelte-check": VERSIONS.svelteCheck,
229
+ "svelte-eslint-parser": VERSIONS.svelteEslintParser,
230
+ "tailwindcss": VERSIONS.tailwindcss,
231
+ "tsup": VERSIONS.tsup,
232
+ "typescript": VERSIONS.typescript,
233
+ "vite": VERSIONS.vite,
234
+ "vitest": VERSIONS.vitest,
235
+ "zod": VERSIONS.zod
236
+ };
237
+ var FULLSTACK_CATALOG_PACKAGES = {
238
+ ...HAI_CATALOG_PACKAGES,
239
+ ...FULLSTACK_EXTERNAL_CATALOG_PACKAGES
240
+ };
241
+ var FULLSTACK_ROOT_CATALOG_PACKAGE_NAMES = [
242
+ "@antfu/eslint-config",
243
+ "@playwright/test",
244
+ "@sveltejs/vite-plugin-svelte",
245
+ "@types/node",
246
+ "eslint",
247
+ "eslint-plugin-format",
248
+ "eslint-plugin-svelte",
249
+ "rimraf",
250
+ "svelte",
251
+ "svelte-check",
252
+ "svelte-eslint-parser",
253
+ "tsup",
254
+ "typescript",
255
+ "vite",
256
+ "vitest"
257
+ ];
258
+ var FULLSTACK_CONTRACT_CATALOG_PACKAGE_NAMES = [
259
+ "@h-ai/api-contract",
260
+ "@h-ai/core",
261
+ "zod"
262
+ ];
263
+ var FULLSTACK_SERV_CATALOG_PACKAGE_NAMES = [
264
+ "@h-ai/core",
265
+ "@h-ai/serv"
266
+ ];
267
+ var FULLSTACK_SHARED_CATALOG_PACKAGE_NAMES = [
268
+ "@h-ai/api-client",
269
+ "@h-ai/ui",
270
+ "@inlang/paraglide-js",
271
+ "@inlang/plugin-message-format",
272
+ "svelte",
273
+ "svelte-check",
274
+ "typescript",
275
+ "vite",
276
+ "vitest"
277
+ ];
278
+ var FULLSTACK_WEB_CATALOG_PACKAGE_NAMES = [
279
+ "@antfu/eslint-config",
280
+ "@h-ai/ui",
281
+ "@iconify-json/tabler",
282
+ "@iconify/tailwind4",
283
+ "@inlang/paraglide-js",
284
+ "@inlang/plugin-message-format",
285
+ "@sveltejs/vite-plugin-svelte",
286
+ "@tailwindcss/vite",
287
+ "bits-ui",
288
+ "daisyui",
289
+ "eslint",
290
+ "eslint-plugin-format",
291
+ "eslint-plugin-svelte",
292
+ "svelte",
293
+ "svelte-check",
294
+ "svelte-eslint-parser",
295
+ "tailwindcss",
296
+ "typescript",
297
+ "vite",
298
+ "vitest"
299
+ ];
300
+ var FULLSTACK_APP_CATALOG_PACKAGE_NAMES = [
301
+ ...FULLSTACK_WEB_CATALOG_PACKAGE_NAMES,
302
+ "@aparajita/capacitor-secure-storage",
303
+ "@capacitor/android",
304
+ "@capacitor/app",
305
+ "@capacitor/camera",
306
+ "@capacitor/cli",
307
+ "@capacitor/core",
308
+ "@capacitor/device",
309
+ "@capacitor/ios",
310
+ "@capacitor/preferences",
311
+ "@capacitor/push-notifications",
312
+ "@capacitor/status-bar",
313
+ "@h-ai/capacitor"
314
+ ];
315
+ var FULLSTACK_DESKTOP_CATALOG_PACKAGE_NAMES = [
316
+ ...FULLSTACK_WEB_CATALOG_PACKAGE_NAMES,
317
+ "@tauri-apps/cli"
318
+ ];
319
+ var API_WORKSPACE_EXTERNAL_CATALOG_PACKAGE_NAMES = [
320
+ "@antfu/eslint-config",
321
+ "@playwright/test",
322
+ "@types/node",
323
+ "eslint",
324
+ "eslint-plugin-format",
325
+ "rimraf",
326
+ "tsup",
327
+ "typescript",
328
+ "vitest",
329
+ "zod"
330
+ ];
331
+ function pickCatalogPackages(packageNames, availableCatalogPackages) {
332
+ return Object.fromEntries(
333
+ [...new Set(packageNames)].sort((left, right) => left.localeCompare(right)).map((packageName) => {
334
+ const version = availableCatalogPackages[packageName];
335
+ if (!version) {
336
+ throw new Error(`Missing catalog version for package "${packageName}"`);
337
+ }
338
+ return [packageName, version];
339
+ })
340
+ );
341
+ }
342
+ function buildFullstackPackageSpecifiers(useCatalogProtocol) {
343
+ return Object.fromEntries(
344
+ Object.entries(VERSIONS).map(([key, version]) => [key, useCatalogProtocol ? HAI_PACKAGE_SPECIFIER_CATALOG : version])
345
+ );
346
+ }
347
+ function buildApiWorkspaceCatalogPackages(featureMap) {
348
+ const packageNames = [
349
+ ...API_WORKSPACE_EXTERNAL_CATALOG_PACKAGE_NAMES,
350
+ "@h-ai/api-client",
351
+ "@h-ai/api-contract",
352
+ "@h-ai/core",
353
+ "@h-ai/serv"
354
+ ];
355
+ if (featureMap.db)
356
+ packageNames.push("@h-ai/reldb");
357
+ if (featureMap.cache)
358
+ packageNames.push("@h-ai/cache");
359
+ if (featureMap.iam)
360
+ packageNames.push("@h-ai/iam");
361
+ if (featureMap.crypto)
362
+ packageNames.push("@h-ai/crypto");
363
+ if (featureMap.storage)
364
+ packageNames.push("@h-ai/storage");
365
+ if (featureMap.ai)
366
+ packageNames.push("@h-ai/ai");
367
+ if (featureMap.audit)
368
+ packageNames.push("@h-ai/audit");
369
+ if (featureMap.reach)
370
+ packageNames.push("@h-ai/reach");
371
+ if (featureMap.payment)
372
+ packageNames.push("@h-ai/payment");
373
+ if (featureMap.vecdb)
374
+ packageNames.push("@h-ai/vecdb");
375
+ if (featureMap.datapipe)
376
+ packageNames.push("@h-ai/datapipe");
377
+ if (featureMap.scheduler)
378
+ packageNames.push("@h-ai/scheduler");
379
+ if (featureMap.deploy)
380
+ packageNames.push("@h-ai/deploy");
381
+ return pickCatalogPackages(packageNames, FULLSTACK_CATALOG_PACKAGES);
382
+ }
383
+ function buildAppHaiCatalogPackages(options) {
384
+ const packageNames = [];
385
+ if (options.isSvelteOnlyApp) {
386
+ packageNames.push("@h-ai/api-client", "@h-ai/capacitor", "@h-ai/ui");
387
+ return pickCatalogPackages(packageNames, HAI_CATALOG_PACKAGES);
388
+ }
389
+ packageNames.push("@h-ai/core", "@h-ai/kit");
390
+ if (options.hasUi)
391
+ packageNames.push("@h-ai/ui");
392
+ if (options.featureMap.db)
393
+ packageNames.push("@h-ai/reldb");
394
+ if (options.featureMap.cache)
395
+ packageNames.push("@h-ai/cache");
396
+ if (options.featureMap.iam)
397
+ packageNames.push("@h-ai/iam");
398
+ if (options.featureMap.crypto)
399
+ packageNames.push("@h-ai/crypto");
400
+ if (options.featureMap.storage)
401
+ packageNames.push("@h-ai/storage");
402
+ if (options.featureMap.ai)
403
+ packageNames.push("@h-ai/ai");
404
+ if (options.featureMap.audit)
405
+ packageNames.push("@h-ai/audit");
406
+ if (options.featureMap.reach)
407
+ packageNames.push("@h-ai/reach");
408
+ if (options.featureMap.payment)
409
+ packageNames.push("@h-ai/payment");
410
+ if (options.featureMap.vecdb)
411
+ packageNames.push("@h-ai/vecdb");
412
+ if (options.featureMap.datapipe)
413
+ packageNames.push("@h-ai/datapipe");
414
+ if (options.featureMap.scheduler)
415
+ packageNames.push("@h-ai/scheduler");
416
+ if (options.featureMap.deploy)
417
+ packageNames.push("@h-ai/deploy");
418
+ if (options.featureMap["api-client"])
419
+ packageNames.push("@h-ai/api-client");
420
+ if (options.featureMap.capacitor)
421
+ packageNames.push("@h-ai/capacitor");
422
+ if (options.isCapacitorApp && !options.featureMap["api-client"])
423
+ packageNames.push("@h-ai/api-client");
424
+ if (options.isCapacitorApp && !options.featureMap.capacitor)
425
+ packageNames.push("@h-ai/capacitor");
426
+ return pickCatalogPackages(packageNames, HAI_CATALOG_PACKAGES);
427
+ }
428
+ function buildFullstackCatalogPackages(frontends) {
429
+ const packageNames = [
430
+ ...FULLSTACK_ROOT_CATALOG_PACKAGE_NAMES,
431
+ ...FULLSTACK_CONTRACT_CATALOG_PACKAGE_NAMES,
432
+ ...FULLSTACK_SERV_CATALOG_PACKAGE_NAMES,
433
+ ...FULLSTACK_SHARED_CATALOG_PACKAGE_NAMES
434
+ ];
435
+ if (frontends.includes("web"))
436
+ packageNames.push(...FULLSTACK_WEB_CATALOG_PACKAGE_NAMES);
437
+ if (frontends.includes("app"))
438
+ packageNames.push(...FULLSTACK_APP_CATALOG_PACKAGE_NAMES);
439
+ if (frontends.includes("desktop"))
440
+ packageNames.push(...FULLSTACK_DESKTOP_CATALOG_PACKAGE_NAMES);
441
+ return pickCatalogPackages(packageNames, FULLSTACK_CATALOG_PACKAGES);
442
+ }
166
443
  var FEATURE_ROUTE_DIRS = {
167
444
  iam: ["routes-shared"],
168
445
  storage: ["routes"],
@@ -179,6 +456,7 @@ var FEATURE_APP_ROUTE_DIRS = {
179
456
  };
180
457
  var FEATURE_ID_REGEX = /^[a-z0-9-]+$/;
181
458
  var HBS_SUFFIX_REGEX = /\.hbs$/;
459
+ var FULLSTACK_FRONTEND_TEMPLATE_PATH_REGEX = /^apps\/\{\{projectName\}\}-(web|app|desktop|miniapp)\//;
182
460
  var NON_IDENTIFIER_CHAR_REGEX = /[^a-z0-9]+/i;
183
461
  var IDENTIFIER_START_REGEX = /^[a-z_$]/i;
184
462
  function getTemplatesRoot() {
@@ -229,6 +507,28 @@ async function findHbsFiles(dir) {
229
507
  await walk(dir);
230
508
  return results;
231
509
  }
510
+ async function findRenderedStaticPathFiles(dir) {
511
+ if (!await fse.pathExists(dir)) {
512
+ return [];
513
+ }
514
+ const results = [];
515
+ async function walk(current) {
516
+ const entries = await fse.readdir(current, { withFileTypes: true });
517
+ for (const entry of entries) {
518
+ const fullPath = path2.join(current, entry.name);
519
+ if (entry.isDirectory()) {
520
+ await walk(fullPath);
521
+ continue;
522
+ }
523
+ const relPath = path2.relative(dir, fullPath);
524
+ if (!entry.name.endsWith(".hbs") && (relPath.includes("{{") || relPath.includes("}}"))) {
525
+ results.push(relPath);
526
+ }
527
+ }
528
+ }
529
+ await walk(dir);
530
+ return results;
531
+ }
232
532
  function buildTemplateContext(options) {
233
533
  const featureMap = {};
234
534
  for (const f of options.features) {
@@ -244,24 +544,62 @@ function buildTemplateContext(options) {
244
544
  }
245
545
  const isApi = options.appType === "api";
246
546
  const isFullstack = options.appType === "fullstack";
247
- const isCapacitorApp = options.appType === "android-app";
547
+ const isCapacitorApp = options.appType === "mobile-app";
548
+ const isSvelteOnlyApp = isCapacitorApp;
549
+ const useCatalogProtocol = options.packageManager === "pnpm";
550
+ const hasUi = !isApi && !isFullstack;
551
+ const selectedFrontends = options.frontends ?? DEFAULT_FULLSTACK_FRONTENDS;
552
+ let haiCatalogPackages;
553
+ if (isFullstack) {
554
+ haiCatalogPackages = buildFullstackCatalogPackages(selectedFrontends);
555
+ } else if (isApi) {
556
+ haiCatalogPackages = buildApiWorkspaceCatalogPackages(featureMap);
557
+ } else {
558
+ haiCatalogPackages = buildAppHaiCatalogPackages({
559
+ featureMap,
560
+ hasUi,
561
+ isCapacitorApp,
562
+ isSvelteOnlyApp
563
+ });
564
+ }
248
565
  return {
249
566
  projectName: options.name,
567
+ useCatalogProtocol,
568
+ haiPackageSpecifier: useCatalogProtocol ? HAI_PACKAGE_SPECIFIER_CATALOG : HAI_PACKAGE_VERSION,
569
+ haiPackageVersion: HAI_PACKAGE_VERSION,
570
+ haiCatalogPackages,
250
571
  appType: options.appType,
251
572
  features: featureMap,
252
- hasUi: !isApi && !isFullstack,
573
+ hasUi,
253
574
  hasI18n: !isApi && !isFullstack,
254
575
  isCapacitorApp,
576
+ isApiWorkspace: isApi,
577
+ isSvelteOnlyApp,
255
578
  defaultLocale: options.moduleConfigs?.core?.defaultLocale ?? "zh-CN",
256
579
  packageManager: options.packageManager,
580
+ api: isApi ? buildApiWorkspaceTemplateContext(options.name, useCatalogProtocol) : void 0,
257
581
  fullstack: isFullstack ? buildFullstackTemplateContext(
258
582
  options.name,
259
- options.frontends ?? DEFAULT_FULLSTACK_FRONTENDS,
260
- options.moduleConfigs
583
+ selectedFrontends,
584
+ options.moduleConfigs,
585
+ useCatalogProtocol
261
586
  ) : void 0
262
587
  };
263
588
  }
264
- function buildFullstackTemplateContext(projectName, frontendsInput, moduleConfigs) {
589
+ function buildApiWorkspaceTemplateContext(projectName, useCatalogProtocol = false) {
590
+ const identifier = toIdentifier(projectName);
591
+ const pascalName = toPascalIdentifier(identifier);
592
+ return {
593
+ versions: VERSIONS,
594
+ packageSpecifiers: buildFullstackPackageSpecifiers(useCatalogProtocol),
595
+ contractPackageName: `${projectName}-contract`,
596
+ contractExportName: `${identifier}Contract`,
597
+ servicePackageName: `${projectName}-service`,
598
+ serviceAppFactoryName: `create${pascalName}App`,
599
+ serviceProceduresFactoryName: `create${pascalName}Procedures`
600
+ };
601
+ }
602
+ function buildFullstackTemplateContext(projectName, frontendsInput, moduleConfigs, useCatalogProtocol = false) {
265
603
  const selectedFrontends = [...new Set(frontendsInput.length > 0 ? frontendsInput : DEFAULT_FULLSTACK_FRONTENDS)];
266
604
  const portsConfig = moduleConfigs?.fullstack?.ports ?? {};
267
605
  const portFor = (target) => portsConfig[target] ?? FRONTEND_PORTS_DEFAULT[target];
@@ -273,9 +611,11 @@ function buildFullstackTemplateContext(projectName, frontendsInput, moduleConfig
273
611
  }));
274
612
  return {
275
613
  versions: VERSIONS,
614
+ packageSpecifiers: buildFullstackPackageSpecifiers(useCatalogProtocol),
276
615
  contractPackageName: `${projectName}-contract`,
277
616
  contractExportName: `${toIdentifier(projectName)}Contract`,
278
617
  servPackageName: `${projectName}-serv`,
618
+ nativeAppIdSegment: toIdentifier(projectName).toLowerCase(),
279
619
  sharedPackageName: `${projectName}-shared`,
280
620
  selectedFrontends,
281
621
  selectedFrontendsJson: `[${selectedFrontends.map((f) => `'${f}'`).join(", ")}]`,
@@ -330,9 +670,14 @@ function toIdentifier(value) {
330
670
  return "app";
331
671
  return IDENTIFIER_START_REGEX.test(camel) ? camel : `app${camel}`;
332
672
  }
673
+ function toPascalIdentifier(value) {
674
+ if (!value)
675
+ return "App";
676
+ return `${value.charAt(0).toUpperCase()}${value.slice(1)}`;
677
+ }
333
678
  async function generateFromTemplates(projectPath, context) {
334
679
  const root = getTemplatesRoot();
335
- const includeBaseTemplate = context.appType !== "fullstack";
680
+ const includeBaseTemplate = context.appType !== "fullstack" && !context.isApiWorkspace;
336
681
  if (includeBaseTemplate) {
337
682
  await copyStaticDir(path2.join(root, "base"), projectPath);
338
683
  }
@@ -341,32 +686,37 @@ async function generateFromTemplates(projectPath, context) {
341
686
  const appExcludes = context.hasI18n ? [] : ["messages"];
342
687
  await copyStaticDir(appDir, projectPath, appExcludes);
343
688
  }
344
- for (const featureId of Object.keys(context.features)) {
345
- if (!context.features[featureId]) {
346
- continue;
347
- }
348
- if (!FEATURE_ID_REGEX.test(featureId)) {
349
- continue;
350
- }
351
- const featureDir = path2.join(root, "features", featureId);
352
- if (!await fse.pathExists(featureDir)) {
353
- continue;
354
- }
355
- const sharedDirs = FEATURE_ROUTE_DIRS[featureId] || [];
356
- for (const dirName of sharedDirs) {
357
- if (context.isCapacitorApp && dirName === "routes-shared") {
689
+ if (!context.isApiWorkspace) {
690
+ for (const featureId of Object.keys(context.features)) {
691
+ if (context.isSvelteOnlyApp) {
358
692
  continue;
359
693
  }
360
- const routesSrc = path2.join(featureDir, dirName);
361
- if (await fse.pathExists(routesSrc)) {
362
- await copyStaticDir(routesSrc, path2.join(projectPath, "src", "routes"));
694
+ if (!context.features[featureId]) {
695
+ continue;
363
696
  }
364
- }
365
- const appSpecificTypes = FEATURE_APP_ROUTE_DIRS[featureId] || [];
366
- if (appSpecificTypes.includes(context.appType)) {
367
- const appRouteSrc = path2.join(featureDir, `routes-${context.appType}`);
368
- if (await fse.pathExists(appRouteSrc)) {
369
- await copyStaticDir(appRouteSrc, path2.join(projectPath, "src", "routes"));
697
+ if (!FEATURE_ID_REGEX.test(featureId)) {
698
+ continue;
699
+ }
700
+ const featureDir = path2.join(root, "features", featureId);
701
+ if (!await fse.pathExists(featureDir)) {
702
+ continue;
703
+ }
704
+ const sharedDirs = FEATURE_ROUTE_DIRS[featureId] || [];
705
+ for (const dirName of sharedDirs) {
706
+ if (context.isCapacitorApp && dirName === "routes-shared") {
707
+ continue;
708
+ }
709
+ const routesSrc = path2.join(featureDir, dirName);
710
+ if (await fse.pathExists(routesSrc)) {
711
+ await copyStaticDir(routesSrc, path2.join(projectPath, "src", "routes"));
712
+ }
713
+ }
714
+ const appSpecificTypes = FEATURE_APP_ROUTE_DIRS[featureId] || [];
715
+ if (appSpecificTypes.includes(context.appType)) {
716
+ const appRouteSrc = path2.join(featureDir, `routes-${context.appType}`);
717
+ if (await fse.pathExists(appRouteSrc)) {
718
+ await copyStaticDir(appRouteSrc, path2.join(projectPath, "src", "routes"));
719
+ }
370
720
  }
371
721
  }
372
722
  }
@@ -382,15 +732,22 @@ async function generateFromTemplates(projectPath, context) {
382
732
  }
383
733
  }
384
734
  async function renderDynamicFiles(templatesRoot, projectPath, context) {
385
- const rootDirs = context.appType === "fullstack" ? [path2.join(templatesRoot, "apps", context.appType)] : [
735
+ const rootDirs = context.appType === "fullstack" || context.isApiWorkspace ? [path2.join(templatesRoot, "apps", context.appType)] : [
386
736
  path2.join(templatesRoot, "base"),
387
737
  path2.join(templatesRoot, "apps", context.appType)
388
738
  ];
389
739
  for (const dir of rootDirs) {
390
740
  await renderHbsInDir(dir, projectPath, context);
741
+ await copyRenderedStaticPathFiles(dir, projectPath, context);
742
+ }
743
+ if (context.isApiWorkspace) {
744
+ return;
391
745
  }
392
746
  const routesDest = path2.join(projectPath, "src", "routes");
393
747
  for (const featureId of Object.keys(context.features)) {
748
+ if (context.isSvelteOnlyApp) {
749
+ continue;
750
+ }
394
751
  if (!context.features[featureId]) {
395
752
  continue;
396
753
  }
@@ -439,6 +796,34 @@ async function renderHbsInDir(dir, destRoot, context) {
439
796
  await fse.writeFile(destPath, normalizedRendered, "utf-8");
440
797
  }
441
798
  }
799
+ async function copyRenderedStaticPathFiles(dir, destRoot, context) {
800
+ const staticFiles = await findRenderedStaticPathFiles(dir);
801
+ for (const relPath of staticFiles) {
802
+ if (!shouldCopyRenderedStaticPathFile(relPath, context)) {
803
+ continue;
804
+ }
805
+ const outRelPath = renderOutputPath(relPath, context);
806
+ if (!isSafeRelativePath(outRelPath)) {
807
+ continue;
808
+ }
809
+ const srcPath = path2.join(dir, relPath);
810
+ const destPath = path2.join(destRoot, outRelPath);
811
+ await fse.ensureDir(path2.dirname(destPath));
812
+ await fse.copyFile(srcPath, destPath);
813
+ }
814
+ }
815
+ function shouldCopyRenderedStaticPathFile(relPath, context) {
816
+ if (context.appType !== "fullstack" || !context.fullstack) {
817
+ return true;
818
+ }
819
+ const normalizedPath = relPath.split(path2.sep).join("/");
820
+ const frontendMatch = FULLSTACK_FRONTEND_TEMPLATE_PATH_REGEX.exec(normalizedPath);
821
+ if (!frontendMatch) {
822
+ return true;
823
+ }
824
+ const target = frontendMatch[1];
825
+ return Boolean(context.fullstack.frontends[target]);
826
+ }
442
827
  function normalizeRenderedContent(content, outRelPath) {
443
828
  const normalizedLineEndings = content.replace(/\r\n/g, "\n");
444
829
  const ext = path2.extname(outRelPath);
@@ -482,13 +867,13 @@ var APP_TYPES = {
482
867
  },
483
868
  "api": {
484
869
  name: "API \u670D\u52A1",
485
- description: "\u7EAF API \u540E\u7AEF\u670D\u52A1\uFF0CRESTful \u8DEF\u7531\u3001\u65E0 UI",
870
+ description: "typed API workspace\uFF0C\u542B contract + service \u53CC\u5DE5\u7A0B\u3001\u65E0 UI",
486
871
  defaultFeatures: ["db", "cache"]
487
872
  },
488
- "android-app": {
489
- name: "Android \u5E94\u7528",
490
- description: "Android \u539F\u751F\u5E94\u7528\uFF08Capacitor + SvelteKit SPA\uFF09\uFF0C\u53EF\u6253\u5305\u4E3A APK",
491
- defaultFeatures: ["iam", "db", "cache", "crypto", "api-client", "capacitor"]
873
+ "mobile-app": {
874
+ name: "\u79FB\u52A8\u5E94\u7528",
875
+ description: "\u79FB\u52A8\u7AEF\u5E94\u7528\uFF08Capacitor + Svelte 5 + Vite\uFF09\uFF0C\u53EF\u6253\u5305\u4E3A Android/iOS",
876
+ defaultFeatures: ["api-client", "capacitor"]
492
877
  },
493
878
  "fullstack": {
494
879
  name: "\u524D\u540E\u7AEF\u5206\u79BB\u5DE5\u7A0B",
@@ -498,9 +883,9 @@ var APP_TYPES = {
498
883
  };
499
884
  var FRONTEND_TARGETS = {
500
885
  web: { name: "Web", description: "\u6D4F\u89C8\u5668 Web \u5E94\u7528", implemented: true },
501
- app: { name: "App", description: "\u79FB\u52A8\u7AEF H5/App \u524D\u7AEF", implemented: true },
886
+ app: { name: "App", description: "\u79FB\u52A8\u7AEF Capacitor App / H5 \u524D\u7AEF", implemented: true },
502
887
  miniapp: { name: "\u5C0F\u7A0B\u5E8F", description: "\u9884\u7559\u76EE\u6807\uFF0C\u5F53\u524D\u53EA\u751F\u6210\u8BF4\u660E\u5360\u4F4D", implemented: false },
503
- desktop: { name: "\u684C\u9762\u7AEF", description: "\u684C\u9762\u7AEF\u524D\u7AEF\u5DE5\u7A0B\uFF08Tauri \u9884\u7559\uFF09", implemented: true }
888
+ desktop: { name: "\u684C\u9762\u7AEF", description: "Tauri \u684C\u9762\u7AEF\u524D\u7AEF\u5DE5\u7A0B", implemented: true }
504
889
  };
505
890
  var DEFAULT_FULLSTACK_FRONTENDS2 = ["web", "app", "desktop"];
506
891
  var FEATURES = {
@@ -691,29 +1076,36 @@ async function createProject(options) {
691
1076
  });
692
1077
  await generateFromTemplates(projectPath, context);
693
1078
  if (resolvedOptions.appType !== "fullstack") {
694
- const { generateConfigFile: generateConfigFile2 } = await import('./cli-config-templates-IGGO7P45.js');
1079
+ const { generateConfigFile: generateConfigFile2, generateEnvExample } = await import('./cli-config-templates-5J5VKWWD.js');
695
1080
  const configs = resolvedOptions.moduleConfigs;
1081
+ const isApiWorkspace = resolvedOptions.appType === "api";
1082
+ const configDir = isApiWorkspace ? path2.join(projectPath, "apps", `${resolvedOptions.name}-service`, "config") : path2.join(projectPath, "config");
1083
+ const envExamplePath = isApiWorkspace ? path2.join(projectPath, "apps", `${resolvedOptions.name}-service`, ".env.example") : path2.join(projectPath, ".env.example");
696
1084
  for (const featureId of resolvedOptions.features) {
697
1085
  const configKey = getFeatureConfigKey(featureId);
698
1086
  if (configKey) {
699
1087
  const content = generateConfigFile2(configKey, configs);
700
- await writeFile(path2.join(projectPath, "config", `_${configKey}.yml`), content);
1088
+ await writeFile(path2.join(configDir, `_${configKey}.yml`), content);
701
1089
  }
702
1090
  }
703
- await writeFile(
704
- path2.join(projectPath, "config", "_core.yml"),
705
- generateConfigFile2("core", configs)
706
- );
707
- const { generateEnvExample } = await import('./cli-config-templates-IGGO7P45.js');
708
- await writeFile(
709
- path2.join(projectPath, ".env.example"),
710
- generateEnvExample(resolvedOptions.features, configs)
711
- );
1091
+ if (!isApiWorkspace) {
1092
+ await writeFile(
1093
+ path2.join(configDir, "_core.yml"),
1094
+ generateConfigFile2("core", configs)
1095
+ );
1096
+ }
1097
+ const envExample = isApiWorkspace ? `${generateEnvExample(resolvedOptions.features, configs)}
1098
+ # =============================================================================
1099
+ # Service Runtime
1100
+ # =============================================================================
1101
+ PORT=3000
1102
+ ` : generateEnvExample(resolvedOptions.features, configs);
1103
+ await writeFile(envExamplePath, envExample);
712
1104
  }
713
- const { generateSkillFiles } = await import('./cli-skill-templates-IMYZPQRG.js');
1105
+ const { generateSkillFiles } = await import('./cli-skill-templates-JMSV2SVW.js');
714
1106
  await generateSkillFiles(projectPath, resolvedOptions.features, resolvedOptions.appType);
715
1107
  const appTypeLabel = APP_TYPES[resolvedOptions.appType].name;
716
- const readmeContent = resolvedOptions.appType === "fullstack" ? generateFullstackReadme(resolvedOptions.name, resolvedOptions.packageManager, resolvedOptions.frontends) : generateReadme(resolvedOptions.name, appTypeLabel, resolvedOptions.packageManager);
1108
+ const readmeContent = resolvedOptions.appType === "fullstack" ? generateFullstackReadme(resolvedOptions.name, resolvedOptions.packageManager, resolvedOptions.frontends) : resolvedOptions.appType === "api" ? generateApiWorkspaceReadme(resolvedOptions.name, resolvedOptions.packageManager) : generateReadme(resolvedOptions.name, appTypeLabel, resolvedOptions.packageManager);
717
1109
  await writeFile(
718
1110
  path2.join(projectPath, "README.md"),
719
1111
  readmeContent
@@ -734,8 +1126,7 @@ async function createProject(options) {
734
1126
  }
735
1127
  if (resolvedOptions.install) {
736
1128
  spinner.start(`\u5B89\u88C5\u4F9D\u8D56 (${resolvedOptions.packageManager})...`);
737
- const installCmd = getInstallCommand(resolvedOptions.packageManager);
738
- execSync(installCmd, { cwd: projectPath, stdio: "ignore" });
1129
+ installDependencies(projectPath, resolvedOptions.packageManager);
739
1130
  spinner.succeed();
740
1131
  }
741
1132
  printCompletionMessage(resolvedOptions);
@@ -855,7 +1246,7 @@ async function resolveOptions(options) {
855
1246
  addExamples = examples;
856
1247
  }
857
1248
  const detected = await detectPackageManager(options.cwd ?? ".");
858
- let packageManager = selectedAppType === "fullstack" ? "pnpm" : options.packageManager;
1249
+ let packageManager = selectedAppType === "fullstack" || selectedAppType === "api" ? "pnpm" : options.packageManager;
859
1250
  if (!packageManager && useDefaults) {
860
1251
  packageManager = detected;
861
1252
  }
@@ -1172,6 +1563,50 @@ function getInstallCommand(pm) {
1172
1563
  function getRunCommand(pm, script) {
1173
1564
  return pm === "npm" ? `npm run ${script}` : `${pm} ${script}`;
1174
1565
  }
1566
+ function installDependencies(projectPath, pm) {
1567
+ const installCmd = getInstallCommand(pm);
1568
+ try {
1569
+ execSync(installCmd, {
1570
+ cwd: projectPath,
1571
+ stdio: "pipe",
1572
+ encoding: "utf-8",
1573
+ maxBuffer: 10 * 1024 * 1024
1574
+ });
1575
+ } catch (error) {
1576
+ const details = formatCommandFailure(installCmd, error);
1577
+ throw new Error(`\u5B89\u88C5\u4F9D\u8D56\u5931\u8D25\uFF08${pm}\uFF09\u3002
1578
+ ${details}`);
1579
+ }
1580
+ }
1581
+ function formatCommandFailure(command, error) {
1582
+ if (!error || typeof error !== "object") {
1583
+ return `\u547D\u4EE4: ${command}`;
1584
+ }
1585
+ const failure = error;
1586
+ const stdout = normalizeChildOutput(failure.stdout);
1587
+ const stderr = normalizeChildOutput(failure.stderr);
1588
+ const status = typeof failure.status === "number" ? `\u9000\u51FA\u7801: ${failure.status}` : "";
1589
+ const signal = typeof failure.signal === "string" ? `\u4FE1\u53F7: ${failure.signal}` : "";
1590
+ const output = [
1591
+ `\u547D\u4EE4: ${command}`,
1592
+ status,
1593
+ signal,
1594
+ stderr ? `stderr:
1595
+ ${stderr}` : "",
1596
+ stdout ? `stdout:
1597
+ ${stdout}` : ""
1598
+ ].filter(Boolean);
1599
+ return output.join("\n\n");
1600
+ }
1601
+ function normalizeChildOutput(output) {
1602
+ if (typeof output === "string") {
1603
+ return output.trim();
1604
+ }
1605
+ if (Buffer.isBuffer(output)) {
1606
+ return output.toString("utf-8").trim();
1607
+ }
1608
+ return "";
1609
+ }
1175
1610
  function generateReadme(name, appTypeLabel, pm) {
1176
1611
  const install = getInstallCommand(pm);
1177
1612
  return `# ${name}
@@ -1196,10 +1631,50 @@ ${getRunCommand(pm, "preview")}
1196
1631
  ## \u6587\u6863
1197
1632
 
1198
1633
  - [hai Agent Framework](https://github.com/hai-series/hai-framework)
1199
- - [SvelteKit](https://kit.svelte.dev/)
1200
1634
  - [Svelte 5](https://svelte.dev/)
1201
1635
  `;
1202
1636
  }
1637
+ function generateApiWorkspaceReadme(name, pm) {
1638
+ return `# ${name}
1639
+
1640
+ \u57FA\u4E8E hai Agent Framework \u6784\u5EFA\u7684 typed API workspace\u3002
1641
+
1642
+ ## \u5DE5\u7A0B\u7ED3\u6784
1643
+
1644
+ - \`apps/${name}-contract\`\uFF1A\u5171\u4EAB API contract\u3001Zod schema \u4E0E\u7C7B\u578B
1645
+ - \`apps/${name}-service\`\uFF1A\u540E\u7AEF API service\uFF0C\u57FA\u4E8E \`@h-ai/serv\` \u66B4\u9732 HTTP \u5E94\u7528
1646
+
1647
+ ## \u5F00\u53D1
1648
+
1649
+ \`\`\`bash
1650
+ ${pm} install
1651
+ ${pm} dev
1652
+ \`\`\`
1653
+
1654
+ ## \u8D28\u91CF\u95E8\u7981
1655
+
1656
+ \`\`\`bash
1657
+ ${pm} typecheck
1658
+ ${pm} lint
1659
+ ${pm} build
1660
+ ${pm} test
1661
+ ${pm} test:e2e
1662
+ \`\`\`
1663
+
1664
+ ## \u6269\u5C55\u5EFA\u8BAE
1665
+
1666
+ - \u5728 \`${name}-contract\` \u4E2D\u7EF4\u62A4\u5E94\u7528\u7EA7 contract\uFF0C\u524D\u540E\u7AEF\u5171\u7528\u540C\u4E00\u4EFD\u7C7B\u578B\u4E0E\u8DEF\u5F84\u5B9A\u4E49\u3002
1667
+ - \u5728 \`${name}-service\` \u4E2D\u6269\u5C55 procedures\u3001\u6A21\u5757\u521D\u59CB\u5316\u4E0E\u914D\u7F6E\u3002
1668
+ - \u9700\u8981 IAM / storage / ai \u65F6\uFF0C\u4F18\u5148\u590D\u7528 \`@h-ai/api-contract\` \u4E0E \`@h-ai/serv/features/*\`\u3002
1669
+
1670
+ ## \u6587\u6863
1671
+
1672
+ - [hai Agent Framework](https://github.com/hai-series/hai-framework)
1673
+ - [@h-ai/serv](./.agents/skills/hai-serv/SKILL.md)
1674
+ - [@h-ai/api-contract](./.agents/skills/hai-api-contract/SKILL.md)
1675
+ - [@h-ai/api-client](./.agents/skills/hai-api-client/SKILL.md)
1676
+ `;
1677
+ }
1203
1678
  function generateFullstackReadme(name, pm, frontends) {
1204
1679
  const enabledFrontends = frontends.map((target) => FRONTEND_TARGETS[target].name).join(" / ");
1205
1680
  return `# ${name}
@@ -1218,13 +1693,28 @@ function generateFullstackReadme(name, pm, frontends) {
1218
1693
 
1219
1694
  \u5DF2\u542F\u7528\u524D\u7AEF\uFF1A${enabledFrontends || "Web / App / Desktop"}
1220
1695
 
1221
- ## \u5F00\u53D1
1696
+ ## \u5F00\u53D1\u3001\u7F16\u8BD1\u4E0E\u6253\u5305
1222
1697
 
1223
1698
  \`\`\`bash
1224
1699
  ${pm} install
1225
1700
  ${pm} dev
1701
+
1702
+ # \u4E00\u952E\u7F16\u8BD1\uFF1A\u7C7B\u578B\u68C0\u67E5 + \u5168\u5DE5\u4F5C\u533A\u6784\u5EFA
1703
+ ${pm} compile
1704
+
1705
+ # \u4E00\u952E\u6253\u5305\uFF1AWeb build\u3001App Capacitor sync\u3001Desktop Tauri build\uFF08\u6309\u542F\u7528\u524D\u7AEF\u6267\u884C\uFF09
1706
+ ${pm} package
1707
+
1708
+ # \u90E8\u7F72\u5165\u53E3\uFF1A\u9ED8\u8BA4\u6267\u884C package\uFF0C\u53EF\u66FF\u6362\u4E3A\u56E2\u961F\u81EA\u5DF1\u7684 CI/CD \u53D1\u5E03\u811A\u672C
1709
+ ${pm} deploy
1226
1710
  \`\`\`
1227
1711
 
1712
+ \u524D\u7AEF\u5355\u72EC\u4EA4\u4ED8\u547D\u4EE4\uFF1A
1713
+
1714
+ - Web\uFF1A\`${pm} --filter ${name}-web build\` / \`${pm} --filter ${name}-web package\`
1715
+ - App\uFF1A\`${pm} --filter ${name}-app package\`\uFF0CAndroid/iOS \u53EF\u7528 \`cap:build:android:debug\` / \`cap:build:android:release\` / \`cap:build:ios\`
1716
+ - Desktop\uFF1A\`${pm} --filter ${name}-desktop tauri:dev\` / \`${pm} --filter ${name}-desktop package\`
1717
+
1228
1718
  ## i18n \u4E0E shared \u534F\u540C
1229
1719
 
1230
1720
  - shared\uFF1A\`packages/${name}-shared/project.inlang\` + \`messages/\`\uFF0C\u53EA\u653E\u8DE8\u7AEF\u5171\u4EAB\u7EC4\u4EF6\u6587\u6848\u3002
@@ -1251,7 +1741,6 @@ ${pm} test:e2e
1251
1741
  ## \u6587\u6863
1252
1742
 
1253
1743
  - [hai Agent Framework](https://github.com/hai-series/hai-framework)
1254
- - [SvelteKit](https://kit.svelte.dev/)
1255
1744
  - [@h-ai/serv](./.agents/skills/hai-serv/SKILL.md)
1256
1745
  - [@h-ai/ui](./.agents/skills/hai-ui/SKILL.md)
1257
1746
  `;
@@ -1275,7 +1764,8 @@ function printCompletionMessage(options) {
1275
1764
  if (!options.install) {
1276
1765
  core.logger.info(chalk.cyan(` ${getInstallCommand(options.packageManager)}`));
1277
1766
  }
1278
- if (options.appType === "fullstack") {
1767
+ if (options.appType === "fullstack" || options.appType === "api") {
1768
+ core.logger.info(chalk.cyan(` ${getRunCommand(options.packageManager, "dev")}`));
1279
1769
  core.logger.info(chalk.cyan(` ${getRunCommand(options.packageManager, "typecheck")}`));
1280
1770
  core.logger.info(chalk.cyan(` ${getRunCommand(options.packageManager, "test")}`));
1281
1771
  core.logger.info(chalk.cyan(` ${getRunCommand(options.packageManager, "test:e2e")}`));
@@ -1364,7 +1854,7 @@ async function addModule(options) {
1364
1854
  core.logger.info(`\u53EF\u7528\u6A21\u5757: ${Object.keys(MODULE_MAP).join(", ")}`);
1365
1855
  return;
1366
1856
  }
1367
- const { generateProjectAiSupport, resolveSkillNamesForPackages } = await import('./cli-skill-templates-IMYZPQRG.js');
1857
+ const { generateProjectAiSupport, resolveSkillNamesForPackages } = await import('./cli-skill-templates-JMSV2SVW.js');
1368
1858
  if (moduleDef.packages.every((p) => project.haiPackages.includes(p))) {
1369
1859
  const generatedFiles2 = await generateProjectAiSupport(
1370
1860
  cwd,
@@ -1400,7 +1890,8 @@ async function addModule(options) {
1400
1890
  const pkg = await fse.readJson(pkgPath);
1401
1891
  if (!pkg.dependencies)
1402
1892
  pkg.dependencies = {};
1403
- const depVersion = `^${getCliVersion()}`;
1893
+ const existingHaiSpecifier = Object.entries(pkg.dependencies).find(([pkgName]) => pkgName.startsWith("@h-ai/"))?.[1];
1894
+ const depVersion = existingHaiSpecifier === "catalog:" ? "catalog:" : `^${getCliVersion()}`;
1404
1895
  for (const pkgName of allPackages) {
1405
1896
  if (!pkg.dependencies[pkgName]) {
1406
1897
  pkg.dependencies[pkgName] = depVersion;
@@ -1846,6 +2337,7 @@ export const down: MigrationFn = async (db) => {
1846
2337
  }
1847
2338
  var MODULE_CONFIG_MAP = {
1848
2339
  "@h-ai/core": { configKey: "core", label: "Core" },
2340
+ "@h-ai/serv": { configKey: "serv", label: "Service" },
1849
2341
  "@h-ai/reldb": { configKey: "db", label: "Database" },
1850
2342
  "@h-ai/cache": { configKey: "cache", label: "Cache" },
1851
2343
  "@h-ai/iam": { configKey: "iam", label: "IAM" },
@@ -1965,7 +2457,7 @@ var VERSION = getCliVersion();
1965
2457
  var cli = cac("hai");
1966
2458
  cli.option("-v, --verbose", "\u663E\u793A\u8BE6\u7EC6\u8F93\u51FA");
1967
2459
  cli.option("-C, --cwd <path>", "\u5DE5\u4F5C\u76EE\u5F55");
1968
- cli.command("create [name]", "\u521B\u5EFA\u65B0\u7684 hai \u9879\u76EE").option("--type <type>", "\u5E94\u7528\u7C7B\u578B (admin, website, h5, api, android-app, fullstack)").option("--frontends <targets>", "\u524D\u540E\u7AEF\u5206\u79BB\u5DE5\u7A0B\u524D\u7AEF\u76EE\u6807 (\u9017\u53F7\u5206\u9694: web,app,miniapp,desktop)").option("-t, --template <template>", "\u9879\u76EE\u6A21\u677F (minimal, default, full, custom)").option("-f, --features <features>", "\u529F\u80FD\u5217\u8868 (\u9017\u53F7\u5206\u9694: iam,db,cache,ai,storage,crypto)").option("--examples", "\u6DFB\u52A0\u793A\u4F8B\u4EE3\u7801").option("--no-examples", "\u4E0D\u6DFB\u52A0\u793A\u4F8B\u4EE3\u7801").option("--no-install", "\u4E0D\u5B89\u88C5\u4F9D\u8D56").option("-p, --package-manager <pm>", "\u5305\u7BA1\u7406\u5668 (pnpm, npm, yarn)").option("--no-git", "\u4E0D\u521D\u59CB\u5316 Git").option("--git-remote <url>", "Git \u8FDC\u7A0B\u4ED3\u5E93\u5730\u5740").option("-y, --yes", "\u4F7F\u7528\u9ED8\u8BA4\u914D\u7F6E\uFF0C\u8DF3\u8FC7\u4EA4\u4E92").action(async (name, options) => {
2460
+ cli.command("create [name]", "\u521B\u5EFA\u65B0\u7684 hai \u9879\u76EE").option("--type <type>", "\u5E94\u7528\u7C7B\u578B (admin, website, h5, api, mobile-app, fullstack)").option("--frontends <targets>", "\u524D\u540E\u7AEF\u5206\u79BB\u5DE5\u7A0B\u524D\u7AEF\u76EE\u6807 (\u9017\u53F7\u5206\u9694: web,app,miniapp,desktop)").option("-t, --template <template>", "\u9879\u76EE\u6A21\u677F (minimal, default, full, custom)").option("-f, --features <features>", "\u529F\u80FD\u5217\u8868 (\u9017\u53F7\u5206\u9694: iam,db,cache,ai,storage,crypto)").option("--examples", "\u6DFB\u52A0\u793A\u4F8B\u4EE3\u7801").option("--no-examples", "\u4E0D\u6DFB\u52A0\u793A\u4F8B\u4EE3\u7801").option("--no-install", "\u4E0D\u5B89\u88C5\u4F9D\u8D56").option("-p, --package-manager <pm>", "\u5305\u7BA1\u7406\u5668 (pnpm, npm, yarn)").option("--no-git", "\u4E0D\u521D\u59CB\u5316 Git").option("--git-remote <url>", "Git \u8FDC\u7A0B\u4ED3\u5E93\u5730\u5740").option("-y, --yes", "\u4F7F\u7528\u9ED8\u8BA4\u914D\u7F6E\uFF0C\u8DF3\u8FC7\u4EA4\u4E92").action(async (name, options) => {
1969
2461
  try {
1970
2462
  const features = typeof options.features === "string" ? options.features.split(",").map((f) => f.trim()) : void 0;
1971
2463
  const frontends = typeof options.frontends === "string" ? options.frontends.split(",").map((f) => f.trim()).filter(Boolean) : void 0;