@h-ai/cli 0.1.0-alpha.65 → 0.1.0-alpha.67

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 (141) hide show
  1. package/README.en.md +66 -251
  2. package/README.ja.md +67 -252
  3. package/README.md +66 -251
  4. package/dist/{chunk-47V5OT22.js → chunk-7DSURTJ4.js} +32 -115
  5. package/dist/chunk-7DSURTJ4.js.map +1 -0
  6. package/dist/{chunk-IPG3QNYK.js → chunk-AOQ4N657.js} +212 -8
  7. package/dist/chunk-AOQ4N657.js.map +1 -0
  8. package/dist/cli-config-templates-6AHNUGBN.js +5 -0
  9. package/dist/{cli-config-templates-SJ2MBIR7.js.map → cli-config-templates-6AHNUGBN.js.map} +1 -1
  10. package/dist/{cli-skill-templates-A5VIR5J6.js → cli-skill-templates-FC3QRKDO.js} +3 -3
  11. package/dist/{cli-skill-templates-A5VIR5J6.js.map → cli-skill-templates-FC3QRKDO.js.map} +1 -1
  12. package/dist/index.js +644 -391
  13. package/dist/index.js.map +1 -1
  14. package/dist/{src-6PPBKQ6Q.js → src-2V6VP4I5.js} +972 -520
  15. package/dist/src-2V6VP4I5.js.map +1 -0
  16. package/package.json +8 -8
  17. package/templates/README.md +48 -145
  18. package/templates/apps/admin/src/routes/admin/+layout.svelte.hbs +1 -1
  19. package/templates/apps/api/.dockerignore.hbs +18 -12
  20. package/templates/apps/api/.gitignore.hbs +9 -1
  21. package/templates/apps/api/apps/{{projectName}}-contract/README.md.hbs +23 -2
  22. package/templates/apps/api/apps/{{projectName}}-service/README.md.hbs +28 -7
  23. package/templates/apps/api/apps/{{projectName}}-service/package.json.hbs +1 -3
  24. package/templates/apps/api/hai.build.json.hbs +1 -0
  25. package/templates/apps/api/images/app.Dockerfile.hbs +35 -0
  26. package/templates/apps/api/package.json.hbs +10 -8
  27. package/templates/apps/fullstack/.dockerignore.hbs +18 -14
  28. package/templates/apps/fullstack/.gitignore.hbs +9 -1
  29. package/templates/apps/fullstack/apps/{{projectName}}-app/README.md.hbs +23 -8
  30. package/templates/apps/fullstack/apps/{{projectName}}-app/index.html.hbs +1 -0
  31. package/templates/apps/fullstack/apps/{{projectName}}-app/package.json.hbs +0 -2
  32. package/templates/apps/fullstack/apps/{{projectName}}-app/public/runtime-config.js.hbs +4 -0
  33. package/templates/apps/fullstack/apps/{{projectName}}-app/vite.config.ts.hbs +3 -3
  34. package/templates/apps/fullstack/apps/{{projectName}}-desktop/README.md.hbs +25 -10
  35. package/templates/apps/fullstack/apps/{{projectName}}-desktop/package.json.hbs +2 -3
  36. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/src/lib.rs.hbs +73 -2
  37. package/templates/apps/fullstack/apps/{{projectName}}-desktop/src-tauri/tauri.conf.json.hbs +2 -2
  38. package/templates/apps/fullstack/apps/{{projectName}}-desktop/vite.config.ts.hbs +2 -2
  39. package/templates/apps/fullstack/apps/{{projectName}}-miniapp/README.md.hbs +16 -6
  40. package/templates/apps/fullstack/apps/{{projectName}}-web/README.md.hbs +24 -10
  41. package/templates/apps/fullstack/apps/{{projectName}}-web/package.json.hbs +0 -2
  42. package/templates/apps/fullstack/apps/{{projectName}}-web/vite.config.ts.hbs +3 -3
  43. package/templates/apps/fullstack/e2e/fullstack.spec.ts.hbs +12 -1
  44. package/templates/apps/fullstack/hai.build.json.hbs +7 -0
  45. package/templates/apps/fullstack/images/app.Dockerfile.hbs +36 -0
  46. package/templates/apps/fullstack/images/web.Dockerfile.hbs +34 -0
  47. package/templates/apps/fullstack/package.json.hbs +7 -12
  48. package/templates/apps/fullstack/packages/{{projectName}}-contract/README.md.hbs +23 -2
  49. package/templates/apps/fullstack/packages/{{projectName}}-serv/README.md.hbs +28 -7
  50. package/templates/apps/fullstack/packages/{{projectName}}-serv/package.json.hbs +0 -1
  51. package/templates/apps/fullstack/packages/{{projectName}}-shared/.gitignore.hbs +7 -0
  52. package/templates/apps/fullstack/packages/{{projectName}}-shared/README.md.hbs +33 -12
  53. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/components/AppShell.svelte.hbs +2 -2
  54. package/templates/apps/fullstack/packages/{{projectName}}-shared/src/lib/pages/settings.svelte.hbs +3 -3
  55. package/templates/apps/fullstack/packages/{{projectName}}-shared/tests/api-client.test.ts.hbs +2 -2
  56. package/templates/apps/h5/src/routes/+layout.svelte.hbs +2 -2
  57. package/templates/apps/mobile-app/index.html.hbs +1 -0
  58. package/templates/apps/mobile-app/public/runtime-config.js +1 -0
  59. package/templates/apps/mobile-app/src/App.svelte.hbs +2 -2
  60. package/templates/apps/mobile-app/src/lib/api.ts.hbs +2 -1
  61. package/templates/apps/mobile-app/src/lib/app-config.ts.hbs +3 -2
  62. package/templates/apps/mobile-app/src/lib/pages/home.svelte.hbs +2 -2
  63. package/templates/apps/website/src/routes/+layout.svelte.hbs +3 -3
  64. package/templates/apps/website/src/routes/services/+page.svelte.hbs +1 -1
  65. package/templates/base/.dockerignore.hbs +18 -13
  66. package/templates/base/.gitignore.hbs +9 -1
  67. package/templates/base/e2e/app.spec.ts.hbs +10 -0
  68. package/templates/base/hai.build.json.hbs +1 -0
  69. package/templates/base/images/app.Dockerfile.hbs +64 -0
  70. package/templates/base/{docker → images/web}/nginx.conf.hbs +6 -0
  71. package/templates/base/package.json.hbs +20 -19
  72. package/templates/base/svelte.config.js.hbs +2 -0
  73. package/templates/base/vite.config.ts.hbs +9 -3
  74. package/templates/shared/.gitattributes +11 -0
  75. package/templates/shared/container-runtime-config.sh +30 -0
  76. package/templates/shared/run-e2e.mjs +65 -0
  77. package/templates/shared/vite-runtime-config.ts +54 -0
  78. package/templates/skills/AGENTS.md +3 -3
  79. package/templates/skills/bridges/admin/AGENTS.md +1 -1
  80. package/templates/skills/bridges/api/AGENTS.md +1 -1
  81. package/templates/skills/bridges/fullstack/AGENTS.md.hbs +1 -1
  82. package/templates/skills/bridges/h5/AGENTS.md +1 -1
  83. package/templates/skills/bridges/mobile-app/AGENTS.md +1 -1
  84. package/templates/skills/bridges/website/AGENTS.md +1 -1
  85. package/templates/skills/hai-api-client/SKILL.md +14 -161
  86. package/templates/skills/hai-api-client/reference.md +166 -0
  87. package/templates/skills/hai-api-contract/SKILL.md +15 -273
  88. package/templates/skills/hai-api-contract/reference.md +278 -0
  89. package/templates/skills/hai-app-create/SKILL.md +2 -2
  90. package/templates/skills/hai-app-create/development.md +6 -4
  91. package/templates/skills/hai-app-create/reference.md +5 -4
  92. package/templates/skills/hai-app-review/SKILL.md +1 -1
  93. package/templates/skills/hai-app-tests/SKILL.md +4 -3
  94. package/templates/skills/hai-app-tests/reference.md +2 -2
  95. package/templates/skills/hai-app-tests/validation.md +31 -0
  96. package/templates/skills/hai-audit/SKILL.md +17 -142
  97. package/templates/skills/hai-audit/reference.md +145 -0
  98. package/templates/skills/hai-build/SKILL.md +24 -3
  99. package/templates/skills/hai-build/reference.md +10 -9
  100. package/templates/skills/hai-cache/SKILL.md +15 -182
  101. package/templates/skills/hai-cache/reference.md +187 -0
  102. package/templates/skills/hai-capacitor/SKILL.md +4 -3
  103. package/templates/skills/hai-capacitor/reference.md +6 -4
  104. package/templates/skills/hai-ci/SKILL.md +2 -0
  105. package/templates/skills/hai-core/SKILL.md +3 -3
  106. package/templates/skills/hai-crypto/SKILL.md +16 -252
  107. package/templates/skills/hai-crypto/reference.md +256 -0
  108. package/templates/skills/hai-datapipe/SKILL.md +15 -196
  109. package/templates/skills/hai-datapipe/reference.md +202 -0
  110. package/templates/skills/hai-deploy/SKILL.md +28 -271
  111. package/templates/skills/hai-deploy/middleware.md +6 -18
  112. package/templates/skills/hai-framework-sync/SKILL.md +2 -2
  113. package/templates/skills/hai-framework-sync/sync.md +1 -1
  114. package/templates/skills/hai-iam/SKILL.md +1 -3
  115. package/templates/skills/hai-kit/SKILL.md +12 -167
  116. package/templates/skills/hai-kit/reference.md +172 -0
  117. package/templates/skills/hai-payment/SKILL.md +19 -251
  118. package/templates/skills/hai-payment/reference.md +256 -0
  119. package/templates/skills/hai-pr-review/SKILL.md +4 -4
  120. package/templates/skills/hai-reach/SKILL.md +2 -2
  121. package/templates/skills/hai-reldb/SKILL.md +1 -1
  122. package/templates/skills/hai-scheduler/SKILL.md +15 -195
  123. package/templates/skills/hai-scheduler/reference.md +202 -0
  124. package/templates/skills/hai-serv/SKILL.md +2 -2
  125. package/templates/skills/hai-spec-implement/SKILL.md +1 -1
  126. package/templates/skills/hai-spec-implement/workflow.md +3 -3
  127. package/templates/skills/hai-storage/SKILL.md +17 -238
  128. package/templates/skills/hai-storage/reference.md +243 -0
  129. package/templates/skills/hai-ui/SKILL.md +1 -1
  130. package/templates/skills/hai-ui/reference.md +11 -5
  131. package/templates/skills/hai-vecdb/SKILL.md +2 -2
  132. package/dist/chunk-47V5OT22.js.map +0 -1
  133. package/dist/chunk-IPG3QNYK.js.map +0 -1
  134. package/dist/cli-config-templates-SJ2MBIR7.js +0 -5
  135. package/dist/src-6PPBKQ6Q.js.map +0 -1
  136. package/templates/apps/api/Dockerfile.hbs +0 -48
  137. package/templates/apps/fullstack/Dockerfile.hbs +0 -69
  138. package/templates/base/Dockerfile.hbs +0 -79
  139. /package/templates/apps/fullstack/{docker → images/web}/19-runtime-config.envsh.hbs +0 -0
  140. /package/templates/apps/fullstack/{docker → images/web}/nginx.conf.hbs +0 -0
  141. /package/templates/apps/fullstack/{docker → images/web}/runtime-config.js.template.hbs +0 -0
