@h-ai/cli 0.1.0-alpha.10

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 (109) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +167 -0
  3. package/dist/chunk-2H7UOFLK.js +10 -0
  4. package/dist/chunk-2H7UOFLK.js.map +1 -0
  5. package/dist/chunk-LANIDJC7.js +659 -0
  6. package/dist/chunk-LANIDJC7.js.map +1 -0
  7. package/dist/chunk-YV7WPUI6.js +206 -0
  8. package/dist/chunk-YV7WPUI6.js.map +1 -0
  9. package/dist/config-templates-S5RI2MC6.js +5 -0
  10. package/dist/config-templates-S5RI2MC6.js.map +1 -0
  11. package/dist/index.d.ts +2 -0
  12. package/dist/index.js +1650 -0
  13. package/dist/index.js.map +1 -0
  14. package/dist/skill-templates-N5DU5FNX.js +5 -0
  15. package/dist/skill-templates-N5DU5FNX.js.map +1 -0
  16. package/dist/src-XJ6YXNAF.js +15030 -0
  17. package/dist/src-XJ6YXNAF.js.map +1 -0
  18. package/package.json +59 -0
  19. package/templates/README.md +126 -0
  20. package/templates/apps/admin/messages/en-US.json +33 -0
  21. package/templates/apps/admin/messages/zh-CN.json +33 -0
  22. package/templates/apps/admin/src/routes/+layout.svelte.hbs +30 -0
  23. package/templates/apps/admin/src/routes/+page.svelte.hbs +35 -0
  24. package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +44 -0
  25. package/templates/apps/admin/src/routes/admin/+page.svelte.hbs +45 -0
  26. package/templates/apps/admin/src/routes/admin/settings/+page.svelte.hbs +37 -0
  27. package/templates/apps/admin/src/routes/api/health/+server.ts +12 -0
  28. package/templates/apps/android-app/.env.hbs +3 -0
  29. package/templates/apps/android-app/capacitor.config.ts.hbs +12 -0
  30. package/templates/apps/android-app/messages/en-US.json +24 -0
  31. package/templates/apps/android-app/messages/zh-CN.json +24 -0
  32. package/templates/apps/android-app/src/lib/api.ts.hbs +30 -0
  33. package/templates/apps/android-app/src/lib/capacitor.ts +21 -0
  34. package/templates/apps/android-app/src/routes/+layout.svelte.hbs +42 -0
  35. package/templates/apps/android-app/src/routes/+layout.ts +7 -0
  36. package/templates/apps/android-app/src/routes/+page.svelte.hbs +27 -0
  37. package/templates/apps/api/src/routes/+layout.svelte +14 -0
  38. package/templates/apps/api/src/routes/+page.svelte +11 -0
  39. package/templates/apps/api/src/routes/api/v1/health/+server.ts +14 -0
  40. package/templates/apps/api/src/routes/api/v1/items/+server.ts +37 -0
  41. package/templates/apps/api/src/routes/api/v1/items/[id]/+server.ts +30 -0
  42. package/templates/apps/h5/messages/en-US.json +37 -0
  43. package/templates/apps/h5/messages/zh-CN.json +37 -0
  44. package/templates/apps/h5/src/routes/+layout.svelte.hbs +57 -0
  45. package/templates/apps/h5/src/routes/+page.svelte.hbs +27 -0
  46. package/templates/apps/h5/src/routes/discover/+page.svelte.hbs +27 -0
  47. package/templates/apps/h5/src/routes/profile/+page.svelte.hbs +27 -0
  48. package/templates/apps/website/messages/en-US.json +32 -0
  49. package/templates/apps/website/messages/zh-CN.json +32 -0
  50. package/templates/apps/website/src/routes/+layout.svelte.hbs +66 -0
  51. package/templates/apps/website/src/routes/+page.svelte.hbs +33 -0
  52. package/templates/apps/website/src/routes/about/+page.svelte.hbs +27 -0
  53. package/templates/apps/website/src/routes/api/health/+server.ts +12 -0
  54. package/templates/apps/website/src/routes/contact/+page.svelte.hbs +59 -0
  55. package/templates/apps/website/src/routes/services/+page.svelte.hbs +63 -0
  56. package/templates/base/e2e/helpers.ts +49 -0
  57. package/templates/base/package.json.hbs +67 -0
  58. package/templates/base/playwright.config.ts +32 -0
  59. package/templates/base/src/app.css +2 -0
  60. package/templates/base/src/app.d.ts.hbs +18 -0
  61. package/templates/base/src/app.html.hbs +16 -0
  62. package/templates/base/src/hooks.server.ts.hbs +123 -0
  63. package/templates/base/src/lib/server/init.ts.hbs +190 -0
  64. package/templates/base/svelte.config.js.hbs +30 -0
  65. package/templates/base/tsconfig.json +8 -0
  66. package/templates/base/vite.config.ts.hbs +27 -0
  67. package/templates/features/ai/routes/api/chat/+server.ts +26 -0
  68. package/templates/features/datapipe/routes/api/datapipe/pipeline/+server.ts +41 -0
  69. package/templates/features/iam/routes-admin/(auth)/+layout.svelte.hbs +21 -0
  70. package/templates/features/iam/routes-admin/(auth)/auth/login/+page.svelte.hbs +98 -0
  71. package/templates/features/iam/routes-admin/(auth)/auth/register/+page.svelte.hbs +124 -0
  72. package/templates/features/iam/routes-h5/auth/login/+page.svelte.hbs +98 -0
  73. package/templates/features/iam/routes-h5/auth/register/+page.svelte.hbs +114 -0
  74. package/templates/features/iam/routes-shared/api/auth/login/+server.ts +32 -0
  75. package/templates/features/iam/routes-shared/api/auth/logout/+server.ts +15 -0
  76. package/templates/features/iam/routes-shared/api/auth/me/+server.ts +12 -0
  77. package/templates/features/iam/routes-shared/api/auth/register/+server.ts +26 -0
  78. package/templates/features/payment/routes/api/v1/payment/create/+server.ts +30 -0
  79. package/templates/features/payment/routes/api/v1/payment/notify/[provider]/+server.ts +42 -0
  80. package/templates/features/payment/routes/api/v1/payment/query/[orderNo]/+server.ts +25 -0
  81. package/templates/features/storage/routes/api/upload/+server.ts +35 -0
  82. package/templates/features/vecdb/routes/api/vecdb/search/+server.ts +36 -0
  83. package/templates/i18n/project.inlang/settings.json +11 -0
  84. package/templates/skills/AGENTS.md +26 -0
  85. package/templates/skills/CLAUDE.md +12 -0
  86. package/templates/skills/copilot-instructions.md +61 -0
  87. package/templates/skills/hai-ai/SKILL.md +721 -0
  88. package/templates/skills/hai-api-client/SKILL.md +355 -0
  89. package/templates/skills/hai-app-create/SKILL.md +371 -0
  90. package/templates/skills/hai-app-review/SKILL.md +156 -0
  91. package/templates/skills/hai-app-tests/SKILL.md +468 -0
  92. package/templates/skills/hai-audit/SKILL.md +145 -0
  93. package/templates/skills/hai-build/SKILL.md +319 -0
  94. package/templates/skills/hai-cache/SKILL.md +190 -0
  95. package/templates/skills/hai-capacitor/SKILL.md +377 -0
  96. package/templates/skills/hai-core/SKILL.md +484 -0
  97. package/templates/skills/hai-crypto/SKILL.md +198 -0
  98. package/templates/skills/hai-datapipe/SKILL.md +220 -0
  99. package/templates/skills/hai-deploy/SKILL.md +216 -0
  100. package/templates/skills/hai-iam/SKILL.md +361 -0
  101. package/templates/skills/hai-kit/SKILL.md +484 -0
  102. package/templates/skills/hai-payment/SKILL.md +275 -0
  103. package/templates/skills/hai-reach/SKILL.md +315 -0
  104. package/templates/skills/hai-reldb/SKILL.md +465 -0
  105. package/templates/skills/hai-scheduler/SKILL.md +188 -0
  106. package/templates/skills/hai-storage/SKILL.md +276 -0
  107. package/templates/skills/hai-ui/SKILL.md +438 -0
  108. package/templates/skills/hai-vecdb/SKILL.md +279 -0
  109. package/templates/skills/opencode.json +11 -0
