@h-ai/cli 0.1.0-alpha5
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/LICENSE +202 -0
- package/README.md +167 -0
- package/dist/chunk-2H7UOFLK.js +10 -0
- package/dist/chunk-2H7UOFLK.js.map +1 -0
- package/dist/chunk-LANIDJC7.js +659 -0
- package/dist/chunk-LANIDJC7.js.map +1 -0
- package/dist/chunk-YV7WPUI6.js +206 -0
- package/dist/chunk-YV7WPUI6.js.map +1 -0
- package/dist/config-templates-S5RI2MC6.js +5 -0
- package/dist/config-templates-S5RI2MC6.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1645 -0
- package/dist/index.js.map +1 -0
- package/dist/skill-templates-N5DU5FNX.js +5 -0
- package/dist/skill-templates-N5DU5FNX.js.map +1 -0
- package/dist/src-XJ6YXNAF.js +15030 -0
- package/dist/src-XJ6YXNAF.js.map +1 -0
- package/package.json +59 -0
- package/templates/README.md +126 -0
- package/templates/apps/admin/messages/en-US.json +33 -0
- package/templates/apps/admin/messages/zh-CN.json +33 -0
- package/templates/apps/admin/src/routes/+layout.svelte.hbs +30 -0
- package/templates/apps/admin/src/routes/+page.svelte.hbs +35 -0
- package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +44 -0
- package/templates/apps/admin/src/routes/admin/+page.svelte.hbs +45 -0
- package/templates/apps/admin/src/routes/admin/settings/+page.svelte.hbs +37 -0
- package/templates/apps/admin/src/routes/api/health/+server.ts +12 -0
- package/templates/apps/android-app/.env.hbs +3 -0
- package/templates/apps/android-app/capacitor.config.ts.hbs +12 -0
- package/templates/apps/android-app/messages/en-US.json +24 -0
- package/templates/apps/android-app/messages/zh-CN.json +24 -0
- package/templates/apps/android-app/src/lib/api.ts.hbs +30 -0
- package/templates/apps/android-app/src/lib/capacitor.ts +21 -0
- package/templates/apps/android-app/src/routes/+layout.svelte.hbs +42 -0
- package/templates/apps/android-app/src/routes/+layout.ts +7 -0
- package/templates/apps/android-app/src/routes/+page.svelte.hbs +27 -0
- package/templates/apps/api/src/routes/+layout.svelte +14 -0
- package/templates/apps/api/src/routes/+page.svelte +11 -0
- package/templates/apps/api/src/routes/api/v1/health/+server.ts +14 -0
- package/templates/apps/api/src/routes/api/v1/items/+server.ts +37 -0
- package/templates/apps/api/src/routes/api/v1/items/[id]/+server.ts +30 -0
- package/templates/apps/h5/messages/en-US.json +37 -0
- package/templates/apps/h5/messages/zh-CN.json +37 -0
- package/templates/apps/h5/src/routes/+layout.svelte.hbs +57 -0
- package/templates/apps/h5/src/routes/+page.svelte.hbs +27 -0
- package/templates/apps/h5/src/routes/discover/+page.svelte.hbs +27 -0
- package/templates/apps/h5/src/routes/profile/+page.svelte.hbs +27 -0
- package/templates/apps/website/messages/en-US.json +32 -0
- package/templates/apps/website/messages/zh-CN.json +32 -0
- package/templates/apps/website/src/routes/+layout.svelte.hbs +66 -0
- package/templates/apps/website/src/routes/+page.svelte.hbs +33 -0
- package/templates/apps/website/src/routes/about/+page.svelte.hbs +27 -0
- package/templates/apps/website/src/routes/api/health/+server.ts +12 -0
- package/templates/apps/website/src/routes/contact/+page.svelte.hbs +59 -0
- package/templates/apps/website/src/routes/services/+page.svelte.hbs +63 -0
- package/templates/base/e2e/helpers.ts +49 -0
- package/templates/base/package.json.hbs +67 -0
- package/templates/base/playwright.config.ts +32 -0
- package/templates/base/src/app.css +2 -0
- package/templates/base/src/app.d.ts.hbs +18 -0
- package/templates/base/src/app.html.hbs +16 -0
- package/templates/base/src/hooks.server.ts.hbs +123 -0
- package/templates/base/src/lib/server/init.ts.hbs +190 -0
- package/templates/base/svelte.config.js.hbs +30 -0
- package/templates/base/tsconfig.json +8 -0
- package/templates/base/vite.config.ts.hbs +27 -0
- package/templates/features/ai/routes/api/chat/+server.ts +26 -0
- package/templates/features/datapipe/routes/api/datapipe/pipeline/+server.ts +41 -0
- package/templates/features/iam/routes-admin/(auth)/+layout.svelte.hbs +21 -0
- package/templates/features/iam/routes-admin/(auth)/auth/login/+page.svelte.hbs +98 -0
- package/templates/features/iam/routes-admin/(auth)/auth/register/+page.svelte.hbs +124 -0
- package/templates/features/iam/routes-h5/auth/login/+page.svelte.hbs +98 -0
- package/templates/features/iam/routes-h5/auth/register/+page.svelte.hbs +114 -0
- package/templates/features/iam/routes-shared/api/auth/login/+server.ts +32 -0
- package/templates/features/iam/routes-shared/api/auth/logout/+server.ts +15 -0
- package/templates/features/iam/routes-shared/api/auth/me/+server.ts +12 -0
- package/templates/features/iam/routes-shared/api/auth/register/+server.ts +26 -0
- package/templates/features/payment/routes/api/v1/payment/create/+server.ts +30 -0
- package/templates/features/payment/routes/api/v1/payment/notify/[provider]/+server.ts +42 -0
- package/templates/features/payment/routes/api/v1/payment/query/[orderNo]/+server.ts +25 -0
- package/templates/features/storage/routes/api/upload/+server.ts +35 -0
- package/templates/features/vecdb/routes/api/vecdb/search/+server.ts +36 -0
- package/templates/i18n/project.inlang/settings.json +11 -0
- package/templates/skills/AGENTS.md +26 -0
- package/templates/skills/CLAUDE.md +12 -0
- package/templates/skills/copilot-instructions.md +61 -0
- package/templates/skills/hai-ai/SKILL.md +659 -0
- package/templates/skills/hai-api-client/SKILL.md +346 -0
- package/templates/skills/hai-app-create/SKILL.md +371 -0
- package/templates/skills/hai-app-review/SKILL.md +156 -0
- package/templates/skills/hai-app-tests/SKILL.md +468 -0
- package/templates/skills/hai-audit/SKILL.md +141 -0
- package/templates/skills/hai-build/SKILL.md +319 -0
- package/templates/skills/hai-cache/SKILL.md +184 -0
- package/templates/skills/hai-capacitor/SKILL.md +389 -0
- package/templates/skills/hai-core/SKILL.md +544 -0
- package/templates/skills/hai-crypto/SKILL.md +183 -0
- package/templates/skills/hai-datapipe/SKILL.md +214 -0
- package/templates/skills/hai-deploy/SKILL.md +210 -0
- package/templates/skills/hai-iam/SKILL.md +355 -0
- package/templates/skills/hai-kit/SKILL.md +319 -0
- package/templates/skills/hai-payment/SKILL.md +289 -0
- package/templates/skills/hai-reach/SKILL.md +325 -0
- package/templates/skills/hai-reldb/SKILL.md +459 -0
- package/templates/skills/hai-scheduler/SKILL.md +242 -0
- package/templates/skills/hai-storage/SKILL.md +230 -0
- package/templates/skills/hai-ui/SKILL.md +275 -0
- package/templates/skills/hai-vecdb/SKILL.md +273 -0
- package/templates/skills/opencode.json +11 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hai-crypto
|
|
3
|
+
description: 使用 @h-ai/crypto 进行加密(非对称/哈希/对称)与密码哈希;当需求涉及加密、解密、签名、验签、哈希、密码存储或密钥管理时使用。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# hai-crypto
|
|
7
|
+
|
|
8
|
+
> `@h-ai/crypto` 提供非对称加密、哈希、对称加密与密码哈希能力,支持 Node.js 与浏览器双端。
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 适用场景
|
|
13
|
+
|
|
14
|
+
- 非对称加密/解密、签名/验签、密钥生成
|
|
15
|
+
- 哈希计算与 HMAC
|
|
16
|
+
- 对称加密/解密(ECB/CBC 模式)
|
|
17
|
+
- 密码存储与验证(加盐迭代哈希)
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 使用步骤
|
|
22
|
+
|
|
23
|
+
### 1. 初始化与关闭
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { crypto } from '@h-ai/crypto'
|
|
27
|
+
|
|
28
|
+
await crypto.init()
|
|
29
|
+
|
|
30
|
+
// 使用后关闭
|
|
31
|
+
await crypto.close()
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
## 核心 API
|
|
37
|
+
|
|
38
|
+
### 非对称加密 — `crypto.asymmetric`
|
|
39
|
+
|
|
40
|
+
| 方法 | 签名 | 说明 |
|
|
41
|
+
| ------------------- | ----------------------------------------------------------- | ------------ |
|
|
42
|
+
| `generateKeyPair` | `() => HaiResult<KeyPair>` | 生成密钥对 |
|
|
43
|
+
| `encrypt` | `(data, publicKey, options?) => HaiResult<string>` | 公钥加密 |
|
|
44
|
+
| `decrypt` | `(ciphertext, privateKey, options?) => HaiResult<string>` | 私钥解密 |
|
|
45
|
+
| `sign` | `(data, privateKey, options?) => HaiResult<string>` | 私钥签名 |
|
|
46
|
+
| `verify` | `(data, signature, publicKey, options?) => HaiResult<boolean>` | 公钥验签 |
|
|
47
|
+
| `isValidPublicKey` | `(key: string) => boolean` | 校验公钥格式 |
|
|
48
|
+
| `isValidPrivateKey` | `(key: string) => boolean` | 校验私钥格式 |
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
const keyPair = crypto.asymmetric.generateKeyPair()
|
|
52
|
+
if (keyPair.success) {
|
|
53
|
+
const { publicKey, privateKey } = keyPair.data
|
|
54
|
+
|
|
55
|
+
const encrypted = crypto.asymmetric.encrypt('敏感数据', publicKey)
|
|
56
|
+
if (encrypted.success) {
|
|
57
|
+
const decrypted = crypto.asymmetric.decrypt(encrypted.data, privateKey)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const signature = crypto.asymmetric.sign('待签名数据', privateKey)
|
|
61
|
+
if (signature.success) {
|
|
62
|
+
const valid = crypto.asymmetric.verify('待签名数据', signature.data, publicKey)
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
**AsymmetricEncryptOptions**:`{ cipherMode?: 0 | 1, outputFormat?: 'hex' | 'base64' }`
|
|
68
|
+
**SignOptions**:`{ hash?: boolean, userId?: string }`
|
|
69
|
+
|
|
70
|
+
### 哈希 — `crypto.hash`
|
|
71
|
+
|
|
72
|
+
| 方法 | 签名 | 说明 |
|
|
73
|
+
| -------- | ---------------------------------------------------------- | -------- |
|
|
74
|
+
| `hash` | `(data: string \| Uint8Array, options?) => HaiResult<string>` | 哈希 |
|
|
75
|
+
| `hmac` | `(data, key) => HaiResult<string>` | HMAC |
|
|
76
|
+
| `verify` | `(data, expectedHash) => HaiResult<boolean>` | 验证哈希 |
|
|
77
|
+
|
|
78
|
+
```typescript
|
|
79
|
+
const hash = crypto.hash.hash('hello')
|
|
80
|
+
const hmac = crypto.hash.hmac('hello', 'secret-key')
|
|
81
|
+
const valid = crypto.hash.verify('hello', hash.data!)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**HashOptions**:`{ inputEncoding?: 'utf8' | 'hex' }`
|
|
85
|
+
|
|
86
|
+
### 对称加密 — `crypto.symmetric`
|
|
87
|
+
|
|
88
|
+
| 方法 | 签名 | 说明 |
|
|
89
|
+
| --------------- | ----------------------------------------------- | --------------------------- |
|
|
90
|
+
| `generateKey` | `() => string` | 生成 128-bit 密钥(32 hex) |
|
|
91
|
+
| `generateIV` | `() => string` | 生成随机 IV(32 hex) |
|
|
92
|
+
| `encrypt` | `(data, key, options?) => HaiResult<string>` | 加密 |
|
|
93
|
+
| `decrypt` | `(ciphertext, key, options?) => HaiResult<string>` | 解密 |
|
|
94
|
+
| `encryptWithIV` | `(data, key) => HaiResult<EncryptWithIVResult>` | CBC 模式加密(自动生成 IV) |
|
|
95
|
+
| `decryptWithIV` | `(ciphertext, key, iv) => HaiResult<string>` | CBC 模式解密 |
|
|
96
|
+
| `deriveKey` | `(password, salt) => string` | 从密码和盐值派生密钥 |
|
|
97
|
+
| `isValidKey` | `(key: string) => boolean` | 校验密钥格式 |
|
|
98
|
+
| `isValidIV` | `(iv: string) => boolean` | 校验 IV 格式 |
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
const key = crypto.symmetric.generateKey()
|
|
102
|
+
const result = crypto.symmetric.encryptWithIV('明文数据', key)
|
|
103
|
+
if (result.success) {
|
|
104
|
+
const decrypted = crypto.symmetric.decryptWithIV(result.data.ciphertext, key, result.data.iv)
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**SymmetricOptions**:`{ mode?: 'ecb' | 'cbc', iv?: string, inputEncoding?: 'utf8' | 'hex', outputFormat?: 'hex' | 'base64' }`
|
|
109
|
+
|
|
110
|
+
### 密码哈希 — `crypto.password`
|
|
111
|
+
|
|
112
|
+
| 方法 | 签名 | 说明 |
|
|
113
|
+
| -------- | --------------------------------------- | -------- |
|
|
114
|
+
| `hash` | `(password, config?) => HaiResult<string>` | 密码哈希 |
|
|
115
|
+
| `verify` | `(password, hash) => HaiResult<boolean>` | 验证密码 |
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
const hashed = crypto.password.hash('MyPassword123')
|
|
119
|
+
if (hashed.success) {
|
|
120
|
+
const valid = crypto.password.verify('MyPassword123', hashed.data)
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
哈希格式:`$hai$<iterations>$<salt>$<hash>`
|
|
125
|
+
**PasswordConfig**:`{ saltLength?: number, iterations?: number }`
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## 错误码 — `HaiCryptoError`
|
|
130
|
+
|
|
131
|
+
| 错误码 | code | 说明 |
|
|
132
|
+
|--------|------|------|
|
|
133
|
+
| `HaiCryptoError.INVALID_INPUT` | `hai:crypto:002` | 无效输入 |
|
|
134
|
+
| `HaiCryptoError.INVALID_KEY` | `hai:crypto:003` | 无效密钥 |
|
|
135
|
+
| `HaiCryptoError.NOT_INITIALIZED` | `hai:crypto:010` | 未初始化 |
|
|
136
|
+
| `HaiCryptoError.INIT_FAILED` | `hai:crypto:011` | 初始化失败 |
|
|
137
|
+
| `HaiCryptoError.KEY_GENERATION_FAILED` | `hai:crypto:020` | 密钥生成失败 |
|
|
138
|
+
| `HaiCryptoError.ENCRYPTION_FAILED` | `hai:crypto:021` | 加密失败 |
|
|
139
|
+
| `HaiCryptoError.DECRYPTION_FAILED` | `hai:crypto:022` | 解密失败 |
|
|
140
|
+
| `HaiCryptoError.SIGN_FAILED` | `hai:crypto:023` | 签名失败 |
|
|
141
|
+
| `HaiCryptoError.VERIFY_FAILED` | `hai:crypto:024` | 验签失败 |
|
|
142
|
+
| `HaiCryptoError.HASH_FAILED` | `hai:crypto:040` | 哈希计算失败 |
|
|
143
|
+
| `HaiCryptoError.HMAC_FAILED` | `hai:crypto:041` | HMAC 计算失败 |
|
|
144
|
+
| `HaiCryptoError.INVALID_IV` | `hai:crypto:060` | 无效 IV |
|
|
145
|
+
|
|
146
|
+
---
|
|
147
|
+
|
|
148
|
+
## 常见模式
|
|
149
|
+
|
|
150
|
+
### 数据加密存储
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
const key = process.env.HAI_CRYPTO_DATA_KEY!
|
|
154
|
+
const encrypted = crypto.symmetric.encrypt(sensitiveData, key)
|
|
155
|
+
// 存入数据库
|
|
156
|
+
|
|
157
|
+
// 读取时解密
|
|
158
|
+
const decrypted = crypto.symmetric.decrypt(storedData, key)
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
### 密码存储与验证
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
// 注册时哈希存储
|
|
165
|
+
const hashResult = crypto.password.hash(userPassword)
|
|
166
|
+
if (hashResult.success) {
|
|
167
|
+
// 存储 hashResult.data 到数据库
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// 登录时验证
|
|
171
|
+
const verifyResult = crypto.password.verify(inputPassword, storedHash)
|
|
172
|
+
if (verifyResult.success && verifyResult.data) {
|
|
173
|
+
// 密码匹配
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## 相关 Skills
|
|
180
|
+
|
|
181
|
+
- `hai-core`:配置与 HaiResult 模型
|
|
182
|
+
- `hai-iam`:密码哈希(内部自动调用 crypto.password)
|
|
183
|
+
- `hai-kit`:SvelteKit 集成(传输加密)
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hai-datapipe
|
|
3
|
+
description: 使用 @h-ai/datapipe 进行文本清洗(HTML/URL/空白移除)、多模式分块(句子/段落/Markdown/字符/自定义)和管线组合;当需求涉及文本预处理、文档分块、数据清洗或 RAG 入库前处理时使用。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# hai-datapipe
|
|
7
|
+
|
|
8
|
+
> `@h-ai/datapipe` 提供文本清洗(clean)、多模式分块(chunk)和可组合管线(pipeline),纯函数模块,无需初始化。
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 适用场景
|
|
13
|
+
|
|
14
|
+
- 文本清洗:移除 HTML 标签、URL、Email,标准化空白
|
|
15
|
+
- 文本分块:句子、段落、Markdown 标题、字数、字符、自定义分隔符
|
|
16
|
+
- RAG 入库前的文档预处理管线
|
|
17
|
+
- 管线模式组合多步清洗 + 分块 + 自定义转换
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 使用步骤
|
|
22
|
+
|
|
23
|
+
### 直接调用(无需 init)
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { datapipe } from '@h-ai/datapipe'
|
|
27
|
+
|
|
28
|
+
// 清洗
|
|
29
|
+
const cleaned = datapipe.clean(htmlText, { removeHtml: true, removeUrls: true })
|
|
30
|
+
|
|
31
|
+
// 分块
|
|
32
|
+
const chunks = datapipe.chunk(cleaned.data, { mode: 'markdown', maxSize: 2000, overlap: 200 })
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 管线模式
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
const result = await datapipe.pipeline()
|
|
39
|
+
.clean({ removeHtml: true, removeUrls: true })
|
|
40
|
+
.transform(text => text.toLowerCase())
|
|
41
|
+
.chunk({ mode: 'paragraph', maxSize: 1000, overlap: 100 })
|
|
42
|
+
.chunkTransform(chunks => chunks.filter(c => c.content.length > 50))
|
|
43
|
+
.run(rawText)
|
|
44
|
+
|
|
45
|
+
if (result.success) {
|
|
46
|
+
// result.data => { text: string, chunks: DataChunk[] }
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## 核心 API
|
|
53
|
+
|
|
54
|
+
### 清洗 — `datapipe.clean`
|
|
55
|
+
|
|
56
|
+
```typescript
|
|
57
|
+
datapipe.clean(text: string, options?: CleanOptionsInput): HaiResult<string>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
**CleanOptionsInput**:
|
|
61
|
+
|
|
62
|
+
| 字段 | 类型 | 默认 | 说明 |
|
|
63
|
+
| -------------------- | ------------------ | ----- | ------------------------ |
|
|
64
|
+
| `removeHtml` | `boolean` | true | 移除 HTML 标签 |
|
|
65
|
+
| `removeUrls` | `boolean` | false | 移除 URL |
|
|
66
|
+
| `removeEmails` | `boolean` | false | 移除 Email 地址 |
|
|
67
|
+
| `normalizeWhitespace`| `boolean` | true | 多空格→单空格、去多余空行 |
|
|
68
|
+
| `trim` | `boolean` | true | 去除首尾空白 |
|
|
69
|
+
| `customReplacements` | `{ pattern, replacement }[]` | — | 自定义正则替换规则 |
|
|
70
|
+
|
|
71
|
+
### 分块 — `datapipe.chunk`
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
datapipe.chunk(text: string, options: ChunkOptionsInput): HaiResult<DataChunk[]>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
**ChunkOptionsInput**:
|
|
78
|
+
|
|
79
|
+
| 字段 | 类型 | 默认 | 说明 |
|
|
80
|
+
| ------------------ | --------- | ---- | ------------------------------ |
|
|
81
|
+
| `mode` | `ChunkMode` | — | 分块模式(必填) |
|
|
82
|
+
| `maxSize` | `number` | 1000 | 分块最大大小 |
|
|
83
|
+
| `overlap` | `number` | 0 | 重叠大小(上下文衔接) |
|
|
84
|
+
| `separator` | `string` | — | 自定义分隔符正则(mode=custom)|
|
|
85
|
+
| `markdownMinLevel` | `number` | 2 | Markdown 最低标题级别(1-6) |
|
|
86
|
+
| `markdownKeepTitle`| `boolean` | true | 分块中保留 Markdown 标题 |
|
|
87
|
+
|
|
88
|
+
**分块模式**:
|
|
89
|
+
|
|
90
|
+
| 模式 | 说明 |
|
|
91
|
+
| ----------- | --------------------------- |
|
|
92
|
+
| `sentence` | 按句子(中英文句号/问号/感叹号) |
|
|
93
|
+
| `paragraph` | 按段落(双换行) |
|
|
94
|
+
| `markdown` | 按 Markdown 标题层级 |
|
|
95
|
+
| `page` | 按分页符(\f) |
|
|
96
|
+
| `word` | 按字数 |
|
|
97
|
+
| `character` | 按字符数 |
|
|
98
|
+
| `custom` | 自定义正则分隔符 |
|
|
99
|
+
|
|
100
|
+
**DataChunk**:
|
|
101
|
+
|
|
102
|
+
```typescript
|
|
103
|
+
interface DataChunk {
|
|
104
|
+
index: number // 分块索引(从 0 开始)
|
|
105
|
+
content: string // 分块内容
|
|
106
|
+
metadata?: Record<string, unknown> // 元数据(Markdown 模式含 title、level)
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 管线 — `datapipe.pipeline()`
|
|
111
|
+
|
|
112
|
+
```typescript
|
|
113
|
+
datapipe.pipeline()
|
|
114
|
+
.clean(options?) // 添加清洗步骤
|
|
115
|
+
.transform(fn) // 添加文本转换步骤(同步/异步)
|
|
116
|
+
.chunk(options) // 添加分块步骤
|
|
117
|
+
.chunkTransform(fn) // 添加分块后处理步骤
|
|
118
|
+
.run(text) // 执行管线 → Promise<HaiResult<PipelineResult>>
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
**PipelineResult**:
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
interface PipelineResult {
|
|
125
|
+
text: string // 处理后的文本(分块前的最终文本)
|
|
126
|
+
chunks: DataChunk[] // 分块列表(如果管线包含 chunk 步骤)
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## 错误码 — `HaiDatapipeError`
|
|
133
|
+
|
|
134
|
+
| 错误码 | code | 说明 |
|
|
135
|
+
|--------|------|------|
|
|
136
|
+
| `HaiDatapipeError.CLEAN_FAILED` | `hai:datapipe:001` | 清洗失败 |
|
|
137
|
+
| `HaiDatapipeError.CHUNK_FAILED` | `hai:datapipe:002` | 分块失败 |
|
|
138
|
+
| `HaiDatapipeError.TRANSFORM_FAILED` | `hai:datapipe:003` | 转换失败 |
|
|
139
|
+
| `HaiDatapipeError.PIPELINE_FAILED` | `hai:datapipe:004` | 管线执行失败 |
|
|
140
|
+
| `HaiDatapipeError.CONFIG_ERROR` | `hai:datapipe:005` | 配置错误 |
|
|
141
|
+
| `HaiDatapipeError.MISSING_SEPARATOR` | `hai:datapipe:006` | 自定义分隔符缺失 |
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## 常见模式
|
|
146
|
+
|
|
147
|
+
### RAG 文档入库前处理
|
|
148
|
+
|
|
149
|
+
```typescript
|
|
150
|
+
import { datapipe } from '@h-ai/datapipe'
|
|
151
|
+
import { ai } from '@h-ai/ai'
|
|
152
|
+
import { vecdb } from '@h-ai/vecdb'
|
|
153
|
+
|
|
154
|
+
// 清洗 + Markdown 分块
|
|
155
|
+
const result = await datapipe.pipeline()
|
|
156
|
+
.clean({ removeHtml: true, removeUrls: true })
|
|
157
|
+
.chunk({ mode: 'markdown', maxSize: 1000, overlap: 100 })
|
|
158
|
+
.run(rawDocument)
|
|
159
|
+
|
|
160
|
+
if (!result.success) return result
|
|
161
|
+
|
|
162
|
+
// 生成嵌入
|
|
163
|
+
const embeddings = await ai.embedding.embedBatch(
|
|
164
|
+
result.data.chunks.map(c => c.content),
|
|
165
|
+
)
|
|
166
|
+
if (!embeddings.success) return embeddings
|
|
167
|
+
|
|
168
|
+
// 入库
|
|
169
|
+
const docs = result.data.chunks.map((chunk, i) => ({
|
|
170
|
+
id: `chunk-${i}`,
|
|
171
|
+
vector: embeddings.data[i],
|
|
172
|
+
content: chunk.content,
|
|
173
|
+
metadata: chunk.metadata,
|
|
174
|
+
}))
|
|
175
|
+
await vecdb.vector.insert('knowledge', docs)
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
### 多步清洗管线
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
const result = await datapipe.pipeline()
|
|
182
|
+
.clean({ removeHtml: true, removeEmails: true })
|
|
183
|
+
.transform(text => text.replace(/\[.*?\]/g, '')) // 移除 [注释]
|
|
184
|
+
.transform(text => text.replace(/\(https?:.*?\)/g, '')) // 移除 Markdown 链接 URL
|
|
185
|
+
.chunk({ mode: 'paragraph', maxSize: 800 })
|
|
186
|
+
.chunkTransform(chunks => chunks.filter(c => c.content.length > 20)) // 过滤过短分块
|
|
187
|
+
.run(rawText)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### 错误分支处理
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
import { datapipe, HaiDatapipeError } from '@h-ai/datapipe'
|
|
194
|
+
|
|
195
|
+
const result = datapipe.chunk(text, { mode: 'custom' })
|
|
196
|
+
if (!result.success) {
|
|
197
|
+
switch (result.error.code) {
|
|
198
|
+
case HaiDatapipeError.MISSING_SEPARATOR.code:
|
|
199
|
+
// mode='custom' 时需提供 separator
|
|
200
|
+
break
|
|
201
|
+
case HaiDatapipeError.CONFIG_ERROR.code:
|
|
202
|
+
// 配置参数校验失败
|
|
203
|
+
break
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## 相关 Skills
|
|
211
|
+
|
|
212
|
+
- `hai-vecdb`:向量数据库存储(分块后入库)
|
|
213
|
+
- `hai-ai`:LLM 与 Embedding 能力
|
|
214
|
+
- `hai-core`:HaiResult 模型
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: hai-deploy
|
|
3
|
+
description: 使用 @h-ai/deploy 进行自动化部署:Vercel 部署 + 基础设施开通(Neon/Upstash/R2/Resend/Aliyun);当需求涉及应用部署、环境配置、凭证管理或云服务开通时使用。
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# hai-deploy
|
|
7
|
+
|
|
8
|
+
> `@h-ai/deploy` 提供自动化部署能力,将 SvelteKit 应用部署到 Vercel,并自动开通 PostgreSQL (Neon)、Redis (Upstash)、S3 (Cloudflare R2)、邮件 (Resend)、短信 (阿里云) 等基础设施服务。
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## 适用场景
|
|
13
|
+
|
|
14
|
+
- 一键部署 SvelteKit 应用到 Vercel
|
|
15
|
+
- 自动开通 PostgreSQL、Redis、S3 等云服务
|
|
16
|
+
- 管理部署凭证(~/.hai/credentials.yml)
|
|
17
|
+
- 扫描应用依赖,自动检测所需服务
|
|
18
|
+
- CLI 部署流程(`hai deploy`)
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 使用步骤
|
|
23
|
+
|
|
24
|
+
### 1. 配置
|
|
25
|
+
|
|
26
|
+
```yaml
|
|
27
|
+
# config/_deploy.yml
|
|
28
|
+
provider:
|
|
29
|
+
type: vercel
|
|
30
|
+
token: ${HAI_DEPLOY_VERCEL_TOKEN}
|
|
31
|
+
|
|
32
|
+
services:
|
|
33
|
+
db:
|
|
34
|
+
provisioner: neon
|
|
35
|
+
apiKey: ${HAI_DEPLOY_NEON_API_KEY}
|
|
36
|
+
cache:
|
|
37
|
+
provisioner: upstash
|
|
38
|
+
email: ${HAI_DEPLOY_UPSTASH_EMAIL}
|
|
39
|
+
apiKey: ${HAI_DEPLOY_UPSTASH_API_KEY}
|
|
40
|
+
storage:
|
|
41
|
+
provisioner: cloudflare-r2
|
|
42
|
+
accountId: ${HAI_DEPLOY_CF_ACCOUNT_ID}
|
|
43
|
+
apiToken: ${HAI_DEPLOY_CF_API_TOKEN}
|
|
44
|
+
email:
|
|
45
|
+
provisioner: resend
|
|
46
|
+
apiKey: ${HAI_DEPLOY_RESEND_API_KEY}
|
|
47
|
+
sms:
|
|
48
|
+
provisioner: aliyun
|
|
49
|
+
accessKeyId: ${HAI_DEPLOY_ALIYUN_ACCESS_KEY_ID}
|
|
50
|
+
accessKeySecret: ${HAI_DEPLOY_ALIYUN_ACCESS_KEY_SECRET}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 2. 初始化与关闭
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
import { deploy } from '@h-ai/deploy'
|
|
57
|
+
|
|
58
|
+
await deploy.init({
|
|
59
|
+
provider: { type: 'vercel', token: 'vel_xxx' },
|
|
60
|
+
services: {
|
|
61
|
+
db: { provisioner: 'neon', apiKey: 'neon_xxx' },
|
|
62
|
+
},
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
// 使用后关闭
|
|
66
|
+
await deploy.close()
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### 3. 扫描应用
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
const scanResult = await deploy.scan('./apps/my-app')
|
|
73
|
+
if (scanResult.success) {
|
|
74
|
+
const { appName, isSvelteKit, requiredServices } = scanResult.data
|
|
75
|
+
}
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 4. 开通基础设施
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
const provResults = await deploy.provisionAll('my-project')
|
|
82
|
+
if (provResults.success) {
|
|
83
|
+
for (const prov of provResults.data) {
|
|
84
|
+
// prov.envVars 包含需要注入的环境变量
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 5. 完整部署
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
const result = await deploy.deployApp('./apps/my-app', {
|
|
93
|
+
projectName: 'my-project',
|
|
94
|
+
skipProvision: false,
|
|
95
|
+
skipBuild: false,
|
|
96
|
+
})
|
|
97
|
+
if (result.success) {
|
|
98
|
+
// result.data.url — 部署地址
|
|
99
|
+
// result.data.deploymentId — 部署 ID
|
|
100
|
+
// result.data.envVarsSet — 已设置的环境变量列表
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
## 核心 API
|
|
107
|
+
|
|
108
|
+
| 方法 | 签名 | 说明 |
|
|
109
|
+
| ---------------------- | -------------------------------------------------------------------------- | ------------ |
|
|
110
|
+
| `deploy.init` | `(config: DeployConfigInput) => Promise<HaiResult<void>>` | 初始化模块 |
|
|
111
|
+
| `deploy.close` | `() => Promise<void>` | 关闭模块 |
|
|
112
|
+
| `deploy.scan` | `(appDir: string) => Promise<HaiResult<ScanResult>>` | 扫描应用 |
|
|
113
|
+
| `deploy.provisionAll` | `(projectName: string) => Promise<HaiResult<ProvisionResult[]>>` | 开通所有服务 |
|
|
114
|
+
| `deploy.deployApp` | `(appDir: string, options?) => Promise<HaiResult<DeployResult>>` | 完整部署 |
|
|
115
|
+
| `deploy.config` | `DeployConfig \| null` | 当前配置 |
|
|
116
|
+
| `deploy.isInitialized` | `boolean` | 初始化状态 |
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## 凭证管理
|
|
121
|
+
|
|
122
|
+
| 函数 | 说明 |
|
|
123
|
+
| ---------------------------- | ------------------------------------------ |
|
|
124
|
+
| `loadCredentials()` | 加载 ~/.hai/credentials.yml 到 process.env |
|
|
125
|
+
| `saveCredential(key, value)` | 保存单个凭证 |
|
|
126
|
+
| `saveCredentials(entries)` | 批量保存凭证 |
|
|
127
|
+
| `getCredentialsPath()` | 获取凭证文件路径 |
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## 错误码 — `HaiDeployError`
|
|
132
|
+
|
|
133
|
+
| 错误码 | code | 说明 |
|
|
134
|
+
| --------------------------------------- | ------------------ | ------------------------ |
|
|
135
|
+
| `HaiDeployError.DEPLOY_FAILED` | `hai:deploy:001` | 部署失败(通用) |
|
|
136
|
+
| `HaiDeployError.PROJECT_CREATE_FAILED` | `hai:deploy:002` | 平台项目创建失败 |
|
|
137
|
+
| `HaiDeployError.BUILD_FAILED` | `hai:deploy:003` | 应用构建失败 |
|
|
138
|
+
| `HaiDeployError.UPLOAD_FAILED` | `hai:deploy:004` | 构建产物上传失败 |
|
|
139
|
+
| `HaiDeployError.AUTH_REQUIRED` | `hai:deploy:005` | 未认证 |
|
|
140
|
+
| `HaiDeployError.AUTH_FAILED` | `hai:deploy:006` | 认证失败 |
|
|
141
|
+
| `HaiDeployError.PROVISION_FAILED` | `hai:deploy:007` | 基础设施开通失败 |
|
|
142
|
+
| `HaiDeployError.ADAPTER_MISSING` | `hai:deploy:008` | SvelteKit adapter 未安装 |
|
|
143
|
+
| `HaiDeployError.SCAN_FAILED` | `hai:deploy:009` | 应用扫描失败 |
|
|
144
|
+
| `HaiDeployError.ENV_VAR_FAILED` | `hai:deploy:010` | 环境变量设置失败 |
|
|
145
|
+
| `HaiDeployError.NOT_INITIALIZED` | `hai:deploy:011` | 模块未初始化 |
|
|
146
|
+
| `HaiDeployError.UNSUPPORTED_TYPE` | `hai:deploy:012` | 不支持的类型 |
|
|
147
|
+
| `HaiDeployError.CONFIG_ERROR` | `hai:deploy:013` | 配置错误 |
|
|
148
|
+
| `HaiDeployError.CREDENTIAL_ERROR` | `hai:deploy:014` | 凭证读写失败 |
|
|
149
|
+
|
|
150
|
+
---
|
|
151
|
+
|
|
152
|
+
## CLI 命令
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
# 部署当前目录
|
|
156
|
+
hai deploy
|
|
157
|
+
|
|
158
|
+
# 部署指定应用
|
|
159
|
+
hai deploy ./apps/admin-console
|
|
160
|
+
|
|
161
|
+
# 跳过基础设施开通
|
|
162
|
+
hai deploy --skip-provision
|
|
163
|
+
|
|
164
|
+
# 跳过构建
|
|
165
|
+
hai deploy --skip-build
|
|
166
|
+
|
|
167
|
+
# 自定义项目名
|
|
168
|
+
hai deploy --project-name my-custom-name
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## 常见模式
|
|
174
|
+
|
|
175
|
+
### 仅部署(跳过基础设施)
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
await deploy.deployApp('./apps/my-app', { skipProvision: true })
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### 仅开通基础设施
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
await deploy.init(config)
|
|
185
|
+
const result = await deploy.provisionAll('my-project')
|
|
186
|
+
// 手动使用 result.data 中的环境变量
|
|
187
|
+
await deploy.close()
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### 自定义部署流程
|
|
191
|
+
|
|
192
|
+
```typescript
|
|
193
|
+
import { deploy } from '@h-ai/deploy'
|
|
194
|
+
|
|
195
|
+
// Provider 通过 init 配置自动创建,不需要手动导入
|
|
196
|
+
await deploy.init({
|
|
197
|
+
provider: { type: 'vercel', token: 'vel_xxx' },
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
// 使用 deploy API 部署
|
|
201
|
+
const result = await deploy.deployApp('./apps/my-app')
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
---
|
|
205
|
+
|
|
206
|
+
## 相关 Skills
|
|
207
|
+
|
|
208
|
+
- **hai-core** — 配置加载、日志、HaiResult 类型
|
|
209
|
+
- **hai-reldb** — 数据库(Neon PostgreSQL)
|
|
210
|
+
- **hai-cache** — 缓存(Upstash Redis)
|