@h-ai/cli 0.1.0-alpha.67 → 0.1.0-alpha.68
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.
- package/README.en.md +40 -4
- package/README.ja.md +40 -4
- package/README.md +40 -4
- package/dist/{src-2V6VP4I5.js → chunk-FI56GONY.js} +32 -3103
- package/dist/chunk-FI56GONY.js.map +1 -0
- package/dist/chunk-MBPB37FR.js +1348 -0
- package/dist/chunk-MBPB37FR.js.map +1 -0
- package/dist/{chunk-7DSURTJ4.js → chunk-ZFNBUF77.js} +327 -199
- package/dist/chunk-ZFNBUF77.js.map +1 -0
- package/dist/cli-config-templates-W2LLPMB6.js +5 -0
- package/dist/{cli-config-templates-6AHNUGBN.js.map → cli-config-templates-W2LLPMB6.js.map} +1 -1
- package/dist/{cli-skill-templates-FC3QRKDO.js → cli-skill-templates-US5CCAJ4.js} +3 -3
- package/dist/{cli-skill-templates-FC3QRKDO.js.map → cli-skill-templates-US5CCAJ4.js.map} +1 -1
- package/dist/index.js +920 -336
- package/dist/index.js.map +1 -1
- package/dist/metafile-esm.json +1 -0
- package/dist/src-DSJJXM2F.js +3849 -0
- package/dist/src-DSJJXM2F.js.map +1 -0
- package/package.json +9 -8
- package/templates/apps/admin/messages/ja-JP.json +38 -0
- package/templates/apps/admin/src/routes/+layout.svelte.hbs +16 -6
- package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +3 -3
- package/templates/apps/api/apps/{{projectName}}-contract/src/index.ts.hbs +2 -0
- package/templates/apps/api/apps/{{projectName}}-contract/src/{{projectName}}-contract.ts.hbs +4 -1
- package/templates/apps/api/apps/{{projectName}}-service/README.md.hbs +5 -1
- package/templates/apps/api/apps/{{projectName}}-service/config/_core.yml.hbs +0 -10
- package/templates/apps/api/apps/{{projectName}}-service/config/_serv.yml.hbs +2 -1
- package/templates/apps/api/apps/{{projectName}}-service/src/app.ts.hbs +24 -11
- package/templates/apps/api/apps/{{projectName}}-service/src/index.ts.hbs +8 -1
- package/templates/apps/api/apps/{{projectName}}-service/src/lib/server/init.ts.hbs +68 -11
- package/templates/apps/api/apps/{{projectName}}-service/src/server/procedures/index.ts.hbs +10 -2
- package/templates/apps/api/e2e/api-service.spec.ts.hbs +2 -2
- package/templates/apps/api/package.json.hbs +1 -1
- package/templates/apps/api/playwright.config.ts.hbs +15 -7
- package/templates/apps/fullstack/apps/{{projectName}}-app/README.md.hbs +1 -1
- package/templates/apps/fullstack/apps/{{projectName}}-app/messages/ja-JP.json.hbs +7 -0
- package/templates/apps/fullstack/apps/{{projectName}}-app/src/App.svelte.hbs +7 -1
- package/templates/apps/fullstack/apps/{{projectName}}-app/vite.config.ts.hbs +1 -1
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/README.md.hbs +1 -1
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/messages/ja-JP.json.hbs +7 -0
- package/templates/apps/fullstack/apps/{{projectName}}-desktop/vite.config.ts.hbs +1 -1
- package/templates/apps/fullstack/apps/{{projectName}}-miniapp/messages/ja-JP.json.hbs +12 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/README.md.hbs +1 -1
- package/templates/apps/fullstack/apps/{{projectName}}-web/messages/ja-JP.json.hbs +7 -0
- package/templates/apps/fullstack/apps/{{projectName}}-web/vite.config.ts.hbs +1 -1
- package/templates/apps/fullstack/e2e/fullstack.spec.ts.hbs +19 -8
- package/templates/apps/fullstack/package.json.hbs +1 -1
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/admin-schemas.ts.hbs +1 -1
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/index.ts.hbs +2 -0
- package/templates/apps/fullstack/packages/{{projectName}}-contract/src/{{projectName}}-contract.ts.hbs +3 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +5 -2
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_core.yml.hbs +0 -6
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_reach.yml.hbs +8 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/config/_serv.yml.hbs +2 -1
- package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +6 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/app-server.ts.hbs +9 -5
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/admin-service.ts.hbs +3 -2
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/messages.ts.hbs +16 -1
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/admin-procedures.ts.hbs +7 -3
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/procedures/index.ts.hbs +3 -0
- package/templates/apps/fullstack/packages/{{projectName}}-serv/src/server/runtime.ts.hbs +58 -7
- package/templates/apps/fullstack/packages/{{projectName}}-serv/tests/app-server.test.ts.hbs +13 -3
- package/templates/apps/fullstack/packages/{{projectName}}-shared/README.md.hbs +9 -4
- package/templates/apps/fullstack/packages/{{projectName}}-shared/messages/ja-JP.json.hbs +105 -0
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AdminWorkspace.svelte.hbs +3 -3
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AppShell.svelte.hbs +5 -5
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/audit.svelte.hbs +7 -7
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/settings.svelte.hbs +1 -1
- package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/users.svelte.hbs +8 -8
- package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/api-client.test.ts.hbs +11 -12
- package/templates/apps/fullstack/playwright.config.ts.hbs +15 -6
- package/templates/apps/h5/messages/ja-JP.json +40 -0
- package/templates/apps/h5/src/routes/+layout.svelte.hbs +14 -3
- package/templates/apps/mobile-app/messages/ja-JP.json +36 -0
- package/templates/apps/mobile-app/src/App.svelte.hbs +13 -3
- package/templates/apps/mobile-app/src/lib/api.ts.hbs +173 -14
- package/templates/apps/website/messages/ja-JP.json +32 -0
- package/templates/apps/website/src/routes/+layout.svelte.hbs +10 -2
- package/templates/base/e2e/app.spec.ts.hbs +13 -8
- package/templates/base/package.json.hbs +4 -1
- package/templates/base/playwright.config.ts +15 -4
- package/templates/base/src/hooks.server.ts.hbs +15 -6
- package/templates/base/src/lib/server/init.ts.hbs +139 -30
- package/templates/base/vite.config.ts.hbs +2 -2
- package/templates/features/iam/routes-shared/api/auth/logout/+server.ts +11 -6
- package/templates/features/payment/routes/api/v1/payment/create/+server.ts +18 -25
- package/templates/features/payment/routes/api/v1/payment/notify/[provider]/+server.ts +4 -0
- package/templates/i18n/project.inlang/settings.json +1 -1
- package/templates/shared/e2e-env.ts +98 -0
- package/templates/shared/run-e2e.mjs +51 -12
- package/templates/skills/AGENTS.md +4 -0
- package/templates/skills/bridges/admin/AGENTS.md +5 -1
- package/templates/skills/bridges/api/AGENTS.md +2 -0
- package/templates/skills/bridges/fullstack/AGENTS.md.hbs +4 -0
- package/templates/skills/bridges/h5/AGENTS.md +5 -1
- package/templates/skills/bridges/mobile-app/AGENTS.md +5 -1
- package/templates/skills/bridges/website/AGENTS.md +5 -1
- package/templates/skills/hai-ai/SKILL.md +8 -2
- package/templates/skills/hai-ai/guide.md +134 -60
- package/templates/skills/hai-ai/reference.md +51 -11
- package/templates/skills/hai-api-client/SKILL.md +2 -0
- package/templates/skills/hai-api-client/reference.md +17 -5
- package/templates/skills/hai-api-contract/SKILL.md +1 -0
- package/templates/skills/hai-api-contract/reference.md +4 -2
- package/templates/skills/hai-app-create/SKILL.md +4 -0
- package/templates/skills/hai-app-create/development.md +20 -4
- package/templates/skills/hai-app-create/reference.md +2 -1
- package/templates/skills/hai-app-review/SKILL.md +6 -2
- package/templates/skills/hai-app-review/differential.md +34 -0
- package/templates/skills/hai-app-tests/SKILL.md +3 -1
- package/templates/skills/hai-app-tests/reference.md +4 -4
- package/templates/skills/hai-app-tests/validation.md +10 -3
- package/templates/skills/hai-audit/SKILL.md +10 -8
- package/templates/skills/hai-audit/reference.md +3 -0
- package/templates/skills/hai-build/reference.md +6 -4
- package/templates/skills/hai-cache/SKILL.md +9 -3
- package/templates/skills/hai-cache/reference.md +53 -11
- package/templates/skills/hai-capacitor/SKILL.md +3 -1
- package/templates/skills/hai-capacitor/reference.md +9 -5
- package/templates/skills/hai-core/SKILL.md +4 -0
- package/templates/skills/hai-core/reference.md +25 -5
- package/templates/skills/hai-crypto/SKILL.md +10 -2
- package/templates/skills/hai-crypto/reference.md +64 -10
- package/templates/skills/hai-datapipe/SKILL.md +2 -0
- package/templates/skills/hai-datapipe/reference.md +3 -1
- package/templates/skills/hai-deploy/SKILL.md +9 -4
- package/templates/skills/hai-deploy/middleware.md +51 -37
- package/templates/skills/hai-iam/SKILL.md +24 -8
- package/templates/skills/hai-iam/reference.md +181 -154
- package/templates/skills/hai-kit/SKILL.md +23 -7
- package/templates/skills/hai-kit/reference.md +42 -24
- package/templates/skills/hai-payment/SKILL.md +13 -11
- package/templates/skills/hai-payment/reference.md +80 -41
- package/templates/skills/hai-pr-review/SKILL.md +21 -88
- package/templates/skills/hai-reach/SKILL.md +5 -2
- package/templates/skills/hai-reach/reference.md +83 -22
- package/templates/skills/hai-reldb/SKILL.md +5 -2
- package/templates/skills/hai-reldb/reference.md +68 -25
- package/templates/skills/hai-scheduler/SKILL.md +8 -5
- package/templates/skills/hai-scheduler/reference.md +38 -24
- package/templates/skills/hai-serv/SKILL.md +23 -8
- package/templates/skills/hai-serv/reference.md +123 -87
- package/templates/skills/hai-spec-implement/SKILL.md +4 -0
- package/templates/skills/hai-spec-implement/evaluation.md +18 -0
- package/templates/skills/hai-spec-implement/handoff.md +47 -0
- package/templates/skills/hai-spec-implement/templates.md +5 -0
- package/templates/skills/hai-spec-implement/workflow.md +2 -0
- package/templates/skills/hai-spec-review/SKILL.md +4 -0
- package/templates/skills/hai-storage/SKILL.md +8 -2
- package/templates/skills/hai-storage/reference.md +64 -25
- package/templates/skills/hai-ui/SKILL.md +16 -2
- package/templates/skills/hai-ui/guide.md +3 -3
- package/templates/skills/hai-ui/reference.md +17 -6
- package/templates/skills/hai-ui-design/SKILL.md +31 -0
- package/templates/skills/hai-ui-design/patterns.md +26 -0
- package/templates/skills/hai-ui-review/SKILL.md +30 -0
- package/templates/skills/hai-ui-review/checklist.md +22 -0
- package/templates/skills/hai-vecdb/SKILL.md +12 -8
- package/templates/skills/hai-vecdb/reference.md +33 -3
- package/dist/chunk-7DSURTJ4.js.map +0 -1
- package/dist/chunk-AOQ4N657.js +0 -640
- package/dist/chunk-AOQ4N657.js.map +0 -1
- package/dist/cli-config-templates-6AHNUGBN.js +0 -5
- package/dist/src-2V6VP4I5.js.map +0 -1
|
@@ -12,15 +12,17 @@ description: "实现本地/S3 文件与目录操作、流式读写、checksum
|
|
|
12
12
|
| 能力 | 使用 @h-ai/storage 访问本地/S3 文件、目录和预签名上传下载 |
|
|
13
13
|
| 适用场景 | 文件接口、目录操作或浏览器直传 |
|
|
14
14
|
| 输入 | StorageConfigInput、文件 key、内容、presign 选项 |
|
|
15
|
-
| 输出 | file/dir/presign 操作的 HaiResult;checksum 生成字符串或校验结果 |
|
|
16
|
-
| 限制 |
|
|
15
|
+
| 输出 | file/dir/presign 操作的 HaiResult;deleteMany 的成功 data/失败 error.ext.deleteMany 保留逐项进度;checksum 生成字符串或校验结果 |
|
|
16
|
+
| 限制 | 仅服务端;预签名仅 S3,local getUrl/putUrl 返回 UNSUPPORTED_OPERATION、publicUrl 为 null;浏览器先检查 API success 再直传。Local list 使用绑定根目录/prefix/delimiter 的无状态游标,files 与 commonPrefixes 共用 maxKeys(1–1000);可跨实例续页,每次仍扫描排序且非快照,游标不代替前缀授权。putUrl 不提供 maxSize 强制约束,上传大小须服务端验证。 |
|
|
17
17
|
|
|
18
18
|
## 使用路径
|
|
19
19
|
|
|
20
20
|
1. Node 端配置 Local/S3,校验并检查 init;MinIO/RustFS 使用 s3 类型,确认桶和权限。
|
|
21
21
|
2. 从 file/dir/presign 选择操作,检查 HaiResult。流与 checksum 按真实签名处理,checksum 在 Node 无需 init。
|
|
22
22
|
3. 客户端经受保护 API 或预签名 URL,服务端校验路径、内容、大小及资源权限;putUrl 不强制 maxSize。
|
|
23
|
+
进度上传使用原生 XHR;预取消不发送,取消/错误一次结算并清理监听,完成后取消不影响旧请求。取消不回滚远端对象,先核对状态再授权删除。
|
|
23
24
|
4. 不覆盖上传使用 ifNoneMatch;冲突/checksum 失败不能伪装成功。验证取消、流错误和文件清理,最后 close。
|
|
25
|
+
5. 批量删除核对逐项进度,S3 每批最多 1000 项;HTTP 200 不能代替成功判断。unknown 结果先核对业务状态,避免重删并发新对象;dir.delete 不保证隔离并发写入或清除 S3 历史版本。
|
|
24
26
|
|
|
25
27
|
## 按需参考
|
|
26
28
|
|
|
@@ -35,3 +37,7 @@ description: "实现本地/S3 文件与目录操作、流式读写、checksum
|
|
|
35
37
|
- [常见模式](reference.md#常见模式)
|
|
36
38
|
- [浏览器端文件上传(预签名 URL 模式)](reference.md#浏览器端文件上传预签名-url-模式)
|
|
37
39
|
- [相关 Skills](reference.md#相关-skills)
|
|
40
|
+
|
|
41
|
+
## 跨端输入与能力约束
|
|
42
|
+
|
|
43
|
+
key 统一使用 `@h-ai/storage/schemas` 的 StorageKeySchema(UTF-8 最多1024字节,无绝对路径/反斜线/控制符/点路径段),prefix另允许空串与部分文件名。HTTP批量删除按原数组限制1–1000项,不能以去重绕过;Node仍按Provider分批。签名有效期整数1–604800秒,Node默认3600、HTTP默认900。HTTP上传只接受key/contentType/expiresIn,不接受contentLength/maxSize/metadata/checksum等file.put选项;未知字段返回400,typed client为VALIDATION_FAILED。Node流式读写、Range、checksum、条件写等无默认HTTP端点。FileUpload大小/类型仅为前端选择体验,服务端仍需验证实际对象与归属;不要编造上传代理端点。校验不替代session资源授权及Provider防逃逸。
|
|
@@ -61,6 +61,19 @@ if (!closeResult.success) {
|
|
|
61
61
|
}
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
+
|
|
65
|
+
初始化只在健康检查成功后发布连接;失败时释放候选资源。若清理仍失败,初始化错误的 `error.ext.cleanupPending` 为 `true`。`storage.close()` 返回 `Promise<HaiResult<void>>`,等待正在进行的初始化,并合并并发关闭。开始清理后 `isInitialized` 为 `false`,配置与业务操作不再可用;清理失败仍保留资源,后续 `close()` 或 `init()` 先重试释放,成功前不会创建替代连接。调用方必须检查关闭结果。
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
const closed = await storage.close()
|
|
69
|
+
if (!closed.success) {
|
|
70
|
+
// 处理清理故障后有限重试;再次失败应向应用报告。
|
|
71
|
+
const retried = await storage.close()
|
|
72
|
+
if (!retried.success) throw new Error(retried.error.message)
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
|
|
64
77
|
> `storage.config` 返回的是**脱敏配置快照**;S3 的 `accessKeyId` / `secretAccessKey` 等敏感字段会被替换为 `[REDACTED]`。
|
|
65
78
|
|
|
66
79
|
## 核心 API
|
|
@@ -92,6 +105,21 @@ const file = await storage.file.get('avatars/user-123.png')
|
|
|
92
105
|
const files = await storage.dir.list({ prefix: 'avatars/', maxKeys: 100 })
|
|
93
106
|
```
|
|
94
107
|
|
|
108
|
+
`file.deleteMany(keys)` 返回 `StorageDeleteResult`:成功时 `data` 为 `{ deletedKeys, failures: [] }`;任一删除项未确认完成时返回 `OPERATION_FAILED`,进度在 `error.ext?.deleteMany`(初始化等前置错误可能不带进度)。重复输入只处理一次,输出 key 不含配置 prefix。S3 每批最多 1000 项,逐项检查 `Deleted` 与 `Errors`;HTTP 200 不代表全部成功,遗漏/重复/未知回执标为 `unknown`。本地删除最多并发 32 项。
|
|
109
|
+
|
|
110
|
+
只对明确的 `InternalError / ServiceUnavailable / SlowDown / RequestTimeout` 项最多尝试三次;成功及权限失败项不重发。`DeleteObjects` 专用客户端禁用 SDK 请求重试;网络中断立即标为 `unknown`,未发送的后续批次标为 `notAttempted`,不盲目重放未知结果。`retryable` 只表示故障类别,调用方重试前仍须核对未知结果及并发写入。`dir.delete()` 传播删除失败;它不能阻止并发新增对象。S3 使用不带 VersionId 的删除,开启版本控制的桶可能创建删除标记,不保证清除历史版本。
|
|
111
|
+
|
|
112
|
+
`@h-ai/serv` / `@h-ai/api-client` 的 `storage.files.deleteMany` 使用同一成功结构并透传失败进度。
|
|
113
|
+
|
|
114
|
+
```ts
|
|
115
|
+
const result = await storage.file.deleteMany(['a.txt', 'b.txt'])
|
|
116
|
+
if (!result.success) {
|
|
117
|
+
const progress = result.error.ext?.deleteMany
|
|
118
|
+
// 结合 outcome 与业务写入状态决定补偿;未知结果不能当作未执行。
|
|
119
|
+
const knownFailures = progress?.failures.filter(item => item.outcome === 'failed' && item.retryable) ?? []
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
95
123
|
### 预签名 URL
|
|
96
124
|
|
|
97
125
|
`storage.presign` 提供以下方法:
|
|
@@ -100,17 +128,21 @@ const files = await storage.dir.list({ prefix: 'avatars/', maxKeys: 100 })
|
|
|
100
128
|
- `putUrl(key, options?)`
|
|
101
129
|
- `publicUrl(key)`
|
|
102
130
|
|
|
131
|
+
预签名仅支持 S3;local `getUrl` / `putUrl` 返回 `HaiStorageError.UNSUPPORTED_OPERATION`(hai:storage:018),`publicUrl` 返回 null,不生成虚拟 URL。serv 与 apiClient 保留失败,须先检查 success;本地文件由应用已有的鉴权接口上传/下载,不假定框架内置签名路由。
|
|
132
|
+
|
|
103
133
|
```typescript
|
|
104
134
|
// 客户端直传模式
|
|
105
135
|
const uploadUrl = await storage.presign.putUrl('uploads/doc.pdf', {
|
|
106
136
|
expiresIn: 3600, // 1 小时有效
|
|
107
137
|
contentType: 'application/pdf',
|
|
108
138
|
})
|
|
139
|
+
if (!uploadUrl.success) return uploadUrl
|
|
109
140
|
|
|
110
141
|
// 临时下载链接
|
|
111
142
|
const downloadUrl = await storage.presign.getUrl('uploads/doc.pdf', {
|
|
112
143
|
expiresIn: 300, // 5 分钟有效
|
|
113
144
|
})
|
|
145
|
+
if (!downloadUrl.success) return downloadUrl
|
|
114
146
|
```
|
|
115
147
|
|
|
116
148
|
> `storage.presign.putUrl()` 当前不支持 `maxSize` 约束参数;如需大小限制,请在应用层上传前校验,或在服务端落库/回调处二次校验。
|
|
@@ -125,6 +157,8 @@ const downloadUrl = await storage.presign.getUrl('uploads/doc.pdf', {
|
|
|
125
157
|
| `HaiStorageError.ALREADY_EXISTS` | `hai:storage:004` | 文件已存在 |
|
|
126
158
|
| `HaiStorageError.CHECKSUM_FAILED` | `hai:storage:016` | checksum 读取/计算失败 |
|
|
127
159
|
| `HaiStorageError.INVALID_CHECKSUM` | `hai:storage:017` | checksum 格式/算法非法 |
|
|
160
|
+
| `HaiStorageError.UNSUPPORTED_OPERATION` | `hai:storage:018` | 当前 Provider 不支持该操作(local 预签名) |
|
|
161
|
+
| `HaiStorageError.INVALID_LIST_OPTIONS` | `hai:storage:019` | 本地列表参数或游标无效、查询范围不匹配 |
|
|
128
162
|
| `HaiStorageError.PERMISSION_DENIED` | `hai:storage:005` | 权限不足 |
|
|
129
163
|
| `HaiStorageError.QUOTA_EXCEEDED` | `hai:storage:006` | 配额超限 |
|
|
130
164
|
| `HaiStorageError.INVALID_PATH` | `hai:storage:007` | 路径无效 |
|
|
@@ -145,6 +179,7 @@ const downloadUrl = await storage.presign.getUrl('uploads/doc.pdf', {
|
|
|
145
179
|
import { apiClient } from '@h-ai/api-client'
|
|
146
180
|
|
|
147
181
|
const result = await apiClient.storage.presignedUrls.createUpload({ key: 'avatar.png' })
|
|
182
|
+
if (!result.success) return result
|
|
148
183
|
```
|
|
149
184
|
|
|
150
185
|
## 常见模式
|
|
@@ -183,7 +218,21 @@ export const POST = kit.handler(async ({ request, locals }) => {
|
|
|
183
218
|
|
|
184
219
|
> 说明:`@h-ai/storage` 只提供存储能力,不强制要求 `/api/storage` 路由命名。应用可按业务语义自定义 API 路径。
|
|
185
220
|
|
|
186
|
-
|
|
221
|
+
### 列表分页
|
|
222
|
+
|
|
223
|
+
Local 的 `prefix` 是 key 字符串前缀,可匹配 `reports/2026-` 这类不以斜杠结尾的前缀。按 UTF-8 字节序返回,`maxKeys` 为 1–1000 的整数、默认 1000,`files` 与 `commonPrefixes` 合计占用预算。`delimiter` 按 prefix 后首次出现的位置分组,空字符串不分组;空物理目录不产生条目。分组与计数参照 [S3 ListObjectsV2](https://docs.aws.amazon.com/AmazonS3/latest/API/API_ListObjectsV2.html)。
|
|
224
|
+
|
|
225
|
+
本地不透明游标绑定规范根目录、prefix 和 delimiter,不依赖进程缓存;同根目录的独立实例或重启后可以续页,下一页可调整 maxKeys。格式、版本或范围不匹配返回 `INVALID_LIST_OPTIONS`。只在确有下一条时返回 `isTruncated: true` 和 `nextContinuationToken`。游标不是授权凭据,HTTP 服务仍须授权 prefix;它不提供快照,并发增删可影响后续页。不同挂载路径不视为同一根目录。每次请求仍扫描排序匹配目录,大目录应缩小 prefix 或使用 S3。
|
|
226
|
+
|
|
227
|
+
```ts
|
|
228
|
+
let continuationToken: string | undefined
|
|
229
|
+
do {
|
|
230
|
+
const page = await storage.dir.list({ prefix: 'reports/2026-', delimiter: '/', maxKeys: 100, continuationToken })
|
|
231
|
+
if (!page.success) return page
|
|
232
|
+
// 消费当前页的 files 和 commonPrefixes。
|
|
233
|
+
continuationToken = page.data.nextContinuationToken
|
|
234
|
+
} while (continuationToken)
|
|
235
|
+
```
|
|
187
236
|
|
|
188
237
|
### 头像上传
|
|
189
238
|
|
|
@@ -200,39 +249,21 @@ if (result.success) {
|
|
|
200
249
|
|
|
201
250
|
## 浏览器端文件上传(预签名 URL 模式)
|
|
202
251
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
```typescript
|
|
206
|
-
import { apiFetch } from '$lib/utils/api'
|
|
207
|
-
|
|
208
|
-
// 1. 向服务端请求预签名上传 URL
|
|
209
|
-
const res = await apiFetch('/api/storage/presign/upload', {
|
|
210
|
-
method: 'POST',
|
|
211
|
-
headers: { 'Content-Type': 'application/json' },
|
|
212
|
-
body: JSON.stringify({ key: `uploads/${file.name}`, contentType: file.type }),
|
|
213
|
-
})
|
|
214
|
-
const { url } = await res.json()
|
|
252
|
+
`uploadWithPresignedUrl` 传 `onProgress` 时使用 XHR,否则使用 fetch。`abortController` 预取消不发送;准备中/进行中取消、外部 XHR abort、网络/超时和进度回调异常一次结算失败并解绑本次监听,完成后取消不会触碰旧 XHR。取消不能撤销远端已发布的对象;应用先核对业务/对象状态,再授权清理,不把本地取消当作服务端回滚。实际 Chrome 门禁设置 `HAI_STORAGE_RUN_BROWSER_GATES=1`,执行 `pnpm --filter @h-ai/storage exec vitest run tests/storage-client-browser.test.ts`;浏览器缺失直接失败。
|
|
215
253
|
|
|
216
|
-
|
|
217
|
-
await fetch(url, {
|
|
218
|
-
method: 'PUT',
|
|
219
|
-
body: file,
|
|
220
|
-
headers: { 'Content-Type': file.type },
|
|
221
|
-
})
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
也可使用 typed client(需配合 `@h-ai/api-client`):
|
|
254
|
+
浏览器端无法直接使用 `storage` 模块。服务端使用 S3 时,通过 typed API 获取预签名 URL,检查失败后再直传:
|
|
225
255
|
|
|
226
256
|
```typescript
|
|
227
257
|
import { apiClient } from '@h-ai/api-client'
|
|
258
|
+
import { uploadWithPresignedUrl } from '@h-ai/storage/client'
|
|
228
259
|
|
|
260
|
+
// apiClient 已初始化;用户和资源范围由服务端授权策略决定。
|
|
229
261
|
const result = await apiClient.storage.presignedUrls.createUpload({
|
|
230
262
|
key: `avatars/${userId}.png`,
|
|
231
263
|
contentType: 'image/png',
|
|
232
264
|
})
|
|
233
|
-
if (result.success)
|
|
234
|
-
|
|
235
|
-
}
|
|
265
|
+
if (!result.success) return result
|
|
266
|
+
return uploadWithPresignedUrl(result.data.url, file, { contentType: 'image/png' })
|
|
236
267
|
```
|
|
237
268
|
|
|
238
269
|
## 相关 Skills
|
|
@@ -241,3 +272,11 @@ if (result.success) {
|
|
|
241
272
|
- `hai-core`:配置与 HaiResult 模型
|
|
242
273
|
- `hai-kit`:SvelteKit API 端点集成(`kit.handler` + `kit.guard`)
|
|
243
274
|
- `hai-ui`:Storage 场景组件(FileUpload/ImageUpload/AvatarUpload)
|
|
275
|
+
|
|
276
|
+
## 生产共享状态
|
|
277
|
+
|
|
278
|
+
生产使用共享 S3 或兼容服务;local 只用于开发/明确测试。对象业务授权和读改写的条件提交由应用负责。 NODE_ENV 或 HAI_CORE_ENV 为 production 时在初始化成功前检查,只有 HAI_E2E=1/HAI_E2E_MOCK=1 明确测试豁免。不要将租约当作最终写入条件,外部未知效果须按稳定业务键核对。
|
|
279
|
+
|
|
280
|
+
## 跨端输入与能力约束
|
|
281
|
+
|
|
282
|
+
key 统一使用 `@h-ai/storage/schemas` 的 StorageKeySchema(UTF-8 最多1024字节,无绝对路径/反斜线/控制符/点路径段),prefix另允许空串与部分文件名。HTTP批量删除按原数组限制1–1000项,不能以去重绕过;Node仍按Provider分批。签名有效期整数1–604800秒,Node默认3600、HTTP默认900。HTTP上传只接受key/contentType/expiresIn,不接受contentLength/maxSize/metadata/checksum等file.put选项;未知字段返回400,typed client为VALIDATION_FAILED。Node流式读写、Range、checksum、条件写等无默认HTTP端点。FileUpload大小/类型仅为前端选择体验,服务端仍需验证实际对象与归属;不要编造上传代理端点。校验不替代session资源授权及Provider防逃逸。
|
|
@@ -19,14 +19,24 @@ description: "使用 @h-ai/ui 构建 Svelte 5 表单、表格、弹窗、新手
|
|
|
19
19
|
|
|
20
20
|
## 使用路径
|
|
21
21
|
|
|
22
|
+
新页面或较大改版先使用 [hai-ui-design](../hai-ui-design/SKILL.md) 确定任务、布局、状态和组件映射;本 skill 负责正确实现。完成后按 [hai-ui-review](../hai-ui-review/SKILL.md) 查看真实页面,小范围修复沿用已有设计。
|
|
23
|
+
|
|
24
|
+
- 密码登录只接收 identifier/password;AuthPanel 将 LoginForm 的 username 映射为 identifier。会话期限来自服务端 session.maxAge/refreshTokenMaxAge,不增加未实现的登录偏好字段或持久会话选择框。
|
|
25
|
+
|
|
22
26
|
- 先检查组件导入、Tailwind @source 和主题 CSS,再选场景 → 组合 → 原子组件,缺能力才自定义。
|
|
23
|
-
-
|
|
27
|
+
- 管理列表和工作台随可用宽度展开;flex/grid 子项设 min-width: 0,表格在自身容器滚动。阅读页与登录表单按内容约束宽度。实际检查 390、1440、1920、2560、3840px,避免宽屏仍挤在中央窄列,手机出现整页横向滚动。
|
|
28
|
+
- 按安装版本的 exports 选择明确列出的 components barrel 入口(不开放任意内部文件);主题工具使用 `@h-ai/ui/theme`,避免仅为主题加载根入口的 AI/图表组件。禁止导入内部 src/dist;例如原子组件使用 `@h-ai/ui/components/primitives/index`。
|
|
24
29
|
- 自动导入识别无分号、跨行及别名的运行时 import;已绑定的本地组件名称不会重复注入。
|
|
25
|
-
-
|
|
30
|
+
- 应用只提供页面级文案;组件内部中英日文由 @h-ai/ui 维护。
|
|
26
31
|
- `UserProfile` 用 `avatarAccept` / `avatarHint` 对齐业务的头像格式与大小限制;文件最终校验和上传由业务回调完成。
|
|
27
32
|
- `BareInput type="file"` 通过 `onchange` 的 `currentTarget.files` 读取文件,不绑定文件路径 `value`;其他输入类型可 `bind:value`。
|
|
28
33
|
- AI 文本视为不可信;Markdown/Mermaid 预览与允许执行 HTML/JS 的预览有不同边界。
|
|
29
34
|
|
|
35
|
+
- Tabs 支持方向键、Home/End、跳过禁用项与单一 Tab 入口,children 内容关联当前页签;DataTable 通过 aria-sort/aria-busy 和加载文字提供状态,有 onrowclick 时支持行 Enter/Space,单元格操作不重复触发行操作。
|
|
36
|
+
- Pagination 导航和输入名称跟随 UI locale,外部 page 变化同步跳页草稿,触摸设备扩大导航按钮;TableToolbar 打开后进入控件,Escape 返回触发点,视图按钮带选中状态。应用仍需接入排序、筛选、分页和视图对应的数据行为。
|
|
37
|
+
- CrudPage 占满宿主剩余高度,空数据和少量数据时分页保留在底部;宿主从视口外壳到内容区逐层使用 flex/grid 的剩余空间约束与 min-height: 0,避免自动高度包装层截断布局。数据区独立滚动,分页不覆盖数据。
|
|
38
|
+
- theme.css 自动引入 design-tokens.css;全局样式的焦点使用 --hai-focus-color(缺省跟随当前 primary),减少动态效果时保留最终状态并缩短动画。长内容在 Empty/Alert 中换行;业务自定义 snippet 也要能收缩。
|
|
39
|
+
|
|
30
40
|
## 按需参考
|
|
31
41
|
|
|
32
42
|
新手引导、首次 Cookie 提示、操作导览和帮助中心见 [guide.md](guide.md)。fullstack 默认在共享管理界面接入,新增业务只补内容与 data-guide 锚点。
|
|
@@ -59,3 +69,7 @@ UserProfile 的 `fieldConstraints` 按字段声明 `required/minlength/maxlength
|
|
|
59
69
|
IAM 表单、AuthPanel、UserProfile、FeedbackModal 直接接收同组参数;CRUD 使用 `form={{ columns: 2, labelPosition: 'left', labelWidth: '6rem' }}`,字段支持 `colSpan` 和延迟翻译的 `validation.message: () => m.required()`。通用字段的 `label/error/hint`、Input/Textarea/Select 的 `validationMessage` 支持翻译函数。内置必填、类型、长度和范围错误由 UI 提供;应用只提供业务文案。通过 UI 的 `setGlobalLocale` / `createLocaleStore` 同步语言,已显示的错误随之更新;自定义提示只用于失败,不能把固定提示直接设成持续的 customValidity。字段错误只在 FormField 或控件其中一处展示。
|
|
60
70
|
|
|
61
71
|
验证一列/双列与两种标签位置、自动/显式跨列、窄抽屉/手机、无效提交与修正、切换语言后的错误、按钮和回车提交,以及关闭重开后的状态。
|
|
72
|
+
|
|
73
|
+
Node 请求/SSR 必须用 `core.i18n.runWithLocale(locale, callback)`(kit 同名方法)包裹实际异步 resolve;serv 自动建立请求语言上下文。浏览器 setGlobalLocale/createLocaleStore 继续管理应用语言,SSR 的 UI setter/store 不写全局值。显式 MessageOptions.locale 优先;进程默认语言仅在启动时设置。
|
|
74
|
+
|
|
75
|
+
`@h-ai/ui/i18n` 的 `createLocaleStore` 按“可解析的持久化值 → 完整 navigator.languages(再检查 navigator.language)→ defaultLocale → 支持列表首项”选择语言;首个不支持的候选不触发默认回退。匹配大小写、语言简写及逐级区域/脚本回退,返回 supportedLocales 中的配置代码;同语言多个变体按列表顺序选择。detectBrowserLocale 无实际命中返回 null,不插入框架默认值;空支持列表最终保留调用方默认值。SSR 不读取浏览器候选或修改全局语言。应用若使用 Paraglide,仍需用该项目的 setLocale 同步应用翻译;内置 UI 字典的覆盖范围不因自定义 store 列表而自动增加。
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
## 最小接入
|
|
6
6
|
|
|
7
|
-
下面的 `m`、`locale`、`currentUser`、`createUser` 来自应用。翻译 key
|
|
7
|
+
下面的 `m`、`locale`、`currentUser`、`createUser` 来自应用。翻译 key 需要在应用中英日文消息文件定义;`nav` 使用当前宿主的公开导航适配器。
|
|
8
8
|
|
|
9
9
|
```svelte
|
|
10
10
|
<script lang='ts'>
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
|
|
65
65
|
## i18n、样式与边界
|
|
66
66
|
|
|
67
|
-
- 通用按钮、进度和错误由 UI
|
|
67
|
+
- 通用按钮、进度和错误由 UI 内置中英日文维护。业务文案使用 `() => m.key()` 延迟求值;GuideHost 的 locale 接入应用已有语言状态,不另建语言体系。
|
|
68
68
|
- 语言变化时宿主重新解析文案并刷新当前浮层。应用若采用整页重载或销毁组件切换语言,应按自身生命周期重新挂载宿主。
|
|
69
69
|
- 目标优先使用 `data-guide`,不依赖 Tailwind 类名或 DOM 顺序;现有 UI 组件支持 data 属性透传。复杂目标可用 `target: () => document.querySelector(...)`。
|
|
70
70
|
- 步骤标题和说明按纯文本显示;帮助正文使用现有安全 MarkdownRenderer,原始 HTML 关闭。
|
|
@@ -74,6 +74,6 @@
|
|
|
74
74
|
|
|
75
75
|
## 默认应用
|
|
76
76
|
|
|
77
|
-
fullstack 的 Web/App/Desktop 在共享 AdminWorkspace 中启用帮助入口、首次邀请和个人设置导览;Web 使用 Cookie,App/Desktop 使用 localStorage,按当前用户 ID 隔离。新增业务功能时,在共享 guide-store
|
|
77
|
+
fullstack 的 Web/App/Desktop 在共享 AdminWorkspace 中启用帮助入口、首次邀请和个人设置导览;Web 使用 Cookie,App/Desktop 使用 localStorage,按当前用户 ID 隔离。新增业务功能时,在共享 guide-store 和中英日文消息中补充文章、导览和稳定锚点。
|
|
78
78
|
|
|
79
79
|
验证首次提示、完成后刷新、手动重看、跳转后等待、缺失目标、账号/版本隔离、语言与主题、移动宽度、键盘和卸载取消。
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
从 [SKILL.md](SKILL.md) 选择主题后读取对应小节。代码片段展示 API 用法;省略的业务变量、schema、依赖与 return 上下文需由应用补齐。
|
|
4
4
|
|
|
5
|
-
> `@h-ai/ui` 是基于 Svelte 5 Runes 的多端 UI 组件库,采用 DaisyUI v5 + Tailwind CSS v4 + Bits UI v2,内置 15 个精选 DaisyUI
|
|
5
|
+
> `@h-ai/ui` 是基于 Svelte 5 Runes 的多端 UI 组件库,采用 DaisyUI v5 + Tailwind CSS v4 + Bits UI v2,内置 15 个精选 DaisyUI 主题、内置中英日文 i18n、自动导入。内置 Shiki 代码高亮、Mermaid 图表渲染、Design Token 系统和 7 个移动端组件。
|
|
6
6
|
|
|
7
7
|
## 运行环境
|
|
8
8
|
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
|
|
29
29
|
- **优先复用 `@h-ai/ui` 现有组件**,不要在 app 中重复实现同类按钮、表格、表单、弹层或场景页面。
|
|
30
30
|
- **页面级文案与业务逻辑放在应用层**;`@h-ai/ui` 负责展示与交互,不承接业务服务、数据库访问或页面级 i18n 管理。
|
|
31
|
-
-
|
|
31
|
+
- **场景组件自带内置中英日文文案**(如 IAM / CRUD / AI / Storage 场景),除非组件显式提供覆盖 prop,否则不要把页面翻译样板再传进去。
|
|
32
32
|
- **自动导入不是全能魔法**:`toast`、类型导入和 `Range` 仍需显式 `import`;其它公开 Svelte 组件可交给 `autoImportHaiUi()`。
|
|
33
33
|
- **移动端组件不是样式糖**:使用 `SafeArea` / `BottomNav` / `PullRefresh` / `ActionSheet` 时,务必同步引入 `design-tokens.css` 与 `mobile.css`。
|
|
34
34
|
|
|
@@ -52,7 +52,6 @@
|
|
|
52
52
|
- **primitives**:单个交互单元,例如 `Button`、`Input`、`Select`、`Badge`。
|
|
53
53
|
- **compounds**:通用业务骨架,例如 `Form`、`Modal`、`Drawer`、`DataTable`、`Pagination`。
|
|
54
54
|
- **scenes**:完整业务流,例如 `LoginForm`、`FileUpload`、`CrudPage`、`AiDocumentEditor`。
|
|
55
|
-
|
|
56
55
|
经验法则:
|
|
57
56
|
|
|
58
57
|
- 只是做一个输入控件或按钮行 → 先看 primitives。
|
|
@@ -345,7 +344,7 @@ const p = usePlatform()
|
|
|
345
344
|
|
|
346
345
|
### 场景组件(Scenes)
|
|
347
346
|
|
|
348
|
-
|
|
347
|
+
内置中英日文翻译的业务场景组件。
|
|
349
348
|
|
|
350
349
|
#### 引导与帮助场景组件
|
|
351
350
|
|
|
@@ -361,7 +360,7 @@ const p = usePlatform()
|
|
|
361
360
|
| 组件 | Props 要点 | 说明 |
|
|
362
361
|
| -------------- | ----------------------------------------------- | -------- |
|
|
363
362
|
| `AuthShell` | `variant`('card'/'split'), `title`, `brandTitle`, `brandText`, `illustration`, `description`, `highlights` | 认证页布局(包裹登录/注册表单) |
|
|
364
|
-
| `LoginForm` | `
|
|
363
|
+
| `LoginForm` | `showForgotPassword`, `showRegisterLink`, `errors` | 登录表单 |
|
|
365
364
|
| `RegisterForm` | `fields`, `minPasswordLength`, `errors` | 注册表单 |
|
|
366
365
|
| `UserProfile` | `user`, `editable`, `fields`, `avatarAccept`, `avatarHint` | 用户资料,选择器和提示对齐业务校验;最终验证和上传仍由回调负责 |
|
|
367
366
|
|
|
@@ -582,6 +581,8 @@ typescript, javascript, python, java, go, rust, c, cpp, csharp, ruby, php, swift
|
|
|
582
581
|
|
|
583
582
|
## 配置驱动认证页面
|
|
584
583
|
|
|
584
|
+
密码登录只接收 identifier/password;AuthPanel 将 LoginForm 的 username 映射为 identifier。会话期限来自服务端 session.maxAge/refreshTokenMaxAge,不增加未实现的登录偏好字段或持久会话选择框。
|
|
585
|
+
|
|
585
586
|
协议支持 `agreements.userAgreementMarkdown` 与 `privacyPolicyMarkdown` 直接从配置加载;YAML 的 `|` 保留 Markdown 段落和换行。弹窗复用安全 MarkdownRenderer,关闭原始 HTML、脚本和代码复制工具。同主题同时提供正文与 URL 时优先正文,URL 可作为额外查看入口;只有 URL 时使用隔离 iframe。
|
|
586
587
|
|
|
587
588
|
```yaml
|
|
@@ -651,7 +652,7 @@ AuthPanel 在 SSR 阶段禁用原生表单控件,客户端挂载并绑定事
|
|
|
651
652
|
| `@h-ai/ui/theme` | 轻量主题元数据与工具,不经过组件根入口 |
|
|
652
653
|
| `@h-ai/ui/i18n` | 轻量语言工具,供状态层使用,不加载组件或引导 CSS |
|
|
653
654
|
| `@h-ai/ui/auto-import` | Svelte 预处理器:组件自动导入 |
|
|
654
|
-
| `@h-ai/ui/components
|
|
655
|
+
| `@h-ai/ui/components/primitives/index` 等明确 barrel | 仅 package.exports 列出的组件目录;组件默认导出经 barrel 转发 |
|
|
655
656
|
| `@h-ai/ui/components/primitives/index` | 公开原子组件目录入口,如 Button/Input |
|
|
656
657
|
| `@h-ai/ui/styles/global.css` | 全局基础样式(重置/滚动条/焦点) |
|
|
657
658
|
| `@h-ai/ui/styles/theme.css` | Tailwind v4 `@theme` Token |
|
|
@@ -686,3 +687,13 @@ IAM 表单、AuthPanel、UserProfile、FeedbackModal 直接接收同组参数;
|
|
|
686
687
|
<Button type="submit">{m.save()}</Button>
|
|
687
688
|
</Form>
|
|
688
689
|
```
|
|
690
|
+
|
|
691
|
+
Node 请求/SSR 必须用 `core.i18n.runWithLocale(locale, callback)`(kit 同名方法)包裹实际异步 resolve;serv 自动建立请求语言上下文。浏览器 setGlobalLocale/createLocaleStore 继续管理应用语言,SSR 的 UI setter/store 不写全局值。显式 MessageOptions.locale 优先;进程默认语言仅在启动时设置。
|
|
692
|
+
|
|
693
|
+
`@h-ai/ui/i18n` 的 `createLocaleStore` 按“可解析的持久化值 → 完整 navigator.languages(再检查 navigator.language)→ defaultLocale → 支持列表首项”选择语言;首个不支持的候选不触发默认回退。匹配大小写、语言简写及逐级区域/脚本回退,返回 supportedLocales 中的配置代码;同语言多个变体按列表顺序选择。detectBrowserLocale 无实际命中返回 null,不插入框架默认值;空支持列表最终保留调用方默认值。SSR 不读取浏览器候选或修改全局语言。应用若使用 Paraglide,仍需用该项目的 setLocale 同步应用翻译;内置 UI 字典的覆盖范围不因自定义 store 列表而自动增加。
|
|
694
|
+
|
|
695
|
+
## 设计、实现与审查交接
|
|
696
|
+
|
|
697
|
+
新页面/较大改版由 [hai-ui-design](../hai-ui-design/SKILL.md) 记录任务、信息结构、状态与组件映射;本参考负责公开用法;[hai-ui-review](../hai-ui-review/SKILL.md) 查看真实页面。theme.css 已引入 design-tokens.css;--hai-focus-color 缺省跟随主题 primary。
|
|
698
|
+
|
|
699
|
+
Tabs 提供单一 Tab 入口、方向键/Home/End、跳过禁用项和 children 内容关联。DataTable 提供 aria-sort、aria-busy、加载文字及行键盘激活。Pagination 导航与输入名称走 UI i18n,外部 page 同步跳页草稿,触摸设备扩大按钮。TableToolbar 进入弹层后聚焦,Escape 返回触发点,视图按钮带 aria-pressed;业务回调仍须实际更新对应数据和视图。Empty/Alert 可容纳长内容与恢复操作;全局样式响应减少动态效果。
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hai-ui-design
|
|
3
|
+
description: "为 Hai 前端的新页面、业务流程或较大改版制定信息结构、交互状态、视觉约定和组件方案;实现用 hai-ui,现有界面审查用 hai-ui-review。"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# hai-ui-design
|
|
7
|
+
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 把用户目标转为适配当前 Hai 组件、主题与平台的页面设计 |
|
|
13
|
+
| 适用场景 | 新页面、新业务流程、信息结构/布局调整或建立应用视觉约定 |
|
|
14
|
+
| 输入 | 用户任务、需求/验收、目标端、当前页面、组件公开类型和已有品牌/设计规则 |
|
|
15
|
+
| 输出 | 页面结构、状态与交互、组件映射、必要的全局/页面设计约定和可观察验收 |
|
|
16
|
+
| 限制 | 方案请求停在设计;已有实现授权时继续交给 hai-app-create / hai-ui。设计不能补定权限等未决业务规则,组件 API 以实际版本为准。 |
|
|
17
|
+
|
|
18
|
+
## 设计路径
|
|
19
|
+
|
|
20
|
+
1. 读取项目入口、需求、实际页面和已有设计,确认目标是新建、局部优化还是整体改版。复用已确认材料;仅澄清会影响用户任务的实质缺口,普通实施细节沿已有授权继续。
|
|
21
|
+
2. 确认本页面的主要任务:后台/编辑器重视扫描、操作和状态;官网重视内容表达与行动;文档/帮助重视阅读;作品展示由内容主导。同一个应用的不同页面可有不同任务,不能把营销式大留白强加给高密度操作界面。
|
|
22
|
+
3. 按 [页面模式与决策](patterns.md) 选择信息结构:主操作、导航、筛选、内容、详情和反馈。列出初始、加载、空态、错误、成功、无权限及实际需要的长任务/取消/重试状态。
|
|
23
|
+
4. 检查安装版本 exports/types 和已有应用实现,按场景 → 组合 → 原子选择 [hai-ui](../hai-ui/SKILL.md) 组件。明确业务负责的数据、鉴权和回调;真实缺口才增加应用组件或提出公共组件改进,不编造 Props。
|
|
24
|
+
5. 把设计落到现有 DaisyUI 语义色、Hai tokens、字体层级、间距、密度和布局。保留本次范围适用的品牌、字体和颜色选择;允许业务主题覆盖,组件内不散落新的色值体系。窄抽屉按容器宽度调整,表格滚动由自身承接。
|
|
25
|
+
6. 用“角色/操作 → 可观察结果”写验收,包含目标尺寸、语言/主题、长内容、键盘/触摸、减少动态效果和适用失败恢复。实现后交给 [hai-ui-review](../hai-ui-review/SKILL.md) 查看真实渲染与行为,必要时修订设计记录。
|
|
26
|
+
|
|
27
|
+
## 设计记录
|
|
28
|
+
|
|
29
|
+
沿用项目已有设计文件。小任务在任务记录或方案中说明即可;跨页面共用规则确实需要持久维护时使用一份 `.agents/instructions/ui-design.md`(或项目既定位置)。记录用户/任务、目标端、主题/token 对应、布局/密度、组件、交互和验收;页面仅记录差异,避免复制需求或整份组件 API。
|
|
30
|
+
|
|
31
|
+
前端工作与 SDD 通过 [交接契约](../hai-spec-implement/handoff.md) 传递范围和验收。设计来源可参考 [UI/UX Pro Max](https://github.com/nextlevelbuilder/ui-ux-pro-max-skill) 的场景匹配与全局/页面分层,以及 [Impeccable](https://github.com/pbakaus/impeccable) 的任务模式;所有建议须经现有产品、平台和真实组件核验。
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# 页面模式与设计决策
|
|
2
|
+
|
|
3
|
+
本文件用于选择布局和交互,组件签名仍从当前版本公开类型确认。先看业务应用已有页面与组件展厅,再选择下面的模式;示例中的业务数据、文案和回调由应用提供。
|
|
4
|
+
|
|
5
|
+
| 场景 | 优先组件 | 设计决策与验收 |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| 列表、搜索、详情和编辑 | CrudPage;需要自定义编排时 DataTable、TableToolbar、Pagination | 标题/统计与搜索/操作分组;明确筛选后的空态和请求失败;窄屏允许表格内部滚动;排序状态、分页、返回位置可感知 |
|
|
8
|
+
| 数据录入、设置、资料 | Form 或原生 form + FormLayout、FormField、现有输入组件 | 关联字段分组,明确必填和单位;首次失焦/提交显示错误,修正更新;自动/显式跨列;失败保留输入,重复提交策略按真实业务 |
|
|
9
|
+
| 详情、确认、短流程 | Drawer、Modal、Confirm、Steps | 根据内容长度与前后文选择;标题、正文、操作区清楚;正文独立滚动,确认操作可见;焦点进入与关闭返回;保留输入与危险操作规则明确 |
|
|
10
|
+
| 多区域导航、移动端 | PageHeader、Breadcrumb、Tabs、AppBar、BottomNav、SafeArea | 导航名称对应真实任务;页签与路由导航分清;方向键和禁用项处理;移动端安全区域、触摸、返回与深链符合当前宿主 |
|
|
11
|
+
| 加载、无结果、失败和完成 | Skeleton、Empty、Alert、Result、现有消息容器 | 区分“没有数据”“筛选无匹配”“请求失败”“无权限”;说明原因和下一动作;重复实时播报、旋转图标和 toast 不能代替可恢复状态 |
|
|
12
|
+
| 上传与长任务 | 现有 storage 场景组件、进度与状态组件 | 大小/类型限制与服务端一致;区分上传、处理、完成和失败;取消/重试按幂等契约;真实外部效果未知时不能显示完成 |
|
|
13
|
+
| AI 对话、Markdown、代码和图表 | 已导出的 AI/图表场景组件 | 控制正文阅读宽度,代码/表格内部滚动;明确流式/加载/失败;渲染不可信内容走安全边界;图表图例、单位、色彩外的信息和文本摘要可读 |
|
|
14
|
+
| 官网与帮助 | 现有布局、内容与 guide 能力 | 官网按内容与行动组织层级,帮助按问题和步骤组织;使用真实文案/素材,语言展开和阅读宽度适合目标端 |
|
|
15
|
+
|
|
16
|
+
## 视觉约定如何落到实现
|
|
17
|
+
|
|
18
|
+
- 语义色用 `base-*`、`primary`、`success`、`warning`、`error` 等当前主题变量,焦点沿 `--hai-focus-color`;使用已编译主题白名单与公开 theme 工具。
|
|
19
|
+
- 共享间距、圆角、动效、触摸区域沿 theme/design tokens;表格使用现有 `density`。调整密度以任务和目标设备为依据,不为每个组件新增同名配置。
|
|
20
|
+
- 标题、说明、字段标签、数值、状态有明确层级;后台外壳使用可用宽度,正文保留阅读宽度。flex/grid 子项考虑 `min-width: 0`;长链接/标识符可换行,代码可内部滚动。
|
|
21
|
+
- 操作优先级按业务决定;按钮文案说明动作,图标按钮有可访问名称。关键操作不只依赖颜色或 hover。
|
|
22
|
+
- 动效说明变化或空间关系,尊重 `prefers-reduced-motion`。新动效的加载、取消和最终状态都要可验证。
|
|
23
|
+
|
|
24
|
+
## 页面方案最小示例
|
|
25
|
+
|
|
26
|
+
“成员列表”沿现有 CrudPage 实现:用户任务是查找成员、查看详情和修改获授权字段。顶部放名称/数量及主要操作,筛选与排序放工具栏,表格使用现有 density;窄屏内部滚动。记录初次加载、请求失败重试、无成员、筛选无结果、提交失败保留输入和缺权限状态。验收覆盖操作后的真实数据、键盘排序/页签、390px 手机、1440px 桌面、英文长名称和明暗主题。具体字段/权限来自业务需求,不从组件示例推断。
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hai-ui-review
|
|
3
|
+
description: "审查实际 Hai 界面的布局、信息层级、交互、响应式、可访问性和异常恢复;只读评审与已有授权的修复复测均适用。"
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# hai-ui-review
|
|
7
|
+
|
|
8
|
+
## 能力契约
|
|
9
|
+
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| --- | --- |
|
|
12
|
+
| 能力 | 根据用户任务与真实渲染检查界面体验和技术质量 |
|
|
13
|
+
| 适用场景 | 界面走查、前端改动自查、布局/交互评审与已授权修复验收 |
|
|
14
|
+
| 输入 | 目标页面/组件、需求或设计约定、运行环境、实际界面与相关实现 |
|
|
15
|
+
| 输出 | 带位置、操作、后果和截图/运行证据的问题清单及复测结果 |
|
|
16
|
+
| 限制 | 只读请求不自动修改;审美偏好单列,不能推翻明确设计。浏览器证据不等于原生平台或真实外部服务验收。 |
|
|
17
|
+
|
|
18
|
+
## 审查路径
|
|
19
|
+
|
|
20
|
+
1. 明确本次页面、角色、主要任务、设计约定与授权范围;理解本次是局部改善还是重新设计。沿 [hai-ui-design](../hai-ui-design/SKILL.md) 的页面任务判断层级、密度和表达。
|
|
21
|
+
2. 使用项目已有运行/浏览器测试入口装配隔离环境。先看真实页面再定位源码;不能启动时做源码/已有截图审查,标明截图来源与新旧关系,记录实际浏览器未验证。
|
|
22
|
+
3. 按 [走查清单](checklist.md) 完成用户路径。先处理任务无法完成、状态错误、键盘不可达和内容溢出,再评估布局一致性、层级和细节。每个问题记录具体页面、尺寸、语言/主题、操作和实际后果。
|
|
23
|
+
4. 复核发现是否来自公共组件、业务组合、设计规则或环境。公共问题优先修正 [hai-ui](../hai-ui/SKILL.md) 对应组件,再同步应用、CLI、文档;业务专属问题留在业务层,实际权限仍由服务端验收。
|
|
24
|
+
5. 已授权修复时集中处理本轮发现,再批量复测受影响路径和尺寸;需要行为回归时按 [hai-app-tests](../hai-app-tests/SKILL.md) 选合适测试层。纯视觉调整使用真实渲染验证,避免只匹配 class 字符串的测试。
|
|
25
|
+
|
|
26
|
+
## 问题与证据
|
|
27
|
+
|
|
28
|
+
沿 [交接契约](../hai-spec-implement/handoff.md) 记录稳定编号、优先级、位置、触发操作、后果、依据、建议和验收。截图证明布局,浏览器操作证明交互,服务/存储证据证明业务效果;三者按实际范围分别说明。
|
|
29
|
+
|
|
30
|
+
先报告已确认问题,再列实际覆盖和未验证边界。已修复项附本轮源码标识、操作与结果,日志/截图放 Git 忽略目录。没有浏览器或宿主环境时继续能做的检查,保留环境限制,不将静态清单视为实际通过。
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# 实际界面走查
|
|
2
|
+
|
|
3
|
+
按本次真实任务选择检查项,说明不适用原因。无需为后台、官网、API 项目强加同样的页面制度。
|
|
4
|
+
|
|
5
|
+
| 维度 | 如何检查 | 问题的可观察依据 |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| 用户任务 | 从入口完成一次真实操作,再尝试失败和恢复 | 操作找不到、错误状态、数据未保存却提示成功、返回后丢失工作 |
|
|
8
|
+
| 信息结构 | 看标题、主操作、筛选、内容和反馈是否能快速定位 | 关键动作埋没、状态不清楚、同级内容层级不一致 |
|
|
9
|
+
| 布局与密度 | 目标手机、桌面、窄抽屉及产品需要的大屏 | 整页横向溢出、遮挡、操作离屏、无效空白、容器嵌套限制宽度 |
|
|
10
|
+
| 内容与语言 | 长中文、长英文、无空格标识符、多行错误、空值 | 截断关键信息、按钮重叠、标签挤压、切语言后出现旧错误文案 |
|
|
11
|
+
| 主题与焦点 | 已编译的明暗主题、Tab 键移动 | 控件边界和焦点不可见、状态仅由颜色区分、主题变量失效 |
|
|
12
|
+
| 键盘与辅助信息 | Tab/Shift+Tab、Enter/Space、方向键、Home/End、Escape | 禁用项被激活、焦点消失、弹层关闭不返回、tab/panel/sort 状态不对应 |
|
|
13
|
+
| 输入与触摸 | 点击区域、IME、失焦/提交、连续操作 | 触摸难点、输入法误提交、隐藏字段旧错误、重复提交或失败后丢输入 |
|
|
14
|
+
| 状态与恢复 | 加载、空态、无匹配、失败、无权限、长任务 | 只有 spinner、无法重试、toast 代替持久错误、未知外部效果被标完成 |
|
|
15
|
+
| 动效与性能 | 减少动态效果、内容加载、表格/图表与流式内容 | 装饰动画仍执行、布局反复跳动、监听器未释放、交互明显卡顿 |
|
|
16
|
+
| 安全与平台 | 不可信 HTML/URL、会话与实际 Web/App/Desktop 宿主 | 未消毒内容执行、前端隐藏代替鉴权、浏览器结果被冒充原生能力 |
|
|
17
|
+
|
|
18
|
+
## 验收怎么写
|
|
19
|
+
|
|
20
|
+
可用例子:“390px、英文、暗色模式下,打开筛选后首个控件获焦,Escape 关闭并回到筛选按钮,整页无横向溢出。”
|
|
21
|
+
|
|
22
|
+
不够具体的例子:“响应式已适配”“体验已优化”“截图正常”。截图应能对应页面与条件;键盘、数据保存、重试等必须实际操作,并保留必要断言。视觉审美建议注明与哪个既定设计目标相关,不能把个人字体/配色偏好写成缺陷。
|
|
@@ -7,18 +7,22 @@ description: "使用 LanceDB/pgvector/Qdrant/Chroma 管理向量集合、写入
|
|
|
7
7
|
|
|
8
8
|
## 能力契约
|
|
9
9
|
|
|
10
|
-
| 项目
|
|
11
|
-
|
|
|
12
|
-
| 能力
|
|
13
|
-
| 适用场景 | 向量持久化、集合管理或相似度搜索
|
|
14
|
-
| 输入
|
|
15
|
-
| 输出
|
|
16
|
-
| 限制
|
|
10
|
+
| 项目 | 契约 |
|
|
11
|
+
| -------- | -------------------------------------------------------------------------------------------------------- |
|
|
12
|
+
| 能力 | 使用 @h-ai/vecdb 管理 LanceDB/pgvector/Qdrant/Chroma 集合与向量检索 |
|
|
13
|
+
| 适用场景 | 向量持久化、集合管理或相似度搜索 |
|
|
14
|
+
| 输入 | VecdbConfigInput、集合、固定维度向量、查询过滤条件 |
|
|
15
|
+
| 输出 | 集合/向量操作的 HaiResult |
|
|
16
|
+
| 限制 | 仅服务端;向量维度须匹配集合。Chroma 是 HTTP 服务,本地 path 模式需可用服务命令;init 失败不得当成空库。 |
|
|
17
17
|
|
|
18
18
|
## 使用路径
|
|
19
19
|
|
|
20
20
|
- `_vecdb.yml` 选择实际后端;init 后检查连接结果,再创建集合并写入相同维度向量。
|
|
21
|
-
-
|
|
21
|
+
- LanceDB 集合维度/metric 随 Arrow schema 持久化,连接 metric 仅是新集合默认值;本地路径不自动跨节点共享。分布式应用优先服务端后端,重启复用持久目录与匹配的 embedding 维度。
|
|
22
|
+
- LanceDB insert/upsert 均需持久非空 id 主键与原子 merge;insert 保留已有 ID,upsert 整行替换。同批重复 ID 或能力缺失返回 CONFIG_ERROR,无 delete/add 回退。原子性只覆盖每次 merge;检查错误后再继续业务写入。
|
|
23
|
+
- LanceDB 使用原生 JSON metadata;filter 仅支持顶层字面量键的 string/有限 number/boolean/null AND 匹配,null 不匹配缺失字段。对象/数组/undefined 与旧 Utf8 metadata 表返回 CONFIG_ERROR;过滤在 topK 前执行,错误不得当作空结果。其它后端的 null/复杂过滤能力须单独核对。
|
|
24
|
+
- Chroma 仅支持 HTTP(S) 根 url(优先于 host/port),不接受路径前缀/URL 凭据/query/fragment;apiKey 按自托管网关协议发送 Authorization: Bearer,不表示 Chroma Cloud 支持。初始化同时验证数据端点权限,认证失败不得当成空库。Qdrant 只有 404 代表集合不存在。
|
|
25
|
+
- Qdrant 仅支持未命名向量字段的三种公开 metric,外部 named-vector/Manhattan 集合返回 CONFIG_ERROR;Chroma 的 metadata/filter 由真实 SDK 校验,非法输入返回操作错误,不执行无过滤回退。
|
|
22
26
|
|
|
23
27
|
## 按需参考
|
|
24
28
|
|
|
@@ -44,7 +44,7 @@ path: ./data/vecdb
|
|
|
44
44
|
# type: chroma
|
|
45
45
|
# url: http://localhost:8000
|
|
46
46
|
# apiKey: ''
|
|
47
|
-
# serverCommand: chroma #
|
|
47
|
+
# serverCommand: chroma # 嵌入式服务端命令,默认 chroma;需独立安装服务端 CLI
|
|
48
48
|
# startupTimeout: 30000 # 嵌入式服务就绪等待超时(毫秒)
|
|
49
49
|
operationLog:
|
|
50
50
|
read: false # collection.exists/info/list, vector.search/count
|
|
@@ -118,6 +118,20 @@ interface CollectionCreateOptions {
|
|
|
118
118
|
}
|
|
119
119
|
```
|
|
120
120
|
|
|
121
|
+
LanceDB 将向量维度存于 Arrow 固定长度 vector 字段,将集合 metric 存于同一 schema 的 metadata;空表也可正确恢复。`collection.create` 中的 metric 优先于连接配置,连接 metric 仅是新集合的默认值。重启或更换默认值不会改变已有集合。每次操作读取持久 schema,并检查其它连接的提交;缺少有效集合定义时返回 `CONFIG_ERROR`,不探测假向量或猜测 metric。旧表/外部表如缺少该定义,需要重建集合,不提供兼容推断。
|
|
122
|
+
|
|
123
|
+
LanceDB 是嵌入式本地文件后端。只有访问相同持久目录、且底层文件系统支持 LanceDB 并发提交的进程才能共享数据;不同节点各自的同名本地路径互不共享。分布式服务优先选择 pgvector、Qdrant 或 Chroma 服务端。AI Knowledge 的 reldb 与 vecdb 都须持久化并指向同一业务数据集,替换 embedding 维度时须重建匹配的集合。
|
|
124
|
+
|
|
125
|
+
搜索始终使用集合 metric,`euclidean` 映射 LanceDB 的 `l2`。`score` 延续公开 API 的 0–1、越大越相似约定:cosine 为 `clamp(1 - distance / 2, 0, 1)`;euclidean 为 `1 / (1 + squaredL2)`;dot 为 `sigmoid(dotProduct)`,用于保持内积排序而非概率。`minScore` 在该转换后过滤;不同 metric/后端的阈值不应视为通用校准值。
|
|
126
|
+
|
|
127
|
+
LanceDB 原子写入的验证基线为 `@lancedb/lancedb 0.40.0 / Lance 13`。新集合在初始 Arrow schema 声明 id 为不可空主键;insert/upsert 均使用原生 merge,以 id 参与严格键冲突检测。依据:[Lance 13 table format](https://github.com/lance-format/lance/blob/v13.0.0/docs/src/format/table/index.md#unenforced-primary-key)、[Lance 13 transaction](https://github.com/lance-format/lance/blob/v13.0.0/protos/transaction.proto)、[Node binding 0.40.0](https://github.com/lancedb/lancedb/blob/v0.40.0/nodejs/lancedb/table.ts)。
|
|
128
|
+
|
|
129
|
+
LanceDB 的 `insert` 仅插入新 ID,已有 ID 保留不覆盖;`upsert` 新增或整体替换。同批重复 ID、缺失 merge 能力/持久主键均返回 `CONFIG_ERROR`,不执行写入。旧表需重建,不自动迁移或清空。每个 merge 独立原子提交;并发胜者由提交顺序决定,不提供多个 merge 或 reldb/vecdb 间的共同事务。框架不会回退到 delete/add;写入结果不明时按 ID 核对。直接使用原生 add 的外部写入会绕过该保护,不属于本接口保证。
|
|
130
|
+
|
|
131
|
+
LanceDB metadata 使用原生 JSON 字段,仍可保存嵌套 JSON 对象,搜索结果还原为对象;insert/upsert 明确使用 Arrow JSON schema 完成 JSONB 编码。旧 Utf8 metadata 表写入或过滤返回 CONFIG_ERROR,需要重建,不自动迁移。依据:[Lance 13 JSON UDF](https://github.com/lance-format/lance/blob/v13.0.0/rust/lance-datafusion/src/udf/json.rs)、[Node 0.40.0 JSON field](https://github.com/lancedb/lancedb/blob/v0.40.0/nodejs/lancedb/arrow.ts)。
|
|
132
|
+
|
|
133
|
+
LanceDB filter 只支持顶层字面量键的 AND 精确匹配,值为 string/有限 number/boolean/null;例如 `{ tenant: 'acme', page: 1, active: true, removedAt: null }`。数字/布尔不匹配同形字符串;null 只匹配显式 JSON null,不匹配缺失键。引号、反斜线、百分号、下划线均为字面量,点/括号不解释为嵌套路径。空对象不筛选;对象、数组、undefined、非有限数值返回 CONFIG_ERROR,不能忽略条件重试。过滤在向量 topK 前执行,随后应用 minScore;其它 Provider 沿用原生约束,不保证同样的 null、复杂值和路径语义。
|
|
134
|
+
|
|
121
135
|
### 向量操作 — `vecdb.vector`
|
|
122
136
|
|
|
123
137
|
| 方法 | 签名 | 说明 |
|
|
@@ -160,7 +174,15 @@ await vecdb.vector.delete('docs', ['doc-1', 'doc-2'])
|
|
|
160
174
|
|
|
161
175
|
> 空批量 `insert/upsert/delete` 会被视为 no-op;写入与搜索会校验向量维度,不匹配时返回 `HaiVecdbError.DIMENSION_MISMATCH`。Qdrant `collection.exists()` 仅在 404 时返回 `false`,网络异常会返回查询错误而不是误判不存在。
|
|
162
176
|
|
|
163
|
-
|
|
177
|
+
Qdrant `insert/upsert/delete` 等待服务端应用完成(wait:true)才返回成功,`vector.count` 请求精确计数。多次操作之间没有事务;Knowledge 在此基础上使用共享版本清单发布与补偿。
|
|
178
|
+
|
|
179
|
+
> Chroma 在 Node 端只有 HTTP 客户端(无进程内嵌入式)。嵌入式模式(提供 `path` 且无 `url`)下 `vecdb.init` 通过 `serverCommand`(默认 `chroma`)拉起本地服务,`vecdb.close` 时关闭进程;npm `chromadb` 提供客户端,服务端 CLI 需另行安装。服务命令不可用或就绪超时时 `init` 返回 `HaiVecdbError.CONNECTION_FAILED`。
|
|
180
|
+
|
|
181
|
+
Chroma 直连 `url` 仅支持 HTTP(S) 根端点,优先于 `host/port`;URL 不得带凭据、路径前缀、query 或 fragment。无 `url` 时 `host/port` 使用 HTTP。可选 `apiKey` 以 `Authorization: Bearer <apiKey>` 发送给采用此协议的自托管服务/网关;远程传输应使用 HTTPS。空串表示未配置,其余值只允许无空白的可打印 ASCII。本接口使用默认 tenant/database,不提供 Chroma Cloud 契约。初始化在心跳后验证数据端点权限,认证/权限失败返回 `CONNECTION_FAILED`,必须先检查 `success` 再执行业务。SDK 参数依据:[chromadb 3.5.0 官方客户端](https://docs.trychroma.com/reference/typescript/client)。
|
|
182
|
+
|
|
183
|
+
直连初始化总截止为 5 秒,本地服务拉起使用 `startupTimeout`;超时中止候选 HTTP 请求。成功清除初始化 timer,不限制后续业务请求。
|
|
184
|
+
|
|
185
|
+
Qdrant 使用 `@qdrant/js-client-rest 1.18.0`,仅支持未命名向量字段的 cosine/euclidean/dot;外部 named-vector/Manhattan 集合的 info/写入/搜索返回 CONFIG_ERROR,不猜测维度或 metric。Chroma 使用 `chromadb 3.5.0` 的真实类型及 metadata/filter 校验,非法输入返回操作错误,不丢弃过滤;content 可省略。各后端的 null 和复杂元数据语义不承诺统一。
|
|
164
186
|
|
|
165
187
|
**VectorDocument**:
|
|
166
188
|
|
|
@@ -178,7 +200,7 @@ interface VectorDocument {
|
|
|
178
200
|
```typescript
|
|
179
201
|
interface VectorSearchOptions {
|
|
180
202
|
topK?: number // 返回数量(默认 10)
|
|
181
|
-
filter?: Record<string, unknown> //
|
|
203
|
+
filter?: Record<string, unknown> // Provider 原生约束;LanceDB 仅支持上述顶层标量 AND 匹配
|
|
182
204
|
minScore?: number // 最低相似度阈值(0-1)
|
|
183
205
|
}
|
|
184
206
|
```
|
|
@@ -293,3 +315,11 @@ if (!result.success) {
|
|
|
293
315
|
- `hai-datapipe`:文本清洗与分块
|
|
294
316
|
- `hai-reldb`:关系型数据库(知识库需要同时使用 reldb 存储结构化数据)
|
|
295
317
|
- `hai-core`:配置管理、HaiResult 模型
|
|
318
|
+
|
|
319
|
+
## 生产共享状态
|
|
320
|
+
|
|
321
|
+
生产使用 Qdrant、pgvector 或远端 Chroma;LanceDB 和嵌入式 Chroma 只用于开发/明确测试。 NODE_ENV 或 HAI_CORE_ENV 为 production 时在初始化成功前检查,只有 HAI_E2E=1/HAI_E2E_MOCK=1 明确测试豁免。不要将租约当作最终写入条件,外部未知效果须按稳定业务键核对。
|
|
322
|
+
|
|
323
|
+
## 关闭与失败恢复
|
|
324
|
+
|
|
325
|
+
vecdb.close() 失败后不要把资源视为已释放;error.ext.cleanupPending 表示同一模块仍保有待清理资源。旧操作引用也会返回 NOT_INITIALIZED;重试 close 或 init 的前置清理,不创建并行替代连接。内嵌 Chroma 只有直接子进程 exit 确认后关闭成功,终止信号回执不是退出证明。
|