@@ -0,0 +1,276 @@
1
+ ---
2
+ name: hai-storage
3
+ description: 使用 @h-ai/storage 进行文件存储操作(本地/S3),包括 file/dir/presign 三组能力;当需求涉及文件上传下载、目录批量删除、S3 预签名 URL 或客户端直传时使用。
4
+ ---
5
+
6
+ # hai-storage
7
+
8
+ > `@h-ai/storage` 提供统一文件存储接口,支持本地文件系统(LocalProvider)和 S3 兼容存储(S3Provider),通过 `storage.file`、`storage.dir`、`storage.presign` 三组接口访问能力。
9
+
10
+ ---
11
+
12
+ ## 运行环境
13
+
14
+ > ⚠️ **服务端模块**。`storage.file` / `storage.dir` / `storage.presign` 均在 Node.js 端使用。浏览器端通过预签名 URL 或 API 端点间接访问存储(见下方「浏览器端文件上传」)。
15
+
16
+ ---
17
+
18
+ ## 适用场景
19
+
20
+ - 文件上传与下载
21
+ - 预签名 URL 生成(客户端直传)
22
+ - S3 兼容存储对接(AWS S3、MinIO、阿里云 OSS 等)
23
+ - 本地开发文件存储
24
+ - 目录前缀清理与批量文件删除
25
+
26
+ ---
27
+
28
+ ## 使用步骤
29
+
30
+ ### 1. 配置
31
+
32
+ ```yaml
33
+ # config/_storage.yml
34
+ type: ${HAI_STORAGE_TYPE:local} # local | s3
35
+ # 本地存储
36
+ root: ${HAI_STORAGE_PATH:./data/storage}
37
+ # S3 存储(type=s3 时生效)
38
+ # endpoint: ${HAI_STORAGE_S3_ENDPOINT:}
39
+ # region: ${HAI_STORAGE_S3_REGION:us-east-1}
40
+ # accessKeyId: ${HAI_STORAGE_S3_ACCESS_KEY:}
41
+ # secretAccessKey: ${HAI_STORAGE_S3_SECRET_KEY:}
42
+ # bucket: ${HAI_STORAGE_S3_BUCKET:my-bucket}
43
+ # forcePathStyle: false
44
+ # prefix: ''
45
+ # publicUrl: ''
46
+ ```
47
+
48
+ ### 2. 初始化与关闭
49
+
50
+ ```typescript
51
+ import { storage } from '@h-ai/storage'
52
+
53
+ await storage.init(core.config.get('storage'))
54
+ // 使用后关闭
55
+ await storage.close()
56
+ ```
57
+
58
+ ---
59
+
60
+ ## 核心 API
61
+
62
+ ### 文件操作
63
+
64
+ `storage.file` 提供以下方法:
65
+
66
+ - `put(key, data, options?)`
67
+ - `get(key, options?)`
68
+ - `head(key)`
69
+ - `exists(key)`
70
+ - `delete(key)`
71
+ - `deleteMany(keys)`
72
+ - `copy(sourceKey, destKey, options?)`
73
+
74
+ ```typescript
75
+ // 上传文件
76
+ const result = await storage.file.put('avatars/user-123.png', fileBuffer, {
77
+ contentType: 'image/png',
78
+ metadata: { userId: '123' },
79
+ })
80
+
81
+ // 下载文件
82
+ const file = await storage.file.get('avatars/user-123.png')
83
+
84
+ // 列出文件
85
+ const files = await storage.dir.list({ prefix: 'avatars/', maxKeys: 100 })
86
+ ```
87
+
88
+ ### 预签名 URL
89
+
90
+ `storage.presign` 提供以下方法:
91
+
92
+ - `getUrl(key, options?)`
93
+ - `putUrl(key, options?)`
94
+ - `publicUrl(key)`
95
+
96
+ ```typescript
97
+ // 客户端直传模式
98
+ const uploadUrl = await storage.presign.putUrl('uploads/doc.pdf', {
99
+ expiresIn: 3600, // 1 小时有效
100
+ contentType: 'application/pdf',
101
+ })
102
+
103
+ // 临时下载链接
104
+ const downloadUrl = await storage.presign.getUrl('uploads/doc.pdf', {
105
+ expiresIn: 300, // 5 分钟有效
106
+ })
107
+ ```
108
+
109
+ ---
110
+
111
+ ## 错误码 — `HaiStorageError`
112
+
113
+ | 错误码 | code | 说明 |
114
+ |--------|------|------|
115
+ | `HaiStorageError.CONNECTION_FAILED` | `hai:storage:001` | 连接失败 |
116
+ | `HaiStorageError.OPERATION_FAILED` | `hai:storage:002` | 操作失败 |
117
+ | `HaiStorageError.NOT_FOUND` | `hai:storage:003` | 文件不存在 |
118
+ | `HaiStorageError.ALREADY_EXISTS` | `hai:storage:004` | 文件已存在 |
119
+ | `HaiStorageError.PERMISSION_DENIED` | `hai:storage:005` | 权限不足 |
120
+ | `HaiStorageError.QUOTA_EXCEEDED` | `hai:storage:006` | 配额超限 |
121
+ | `HaiStorageError.INVALID_PATH` | `hai:storage:007` | 路径无效 |
122
+ | `HaiStorageError.IO_ERROR` | `hai:storage:008` | IO 错误 |
123
+ | `HaiStorageError.NETWORK_ERROR` | `hai:storage:009` | 网络错误 |
124
+ | `HaiStorageError.NOT_INITIALIZED` | `hai:storage:010` | 未初始化 |
125
+ | `HaiStorageError.UNSUPPORTED_TYPE` | `hai:storage:011` | 不支持的存储类型 |
126
+ | `HaiStorageError.CONFIG_ERROR` | `hai:storage:012` | 配置错误 |
127
+ | `HaiStorageError.PRESIGN_FAILED` | `hai:storage:013` | 预签名 URL 生成失败 |
128
+ | `HaiStorageError.UPLOAD_FAILED` | `hai:storage:014` | 上传失败 |
129
+ | `HaiStorageError.DOWNLOAD_FAILED` | `hai:storage:015` | 下载失败 |
130
+
131
+ ---
132
+
133
+ ## API 契约(`@h-ai/storage/api`)
134
+
135
+ `@h-ai/storage/api` 子路径导出所有存储端点的 Zod Schema 和端点契约定义,客户端与服务端共享同一份真相源,编译时保证 I/O 一致性。
136
+
137
+ ### 端点定义 — `storageEndpoints`
138
+
139
+ | 端点名 | method | path | input Schema | output Schema |
140
+ | ------------------ | ------ | ---------------------------- | ------------------------ | ------------------------ |
141
+ | `presignDownload` | POST | `/storage/presign/download` | `PresignGetInputSchema` | `PresignUrlOutputSchema` |
142
+ | `presignUpload` | POST | `/storage/presign/upload` | `PresignPutInputSchema` | `PresignUrlOutputSchema` |
143
+ | `fileInfo` | POST | `/storage/file/info` | `FileInfoInputSchema` | `FileMetadataSchema` |
144
+ | `listFiles` | GET | `/storage/files` | inline(prefix/maxKeys) | `ListFilesOutputSchema` |
145
+ | `deleteFile` | POST | `/storage/file/delete` | `DeleteFileInputSchema` | `z.void()` |
146
+ | `deleteFiles` | POST | `/storage/files/delete` | `DeleteFilesInputSchema` | `z.void()` |
147
+
148
+ ### 使用示例
149
+
150
+ ```typescript
151
+ import { storageEndpoints, PresignPutInputSchema } from '@h-ai/storage/api'
152
+
153
+ // 客户端:通过 api-client 调用端点
154
+ const { url } = await api.call(storageEndpoints.presignUpload, { key: 'avatar.png' })
155
+
156
+ // 服务端:基于契约定义路由
157
+ export const POST = kit.fromContract(storageEndpoints.presignUpload, async (input) => {
158
+ const result = await storage.presign.putUrl(input.key, input)
159
+ return result.success ? result.data : kit.response.internalError(result.error.message)
160
+ })
161
+
162
+ // 独立 Schema 校验
163
+ const parsed = PresignPutInputSchema.safeParse(requestBody)
164
+ if (!parsed.success) { /* 校验失败 */ }
165
+ ```
166
+
167
+ ### 导出的 Schema
168
+
169
+ - `FileMetadataSchema` — 文件元数据(key / size / contentType / lastModified / etag? / metadata?)
170
+ - `PresignGetInputSchema` — 下载签名入参(key + expiresIn?)
171
+ - `PresignPutInputSchema` — 上传签名入参(key + contentType? + contentLength? + expiresIn?)
172
+ - `PresignUrlOutputSchema` — 签名 URL 出参(url + key + expiresAt?)
173
+ - `ListFilesOutputSchema` — 文件列表出参(files + commonPrefixes + isTruncated + nextContinuationToken?)
174
+ - `DeleteFileInputSchema` — 删除单文件入参(key)
175
+ - `DeleteFilesInputSchema` — 批量删除入参(keys[])
176
+ - `FileInfoInputSchema` — 文件信息入参(key)
177
+
178
+ ### 导出的推导类型
179
+
180
+ `PresignGetInput` / `PresignPutInput` / `PresignUrlOutput` / `ListFilesOutput` / `DeleteFileInput` / `DeleteFilesInput` / `FileInfoInput`
181
+
182
+ ---
183
+
184
+ ## 常见模式
185
+
186
+ ### 与 kit 集成(文件上传 API)
187
+
188
+ ```typescript
189
+ import { storage } from '$lib/server/init'
190
+ // src/routes/api/files/upload/+server.ts
191
+ import { kit } from '@h-ai/kit'
192
+ import { z } from 'zod'
193
+
194
+ const UploadSchema = z.object({
195
+ key: z.string().min(1),
196
+ })
197
+
198
+ export const POST = kit.handler(async ({ request, locals }) => {
199
+ kit.guard.requirePermission(locals.session, 'storage:write')
200
+ const formData = await request.formData()
201
+ const file = formData.get('file') as File
202
+ if (!file)
203
+ return kit.response.badRequest('Missing file')
204
+
205
+ const key = `uploads/${locals.session.userId}/${file.name}`
206
+ const buffer = new Uint8Array(await file.arrayBuffer())
207
+ const result = await storage.file.put(key, buffer, { contentType: file.type })
208
+ if (!result.success)
209
+ return kit.response.internalError()
210
+ return kit.response.created({ key })
211
+ })
212
+ ```
213
+
214
+ > 说明:`@h-ai/storage` 只提供存储能力,不强制要求 `/api/storage` 路由命名。应用可按业务语义自定义 API 路径。
215
+
216
+ ### 头像上传
217
+
218
+ ```typescript
219
+ const key = `avatars/${userId}/${Date.now()}.png`
220
+ const result = await storage.file.put(key, avatarBuffer, {
221
+ contentType: 'image/png',
222
+ })
223
+ if (result.success) {
224
+ const publicUrl = storage.presign.publicUrl(key)
225
+ await iam.user.updateUser(userId, { avatarUrl: publicUrl ?? '' })
226
+ }
227
+ ```
228
+
229
+ ---
230
+
231
+ ## 浏览器端文件上传(预签名 URL 模式)
232
+
233
+ 浏览器端无法直接使用 `storage` 模块,应通过 API 获取预签名 URL 后直传:
234
+
235
+ ```typescript
236
+ import { apiFetch } from '$lib/utils/api'
237
+
238
+ // 1. 向服务端请求预签名上传 URL
239
+ const res = await apiFetch('/api/storage/presign/upload', {
240
+ method: 'POST',
241
+ headers: { 'Content-Type': 'application/json' },
242
+ body: JSON.stringify({ key: `uploads/${file.name}`, contentType: file.type }),
243
+ })
244
+ const { url } = await res.json()
245
+
246
+ // 2. 浏览器直传到存储(不经过服务端,大文件友好)
247
+ await fetch(url, {
248
+ method: 'PUT',
249
+ body: file,
250
+ headers: { 'Content-Type': file.type },
251
+ })
252
+ ```
253
+
254
+ 也可使用契约调用(需配合 `@h-ai/api-client`):
255
+
256
+ ```typescript
257
+ import { api } from '@h-ai/api-client'
258
+ import { storageEndpoints } from '@h-ai/storage/api'
259
+
260
+ const result = await api.call(storageEndpoints.presignUpload, {
261
+ key: `avatars/${userId}.png`,
262
+ contentType: 'image/png',
263
+ })
264
+ if (result.success) {
265
+ await fetch(result.data.url, { method: 'PUT', body: file })
266
+ }
267
+ ```
268
+
269
+ ---
270
+
271
+ ## 相关 Skills
272
+
273
+ - `hai-build`:模块初始化顺序
274
+ - `hai-core`:配置与 HaiResult 模型
275
+ - `hai-kit`:SvelteKit API 端点集成(`kit.handler` + `kit.guard`)
276
+ - `hai-ui`:Storage 场景组件(FileUpload/ImageUpload/AvatarUpload)