@@ -0,0 +1,256 @@
1
+ # hai-payment 参考
2
+
3
+ > `@h-ai/payment` 是 hai-framework 的统一支付模块,通过 Provider 模式支持微信支付、支付宝、Stripe。服务端处理订单和回调,客户端调起支付。
4
+
5
+ ## 运行环境
6
+
7
+ > **服务端 + 浏览器分工模块。** `payment.createOrder` / `payment.handleNotify` / `payment.refund` 等操作在 Node.js 端执行。浏览器端使用 `invokePayment()`(从 `@h-ai/payment/client` 导入)调起支付。
8
+
9
+ ## 依赖
10
+
11
+ | 模块 | 用途 | 是否必需 | 初始化要求 |
12
+ | --- | --- | --- | --- |
13
+ | `@h-ai/audit` | 审计日志(支付操作自动审计) | 可选 | 已初始化时自动写入审计日志 |
14
+
15
+ ## 适用场景
16
+
17
+ - 接入微信支付(JSAPI / H5 / Native / App)
18
+ - 接入支付宝(H5 / App / PC)
19
+ - 接入 Stripe(Checkout Session)
20
+ - 支付回调验签与通知处理
21
+ - 订单查询与退款
22
+ - 客户端调起支付(Web / H5 / App)
23
+
24
+ ## 使用步骤
25
+
26
+ ### 1. 配置
27
+
28
+ ```yaml
29
+ # config/_payment.yml(自行创建)
30
+ wechat:
31
+ appId: ''
32
+ mchId: ''
33
+ apiV3Key: ''
34
+ privateKey: ''
35
+ serialNo: ''
36
+ platformCert: '' # 可选,回调验签需要
37
+
38
+ alipay:
39
+ appId: ''
40
+ privateKey: ''
41
+ alipayPublicKey: ''
42
+ signType: RSA2 # 可选,默认 RSA2
43
+ sandbox: false # 可选,默认 false
44
+
45
+ stripe:
46
+ secretKey: ''
47
+ webhookSecret: ''
48
+ webhookToleranceSeconds: 300 # 可选,默认 300 秒
49
+ ```
50
+
51
+ 约定环境变量优先于 YAML,例如 `HAI_PAYMENT_WECHAT_APIV3KEY`、
52
+ `HAI_PAYMENT_STRIPE_WEBHOOKSECRET`。生产密钥只放环境或密钥管理器。
53
+
54
+ ### 2. 初始化(服务端)
55
+
56
+ ```typescript
57
+ import { payment } from '@h-ai/payment'
58
+
59
+ const initResult = await payment.init({
60
+ wechat: {
61
+ appId: 'wx1234567890',
62
+ mchId: '1600000000',
63
+ apiV3Key: 'your-api-key-v3',
64
+ privateKey: '-----BEGIN RSA PRIVATE KEY-----...',
65
+ serialNo: 'CERT_SERIAL_NO',
66
+ },
67
+ alipay: {
68
+ appId: '2021000000000000',
69
+ privateKey: '-----BEGIN RSA PRIVATE KEY-----...',
70
+ alipayPublicKey: '-----BEGIN PUBLIC KEY-----...',
71
+ },
72
+ })
73
+ if (!initResult.success) {
74
+ // 处理初始化错误
75
+ }
76
+ ```
77
+
78
+ ### 3. 创建订单
79
+
80
+ ```typescript
81
+ const result = await payment.createOrder('wechat', {
82
+ orderNo: 'ORDER_20250101_001',
83
+ amount: 9900, // 单位:分
84
+ description: '商品名称',
85
+ tradeType: 'jsapi',
86
+ userId: 'user_openid',
87
+ notifyUrl: 'https://example.com/payment/notify/wechat',
88
+ metadata: { source: 'web' },
89
+ })
90
+
91
+ if (result.success) {
92
+ // result.data: PaymentOrder { provider, tradeType, clientParams, prepayId? }
93
+ // clientParams 包含调起支付所需参数
94
+ }
95
+
96
+ // amount / totalAmount 必须是正整数(单位:分)
97
+ ```
98
+
99
+ ### 4. 处理支付回调
100
+
101
+ ```typescript
102
+ // API 路由:POST /payment/notify/:provider
103
+ const result = await payment.handleNotify('wechat', {
104
+ body: await request.text(),
105
+ headers: Object.fromEntries(request.headers),
106
+ })
107
+
108
+ if (result.success) {
109
+ // result.data: { orderNo, transactionId, amount, status, paidAt? }
110
+ // 更新订单状态...
111
+ }
112
+ ```
113
+
114
+ ### 5. 查询订单
115
+
116
+ ```typescript
117
+ const result = await payment.queryOrder('wechat', 'ORDER_20250101_001')
118
+
119
+ if (result.success) {
120
+ // result.data.status: 'pending' | 'paid' | 'closed' | 'refunded' | 'failed'
121
+ }
122
+ ```
123
+
124
+ ### 6. 退款
125
+
126
+ ```typescript
127
+ const result = await payment.refund('wechat', {
128
+ orderNo: 'ORDER_20250101_001',
129
+ refundNo: 'REFUND_20250101_001',
130
+ amount: 9900,
131
+ totalAmount: 9900, // 微信退款必填
132
+ reason: '用户退款',
133
+ })
134
+ ```
135
+
136
+ ### 7. 客户端调起支付(浏览器)
137
+
138
+ ```typescript
139
+ import { invokePayment } from '@h-ai/payment/client'
140
+
141
+ // 前端拿到服务端返回的 PaymentOrder 后调起支付
142
+ const payResult = await invokePayment(orderResult.data)
143
+ ```
144
+
145
+ ## 核心 API(服务端)
146
+
147
+ | API | 用途 | 返回值 |
148
+ | ------------------------------------------------ | -------- | ----------------------------- |
149
+ | `payment.init(config)` | 初始化 | `HaiResult<void>` |
150
+ | `payment.close()` | 关闭 | `void` |
151
+ | `payment.createOrder(providerName, input)` | 创建订单 | `HaiResult<PaymentOrder>` |
152
+ | `payment.handleNotify(providerName, request)` | 处理回调 | `HaiResult<PaymentNotifyResult>` |
153
+ | `payment.queryOrder(providerName, orderNo)` | 查询订单 | `HaiResult<OrderStatus>` |
154
+ | `payment.refund(providerName, input)` | 退款 | `HaiResult<RefundResult>` |
155
+ | `payment.closeOrder(providerName, orderNo)` | 关闭订单 | `HaiResult<void>` |
156
+ | `payment.getProvider(name)` | 获取 Provider | `PaymentProvider \| undefined` |
157
+ | `payment.registerProvider(provider)` | 注册自定义 Provider | `void` |
158
+
159
+ ## 客户端 API
160
+
161
+ | API | 用途 | 返回值 |
162
+ | ------------------------ | -------- | ----------------------------- |
163
+ | `invokePayment(options)` | 调起支付 | `HaiResult<InvokePaymentResult>` |
164
+
165
+ ## 错误码 — `HaiPaymentError`
166
+
167
+ | 错误码 | code | 说明 |
168
+ |--------|------|------|
169
+ | `HaiPaymentError.CREATE_ORDER_FAILED` | `hai:payment:001` | 创建订单失败 |
170
+ | `HaiPaymentError.QUERY_ORDER_FAILED` | `hai:payment:002` | 查询订单失败 |
171
+ | `HaiPaymentError.REFUND_FAILED` | `hai:payment:003` | 退款失败 |
172
+ | `HaiPaymentError.CLOSE_ORDER_FAILED` | `hai:payment:004` | 关闭订单失败 |
173
+ | `HaiPaymentError.NOT_INITIALIZED` | `hai:payment:010` | 模块未初始化 |
174
+ | `HaiPaymentError.SIGN_FAILED` | `hai:payment:020` | 签名失败 |
175
+ | `HaiPaymentError.PROVIDER_NOT_FOUND` | `hai:payment:030` | Provider 未注册 |
176
+ | `HaiPaymentError.INVALID_AMOUNT` | `hai:payment:040` | 金额无效 |
177
+ | `HaiPaymentError.NOTIFY_VERIFY_FAILED` | `hai:payment:050` | 回调验签失败 |
178
+ | `HaiPaymentError.NOTIFY_PARSE_FAILED` | `hai:payment:051` | 回调解析失败 |
179
+ | `HaiPaymentError.INVOKE_WEB_FAILED` | `hai:payment:060` | Web 端调起支付失败 |
180
+ | `HaiPaymentError.INVOKE_APP_FAILED` | `hai:payment:061` | App 端调起支付失败 |
181
+ | `HaiPaymentError.CONFIG_ERROR` | `hai:payment:070` | 配置无效 |
182
+
183
+ ## Provider 模式
184
+
185
+ 内置 Provider:
186
+
187
+ - **wechat** — 微信支付 API v3
188
+ - **alipay** — 支付宝开放平台
189
+ - **stripe** — Stripe Checkout Session 模式
190
+
191
+ 自定义 Provider 通过 `payment.registerProvider(provider)` 注册。
192
+
193
+ ### HTTP API 契约
194
+
195
+ ```typescript
196
+ import { apiContract } from '@h-ai/api-contract'
197
+
198
+ // apiContract.payment.orders.create — POST /payment/orders
199
+ // apiContract.payment.orders.get — GET /payment/orders/{orderNo}
200
+ // apiContract.payment.orders.refund — POST /payment/orders/{orderNo}/refunds
201
+ // apiContract.payment.notifications.wechat — POST /payment/notifications/wechat
202
+ ```
203
+
204
+ ## 常见模式
205
+
206
+ ### 服务端路由(SvelteKit)
207
+
208
+ ```typescript
209
+ import { kit } from '@h-ai/kit'
210
+ // src/routes/api/v1/payment/create/+server.ts
211
+ import { payment } from '@h-ai/payment'
212
+
213
+ export const POST = kit.handler(async ({ request, locals }) => {
214
+ const body = await request.json()
215
+ const result = await payment.createOrder(body.provider, {
216
+ orderNo: body.orderNo,
217
+ amount: body.amount,
218
+ description: body.description,
219
+ tradeType: body.tradeType,
220
+ userId: body.userId,
221
+ notifyUrl: body.notifyUrl,
222
+ })
223
+
224
+ if (!result.success) {
225
+ return kit.response.internalError(result.error.message)
226
+ }
227
+
228
+ return kit.response.ok(result.data, locals.requestId)
229
+ })
230
+ ```
231
+
232
+ ### 完整支付流程
233
+
234
+ ```
235
+ 1. 客户端 → 服务端:创建订单(api.payment.orders.create({...}))
236
+ 2. 服务端 → 支付平台:调用 Provider 创建预支付
237
+ 3. 服务端 → 客户端:返回 providerData(含调起参数)
238
+ 4. 客户端:invokePayment(providerData) 调起支付
239
+ 5. 支付平台 → 服务端:异步回调通知
240
+ 6. 服务端:handleNotify() 验签 + 更新订单状态
241
+ 7. 客户端:轮询或回调查询订单状态
242
+ ```
243
+
244
+ ## 审计日志
245
+
246
+ 关键支付操作(创建订单、回调、退款、关闭订单)成功后自动写入审计日志(依赖 `@h-ai/audit`),无需额外配置。`queryOrder` 为只读操作,不写审计日志。
247
+
248
+ 内置 Provider 的 HTTP 请求默认带 15 秒超时;Stripe 可通过 `webhookToleranceSeconds` 调整 webhook 时间戳容忍窗口。
249
+
250
+ ## 相关 Skills
251
+
252
+ - `hai-kit`:服务端 API 路由与契约处理
253
+ - `hai-api-client`:客户端契约调用
254
+ - `hai-reldb`:订单持久化存储
255
+ - `hai-audit`:审计日志(payment 内部自动调用)
256
+ - `hai-core`:HaiResult 类型、日志、配置
@@ -49,11 +49,11 @@ description: "审查 PR 范围、风险、验证证据和合并准备度。"
49
49
 
50
50
  - AI Review 默认只评论、不阻塞 merge。
51
51
  - 只有在 CI 稳定、误报可控、团队明确同意后,才考虑将特定静态规则设为 blocking。
52
- - AI 的建议必须由人类判断,不得自动 merge。
52
+ - AI 建议须用实现与测试核实;执行合并必须有用户授权并满足仓库规则。
53
53
 
54
54
  ## AI-assisted PR 要求
55
55
 
56
- PR 描述必须说明:
56
+ 按仓库 PR 模板说明;要求披露 AI 使用时包含:
57
57
 
58
58
  - 是否使用 AI 辅助
59
59
  - AI 负责了哪部分:搜索、实现、测试、review、文档
@@ -62,7 +62,7 @@ PR 描述必须说明:
62
62
 
63
63
  ## Issue 关联与上下文交接
64
64
 
65
- - PR 必须关联 issue 或说明为什么不需要 issue。
65
+ - 按当前仓库规则关联 issue;没有 issue 时清楚描述需求与验收。
66
66
  - PR scope 必须与 issue 的目标、验收标准和明确不做事项一致。
67
67
  - AI-assisted PR 必须说明 AI 负责了哪些阶段,以及人类如何复核。
68
68
  - 多人或多 agent 协作时,PR 描述必须列出 reviewer focus,避免重复 review。
@@ -82,7 +82,7 @@ PR 描述必须说明:
82
82
 
83
83
  - ❌ 不在 `pull_request_target` 中运行 AI agent 读取 PR 代码和 secrets。
84
84
  - ❌ 不给 AI Review workflow 默认 `contents: write`、`pull-requests: write`,除非只用于评论且触发源可信。
85
- - ❌ 不允许 AI 自动合并 PR。
85
+ - ❌ 不因收到审查任务就擅自合并 PR。
86
86
  - ❌ 不把私有提示词、聊天原文、token、cookie、连接串写入 PR。
87
87
  - ✅ AI Review 的 prompt 必须限制任务范围、禁止执行 secrets、要求引用具体文件/行。
88
88
 
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: hai-reach
3
- description: "使用 @h-ai/reach 配置邮件、短信、API 通知和多渠道消息模板。"
3
+ description: "接入邮件、短信、API 通知与模板,处理发送结果、免打扰和可选持久化。"
4
4
  ---
5
5
 
6
6
  # hai-reach
@@ -22,7 +22,7 @@ description: "使用 @h-ai/reach 配置邮件、短信、API 通知和多渠道
22
22
 
23
23
  ## 按需参考
24
24
 
25
- 详细配置、API 签名、错误码和范本在 [reference.md](reference.md)。按下列标题定位所需小节,不默认通读;用例中的业务变量需结合当前应用补齐。
25
+ 按任务读取 [reference.md](reference.md) 的对应小节;签名以当前源码或安装版本的公开类型为准,不默认加载全部资料。示例中的业务变量由应用提供。
26
26
 
27
27
  - 运行环境
28
28
  - 依赖
@@ -24,7 +24,7 @@ description: "使用 @h-ai/reldb 访问 SQLite/PostgreSQL/MySQL,编写 SQL、C
24
24
 
25
25
  ## 按需参考
26
26
 
27
- 详细配置、API 签名、错误码和范本在 [reference.md](reference.md)。按下列标题定位所需小节,不默认通读;用例中的业务变量需结合当前应用补齐。
27
+ 按任务读取 [reference.md](reference.md) 的对应小节;签名以当前源码或安装版本的公开类型为准,不默认加载全部资料。示例中的业务变量由应用提供。
28
28
 
29
29
  - 运行环境
30
30
  - 适用场景
@@ -1,24 +1,12 @@
1
1
  ---
2
2
  name: hai-scheduler
3
- description: "使用 @h-ai/scheduler 注册 cron/API/JS/Hook 任务、手工触发并查询执行日志。"
3
+ description: "注册或排查 cron/API/JS/Hook 任务、手工触发、执行日志、重试取消与多节点调度。"
4
4
  ---
5
5
 
6
6
  # hai-scheduler
7
7
 
8
8
  ## 能力契约
9
9
 
10
- 持久化动态任务每个 `tickInterval`(默认 1000ms)在运行节点刷新;API 操作及获锁后的每次尝试重读定义,读取失败或任务已禁用/删除/改期时中断执行。`tasks` 仅表示最近成功刷新快照,已开始的外部副作用不会回滚。跨节点任务使用 `register()` 与共享数据库、Redis;`init({ tasks })` 是节点本地配置,memory cache 不支持跨进程防重。
11
-
12
- `refreshTasks()` 主动刷新而不执行,同一快照的并发读取合并;保存、更新和删除落库成功后才发布内存投影。清空可选策略使用 `retry: null` / `handler: null`。Hook 业务异常为 `failed` 并重试,缺处理器、取消或 `SchedulerTaskSkippedError` 为 `interrupted`;一次性任务只在成功后删除。`event.context.occurrenceId` 在一次发生的重试期间不变,宿主用其绑定持久幂等回执;跨周期长任务使用宿主持久租约。配置被替换时旧发生停止重试,成功清理前再次核对定义。
13
-
14
- 关闭必须 `await scheduler.close()` 后再关闭数据库和缓存:关闭会拒绝新任务、取消 HTTP/Worker/重试并等待执行链退出。生命周期回调通过事件 `signal` 协作取消,必须自行停止外部副作用,禁止在 Hook 阻塞主线程。旧任务取消后不重试、不删除新实例同 ID 的任务。
15
-
16
- JS 任务每次调用独立 Worker,默认 30000 毫秒期限包含线程启动;超时后等待线程终止才返回失败或重试,同步死循环不会占用主事件循环。上下文和结果须支持结构化克隆。Worker/vm 不构成安全沙箱,仍只接受受信任的服务端代码。
17
-
18
- 初始化为全有或全无:必须检查 `init()` 的 HaiResult。空 ID、重复 ID(包括与数据库记录重复)、无效 cron、持久化读取或解析失败均使初始化失败并清理状态;修正后重试,不会静默跳过任务。
19
-
20
- API 任务 `timeout` 默认 30000 毫秒,覆盖请求及完整响应体读取;`maxResponseBytes` 指定实际接收字节上限(正安全整数,默认 1048576 即 1 MiB),例如 `maxResponseBytes: 10 * 1024 * 1024` 允许最大 10 MiB;非法值在请求前失败。超时、超限和非成功 HTTP 状态均失败,重试由任务 retry 策略控制。
21
-
22
10
  | 项目 | 契约 |
23
11
  | --- | --- |
24
12
  | 能力 | 使用 @h-ai/scheduler 注册 cron/API/JS/Hook 任务、手工触发并查询执行日志 |
@@ -27,189 +15,21 @@ API 任务 `timeout` 默认 30000 毫秒,覆盖请求及完整响应体读取
27
15
  | 输出 | 任务管理、触发和日志查询的 HaiResult |
28
16
  | 限制 | 仅服务端;vm 不是安全沙箱,JS 任务只执行可信代码。多节点需要共享锁,关闭释放调度资源。 |
29
17
 
30
- > `@h-ai/scheduler` 使用统一任务模型管理 API / JS / Hook 三类执行路径,支持持久化、手工触发来源记录、分布式锁与全局生命周期回调。
31
-
32
- ## 运行环境
33
-
34
- > ⚠️ **服务端模块(Node.js only)。** 浏览器端通过 API 端点触发 `scheduler.trigger()` 或查询任务日志。
35
-
36
- ## 依赖
37
-
38
- | 模块 | 用途 | 是否必需 | 初始化要求 |
39
- | --- | --- | --- | --- |
40
- | `@h-ai/reldb` | 任务定义与执行日志持久化 | `enableDb: true` 时必需 | 需在 `scheduler.init()` 前初始化 |
41
- | `@h-ai/cache` | 分布式锁 | 可选 | 初始化后自动启用 |
42
-
43
- ## 使用步骤
44
-
45
- ### 1. 初始化
46
-
47
- ```ts
48
- import { cache } from '@h-ai/cache'
49
- import { core } from '@h-ai/core'
50
- import { reldb } from '@h-ai/reldb'
51
- import { scheduler } from '@h-ai/scheduler'
52
-
53
- await reldb.init({ type: 'sqlite', database: './scheduler.db' })
54
- await cache.init({ type: 'memory' })
55
-
56
- await scheduler.init({
57
- enableDb: true,
58
- maxLogs: 1000,
59
- retentionDays: 30,
60
- hooks: {
61
- onTaskStart(event) {
62
- core.logger.info('Task started', { taskId: event.task.id, trigger: event.trigger })
63
- },
64
- onTaskInterrupted(event) {
65
- core.logger.warn('Task interrupted', { taskId: event.task.id, reason: event.reason })
66
- },
67
- onTaskFinish(event) {
68
- core.logger.info('Task finished', { status: event.log.status })
69
- },
70
- },
71
- })
72
- ```
73
-
74
- ### 2. 注册任务
75
-
76
- ```ts
77
- await scheduler.register({
78
- id: 'health-check',
79
- name: '健康检查',
80
- description: '每 5 分钟巡检一次接口健康状态',
81
- cron: '*/5 * * * *',
82
- params: { channel: 'ops' },
83
- retry: { maxAttempts: 3, backoffMs: [1000, 5000] },
84
- handler: {
85
- kind: 'api',
86
- url: 'https://api.example.com/health',
87
- method: 'GET',
88
- },
89
- })
90
-
91
- await scheduler.register({
92
- id: 'cleanup',
93
- name: '清理过期数据',
94
- description: '夜间单次清理任务',
95
- cron: '0 2 * * *',
96
- deleteAfterRun: true,
97
- params: { source: 'nightly' },
98
- handler: {
99
- kind: 'js',
100
- code: '(context) => ({ taskId: context.taskId, params: context.params })',
101
- },
102
- })
103
- ```
104
-
105
- > ⚠️ **安全警示**:`kind: 'js'` 仅允许受信任的服务端代码。当前实现使用 Node.js `vm` 便捷执行,不是安全沙箱;禁止把用户、租户或运营后台自由输入的 JS 字符串直接注册为任务。需要可配置执行逻辑时,优先改用 `kind: 'api'` 或 `hooks.onTaskExecute`。
106
-
107
- ### 3. 使用全局 execute hook 处理无 handler 任务
108
-
109
- ```ts
110
- await scheduler.setHooks({
111
- async onTaskExecute(event) {
112
- return { via: 'hook', source: event.context.trigger.source }
113
- },
114
- })
115
-
116
- await scheduler.register({
117
- id: 'hook-task',
118
- name: 'Hook 任务',
119
- cron: '* * * * *',
120
- })
121
- ```
122
-
123
- ### 4. 手工触发与日志查询
124
-
125
- ```ts
126
- const result = await scheduler.trigger('cleanup', { source: 'admin-console' })
127
-
128
- const logs = await scheduler.getLogs({
129
- taskId: 'cleanup',
130
- triggerType: 'manual',
131
- triggerSource: 'admin-console',
132
- startedAfter: Date.now() - 24 * 60 * 60 * 1000,
133
- startedBefore: Date.now(),
134
- pagination: { page: 1, pageSize: 20 },
135
- })
136
- ```
137
-
138
- ## 核心 API
139
-
140
- | 方法 / 属性 | 签名 | 说明 |
141
- | --- | --- | --- |
142
- | `init` | `(config?) => Promise<HaiResult<void>>` | 初始化调度器 |
143
- | `register` | `(task) => Promise<HaiResult<void>>` | 注册统一任务模型 |
144
- | `updateTask` | `(taskId, updates) => Promise<HaiResult<void>>` | 更新 cron / params / handler |
145
- | `refreshTasks` | `() => Promise<HaiResult<void>>` | 主动刷新共享定义,不执行任务 |
146
- | `register` 扩展字段 | `description / deleteAfterRun / retry` | 支持任务描述、一次性任务、失败重试策略 |
147
- | `trigger` | `(taskId, { source? }) => Promise<HaiResult<TaskExecutionLog>>` | 手工触发并记录来源 |
148
- | `getLogs` | `(options?) => Promise<HaiResult<PaginatedResult<TaskExecutionLog>>>` | 支持按 trigger + startedAfter/startedBefore 过滤日志 |
149
- | `setHooks` | `(hooks) => HaiResult<void>` | 设置全局生命周期回调 |
150
- | `clearHooks` | `() => HaiResult<void>` | 清空全局生命周期回调 |
151
- | `start / stop` | `() => HaiResult<void>` | 启动 / 停止调度 |
152
- | `close` | `() => Promise<void>` | 关闭调度器 |
153
-
154
- ## 常见模式
155
-
156
- ### 持久化 JS 任务
157
-
158
- ```ts
159
- await scheduler.init({ enableDb: true })
160
-
161
- await scheduler.register({
162
- id: 'persisted-js',
163
- name: '持久化 JS 任务',
164
- cron: '*/10 * * * *',
165
- handler: {
166
- kind: 'js',
167
- code: '(context) => ({ taskId: context.taskId })',
168
- },
169
- })
170
- ```
171
-
172
- ### 手工触发来源审计
173
-
174
- ```ts
175
- await scheduler.trigger('cleanup', { source: 'admin-console' })
176
- await scheduler.trigger('cleanup', { source: 'cli' })
177
-
178
- const adminLogs = await scheduler.getLogs({ triggerSource: 'admin-console' })
179
- ```
180
-
181
- ### 分布式锁
18
+ ## 使用路径
182
19
 
183
- ```ts
184
- await cache.init({ type: 'redis', host: 'localhost', port: 6379 })
185
- await reldb.init({ type: 'sqlite', database: './scheduler.db' })
186
- await scheduler.init({
187
- enableDb: true,
188
- maxLogs: 500,
189
- retentionDays: 14,
190
- lockExpireMs: 300000,
191
- nodeId: 'node-1',
192
- })
193
- ```
20
+ 1. 持久化模式先初始化 reldb;多节点需共享数据库与 Redis,Memory 只用于单进程。检查 scheduler.init 的 HaiResult。
21
+ 2. 动态共享任务通过 register 管理,不与 init.tasks 重复声明;读取失败、禁用、删除或改期时不得继续旧任务。
22
+ 3. 根据可信逻辑选择 API/JS/Hook。Worker/vm 不是安全沙箱;Hook 监听 signal,业务以 occurrenceId 处理幂等。
23
+ 4. 明确 timeout、响应大小、重试与执行状态;关闭时 await scheduler.close,再关闭数据库和缓存。
24
+ 5. 验证手动/定时、并发抢锁、失败重试、取消与定义更新。
194
25
 
195
- ## 错误码 — `HaiSchedulerError`
26
+ ## 按需参考
196
27
 
197
- | 错误码 | code | 说明 |
198
- |--------|------|------|
199
- | `HaiSchedulerError.NOT_INITIALIZED` | `hai:scheduler:010` | 未初始化 |
200
- | `HaiSchedulerError.INIT_FAILED` | `hai:scheduler:011` | 初始化失败 |
201
- | `HaiSchedulerError.CONFIG_ERROR` | `hai:scheduler:012` | 配置错误 |
202
- | `HaiSchedulerError.TASK_NOT_FOUND` | `hai:scheduler:020` | 任务不存在 |
203
- | `HaiSchedulerError.TASK_ALREADY_EXISTS` | `hai:scheduler:021` | 任务已存在 |
204
- | `HaiSchedulerError.INVALID_CRON` | `hai:scheduler:022` | Cron 表达式无效 |
205
- | `HaiSchedulerError.EXECUTION_FAILED` | `hai:scheduler:023` | 执行失败 |
206
- | `HaiSchedulerError.JS_EXECUTION_FAILED` | `hai:scheduler:024` | JS 执行失败 |
207
- | `HaiSchedulerError.API_EXECUTION_FAILED` | `hai:scheduler:025` | API 执行失败 |
208
- | `HaiSchedulerError.DB_SAVE_FAILED` | `hai:scheduler:026` | DB 保存失败 |
209
- | `HaiSchedulerError.ALREADY_RUNNING` | `hai:scheduler:027` | 已在运行 |
210
- | `HaiSchedulerError.NOT_RUNNING` | `hai:scheduler:028` | 未在运行 |
211
- | `HaiSchedulerError.LOCK_ACQUIRE_FAILED` | `hai:scheduler:029` | 锁获取失败 |
212
- | `HaiSchedulerError.JS_COMPILE_FAILED` | `hai:scheduler:030` | JS 编译失败 |
213
- | `HaiSchedulerError.HOOK_EXECUTION_FAILED` | `hai:scheduler:031` | Hook 执行失败 |
28
+ 按本次操作读取对应小节;以已安装版本的公开类型核验签名,示例中的业务变量由应用提供。
214
29
 
215
- 调度循环按分钟时间点匹配 cron,并用同一分钟生成分布式锁键;启动或 tick 延迟至非零秒仍检查当前分钟,同一轮运行不会每个 tick 重复调度。
30
+ - [运行环境](reference.md#运行环境)
31
+ - [依赖](reference.md#依赖)
32
+ - [使用步骤](reference.md#使用步骤)
33
+ - [核心 API](reference.md#核心-api)
34
+ - [常见模式](reference.md#常见模式)
35
+ - [错误码 — `HaiSchedulerError`](reference.md#错误码--haischedulererror)