@ranger1/dx 0.1.67 → 0.1.69
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/@opencode/commands/oh_attach.json +5 -5
- package/@opencode/commands/opencode_attach.json +1 -1
- package/@opencode/commands/pr-review-loop.md +5 -6
- package/lib/cli/commands/deploy.js +1 -1
- package/lib/cli/dx-cli.js +8 -5
- package/lib/cli/help.js +2 -2
- package/lib/telegram-webhook.js +119 -21
- package/lib/vercel-deploy.js +17 -3
- package/package.json +1 -1
|
@@ -18,17 +18,17 @@
|
|
|
18
18
|
"model": "openai/gpt-5.3-codex"
|
|
19
19
|
},
|
|
20
20
|
"explore": {
|
|
21
|
-
"model": "openai/gpt-5.
|
|
21
|
+
"model": "openai/gpt-5.3-codex"
|
|
22
22
|
},
|
|
23
23
|
"multimodal-looker": {
|
|
24
24
|
"model": "openai/gpt-5.3-codex"
|
|
25
25
|
},
|
|
26
26
|
"prometheus": {
|
|
27
|
-
"model": "
|
|
27
|
+
"model": "gpt-5.3-codex",
|
|
28
28
|
"variant": "max"
|
|
29
29
|
},
|
|
30
30
|
"metis": {
|
|
31
|
-
"model": "
|
|
31
|
+
"model": "gpt-5.3-codex",
|
|
32
32
|
"variant": "max"
|
|
33
33
|
},
|
|
34
34
|
"momus": {
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"model": "openai/gpt-5.1-codex-min"
|
|
76
76
|
},
|
|
77
77
|
"middle": {
|
|
78
|
-
"model": "openai/gpt-5.
|
|
78
|
+
"model": "openai/gpt-5.3-codex"
|
|
79
79
|
},
|
|
80
80
|
"unspecified-low": {
|
|
81
81
|
"model": "openai/gpt-5.1-codex-min",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"variant": "medium"
|
|
87
87
|
},
|
|
88
88
|
"writing": {
|
|
89
|
-
"model": "openai/gpt-5.
|
|
89
|
+
"model": "openai/gpt-5.3-codex"
|
|
90
90
|
}
|
|
91
91
|
}
|
|
92
92
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
allowed-tools: [Bash, Read, Glob, TodoWrite, Edit, Grep, Task]
|
|
3
3
|
description: '循环审核修复'
|
|
4
|
-
agent: sisyphus
|
|
5
4
|
---
|
|
6
5
|
|
|
7
6
|
# PR Review Loop
|
|
@@ -151,14 +150,14 @@ agent: sisyphus
|
|
|
151
150
|
gh auth status
|
|
152
151
|
|
|
153
152
|
# 1) precheck(round 1)
|
|
154
|
-
python3 "
|
|
153
|
+
python3 "~/.opencode/agents/pr_precheck.py" --pr <PR_NUMBER> --round 1
|
|
155
154
|
|
|
156
155
|
# 2) context(round 1)
|
|
157
|
-
python3 "
|
|
156
|
+
python3 "~/.opencode/agents/pr_context.py" --pr <PR_NUMBER> --round 1
|
|
158
157
|
|
|
159
158
|
# 3) 校验:两者都必须输出单行 JSON,且 runId 必须一致
|
|
160
|
-
python3 "
|
|
161
|
-
python3 "
|
|
159
|
+
python3 "~/.opencode/agents/pr_precheck.py" --pr <PR_NUMBER> --round 1 > ./.cache/_precheck.json
|
|
160
|
+
python3 "~/.opencode/agents/pr_context.py" --pr <PR_NUMBER> --round 1 > ./.cache/_context.json
|
|
162
161
|
python3 - <<'PY'
|
|
163
162
|
import json
|
|
164
163
|
p=json.load(open('./.cache/_precheck.json'))
|
|
@@ -168,7 +167,7 @@ print('OK', p.get('runId'))
|
|
|
168
167
|
PY
|
|
169
168
|
|
|
170
169
|
# 4) 运行脚本相关测试(注意:pytest 把 @ 当作 argfile;必须加 ./ 并加引号)
|
|
171
|
-
python3 -m pytest -q "
|
|
170
|
+
python3 -m pytest -q "~/.opencode/agents/test_pr_review_aggregate.py"
|
|
172
171
|
```
|
|
173
172
|
|
|
174
173
|
## 终止与收尾(强制)
|
|
@@ -40,7 +40,7 @@ export function parseTelegramWebhookFlags(argv = []) {
|
|
|
40
40
|
|
|
41
41
|
const dryRun = args.includes('--webhook-dry-run') ? true : undefined
|
|
42
42
|
|
|
43
|
-
//
|
|
43
|
+
// 默认值由下游决定(当前为默认严格),这里仅处理显式覆盖
|
|
44
44
|
const strict = args.includes('--strict-webhook')
|
|
45
45
|
? true
|
|
46
46
|
: args.includes('--no-strict-webhook')
|
package/lib/cli/dx-cli.js
CHANGED
|
@@ -295,6 +295,13 @@ class DxCli {
|
|
|
295
295
|
|
|
296
296
|
this.validateInputs()
|
|
297
297
|
|
|
298
|
+
// Fail fast for unknown commands before dependency/env startup checks.
|
|
299
|
+
if (this.command && !this.commandHandlers[this.command]) {
|
|
300
|
+
logger.error(`未知命令: ${this.command}`)
|
|
301
|
+
showHelp()
|
|
302
|
+
process.exit(1)
|
|
303
|
+
}
|
|
304
|
+
|
|
298
305
|
// Commands that should work without env/dependency checks.
|
|
299
306
|
// - help: printing help should never require env vars.
|
|
300
307
|
// - status: should be available even when env is incomplete.
|
|
@@ -344,11 +351,7 @@ class DxCli {
|
|
|
344
351
|
}
|
|
345
352
|
|
|
346
353
|
const handler = this.commandHandlers[command]
|
|
347
|
-
if (!handler)
|
|
348
|
-
logger.error(`未知命令: ${command}`)
|
|
349
|
-
showHelp()
|
|
350
|
-
process.exit(1)
|
|
351
|
-
}
|
|
354
|
+
if (!handler) return
|
|
352
355
|
|
|
353
356
|
await handler(subArgs)
|
|
354
357
|
}
|
package/lib/cli/help.js
CHANGED
|
@@ -194,7 +194,7 @@ script 子命令:
|
|
|
194
194
|
Telegram Webhook(仅 target=telegram-bot 生效):
|
|
195
195
|
--webhook-path <path> 对外 webhook 路径(默认 /api/webhook)
|
|
196
196
|
--webhook-dry-run 只打印将设置的 URL,不调用 Telegram API
|
|
197
|
-
--strict-webhook
|
|
197
|
+
--strict-webhook 显式开启严格校验(默认已严格)
|
|
198
198
|
--no-strict-webhook 关闭严格校验(仅告警)
|
|
199
199
|
|
|
200
200
|
常见示例:
|
|
@@ -203,7 +203,7 @@ script 子命令:
|
|
|
203
203
|
dx deploy telegram-bot --staging # 部署 Telegram Bot + 自动配置 Webhook
|
|
204
204
|
dx deploy telegram-bot --staging --webhook-path /webhook # 使用短路径(rewrite 到 /api/webhook)
|
|
205
205
|
dx deploy telegram-bot --prod --webhook-dry-run # 仅打印,不实际调用 Telegram
|
|
206
|
-
dx deploy telegram-bot --
|
|
206
|
+
dx deploy telegram-bot --dev --no-strict-webhook # 开发环境显式降级为仅告警
|
|
207
207
|
dx deploy all --staging # 串行部署 front + admin
|
|
208
208
|
`)
|
|
209
209
|
return
|
package/lib/telegram-webhook.js
CHANGED
|
@@ -17,11 +17,35 @@ function normalizeDeployUrl(raw) {
|
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export function parseDeployUrlFromDeployOutput(output) {
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
const lines = String(output || '')
|
|
21
|
+
.split(/\r?\n/)
|
|
22
|
+
.map(line => String(line || '').trim())
|
|
23
|
+
.filter(Boolean)
|
|
24
|
+
|
|
25
|
+
const pickUrl = line => {
|
|
26
|
+
const m = line.match(/(https?:\/\/)?([a-z0-9-]+\.vercel\.app)\b/i)
|
|
27
|
+
return m ? `https://${m[2]}` : null
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
for (const line of lines) {
|
|
31
|
+
if (!/^production\s*:/i.test(line)) continue
|
|
32
|
+
const url = pickUrl(line)
|
|
33
|
+
if (url) return url
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
for (const line of lines) {
|
|
37
|
+
if (!/^preview\s*:/i.test(line)) continue
|
|
38
|
+
const url = pickUrl(line)
|
|
39
|
+
if (url) return url
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
for (const line of lines) {
|
|
43
|
+
if (/to deploy to production/i.test(line)) continue
|
|
44
|
+
const url = pickUrl(line)
|
|
45
|
+
if (url) return url
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return null
|
|
25
49
|
}
|
|
26
50
|
|
|
27
51
|
export function parseDeployUrlFromVercelListOutput(output, projectNameHint) {
|
|
@@ -72,7 +96,7 @@ export async function handleTelegramBotDeploy(environment, projectId, orgId, tok
|
|
|
72
96
|
strict: strictOverride,
|
|
73
97
|
} = options || {}
|
|
74
98
|
|
|
75
|
-
const strictDefault =
|
|
99
|
+
const strictDefault = true
|
|
76
100
|
|
|
77
101
|
const strictEnv = process.env.DX_TELEGRAM_WEBHOOK_STRICT != null
|
|
78
102
|
? !['0', 'false', 'no'].includes(String(process.env.DX_TELEGRAM_WEBHOOK_STRICT).toLowerCase())
|
|
@@ -103,12 +127,25 @@ export async function handleTelegramBotDeploy(environment, projectId, orgId, tok
|
|
|
103
127
|
logger.error(` - ${v}`)
|
|
104
128
|
})
|
|
105
129
|
|
|
130
|
+
const message = 'Telegram Webhook 配置失败:缺少必需环境变量'
|
|
106
131
|
if (strict) {
|
|
107
|
-
|
|
132
|
+
return {
|
|
133
|
+
status: 'failed',
|
|
134
|
+
reason: 'missing_env_vars',
|
|
135
|
+
strict,
|
|
136
|
+
message,
|
|
137
|
+
missingVars,
|
|
138
|
+
}
|
|
108
139
|
}
|
|
109
140
|
|
|
110
141
|
logger.warn('跳过 Webhook 配置,请手动设置')
|
|
111
|
-
return
|
|
142
|
+
return {
|
|
143
|
+
status: 'warning',
|
|
144
|
+
reason: 'missing_env_vars',
|
|
145
|
+
strict,
|
|
146
|
+
message,
|
|
147
|
+
missingVars,
|
|
148
|
+
}
|
|
112
149
|
}
|
|
113
150
|
|
|
114
151
|
try {
|
|
@@ -122,12 +159,22 @@ export async function handleTelegramBotDeploy(environment, projectId, orgId, tok
|
|
|
122
159
|
projectNameHint,
|
|
123
160
|
})
|
|
124
161
|
if (!deploymentUrl) {
|
|
162
|
+
const message = '无法获取 Vercel 部署 URL'
|
|
125
163
|
if (strict) {
|
|
126
|
-
|
|
164
|
+
return {
|
|
165
|
+
status: 'failed',
|
|
166
|
+
reason: 'missing_deploy_url',
|
|
167
|
+
strict,
|
|
168
|
+
message,
|
|
169
|
+
}
|
|
127
170
|
}
|
|
128
|
-
|
|
129
171
|
logger.error('无法获取 Vercel 部署 URL,跳过 Webhook 配置')
|
|
130
|
-
return
|
|
172
|
+
return {
|
|
173
|
+
status: 'warning',
|
|
174
|
+
reason: 'missing_deploy_url',
|
|
175
|
+
strict,
|
|
176
|
+
message,
|
|
177
|
+
}
|
|
131
178
|
}
|
|
132
179
|
|
|
133
180
|
const webhookUrl = `${deploymentUrl}${webhookPath}`
|
|
@@ -135,7 +182,13 @@ export async function handleTelegramBotDeploy(environment, projectId, orgId, tok
|
|
|
135
182
|
|
|
136
183
|
if (dryRun) {
|
|
137
184
|
logger.warn('DX_TELEGRAM_WEBHOOK_DRY_RUN=1,已跳过 setWebhook/getWebhookInfo 调用')
|
|
138
|
-
return
|
|
185
|
+
return {
|
|
186
|
+
status: 'warning',
|
|
187
|
+
reason: 'dry_run',
|
|
188
|
+
strict,
|
|
189
|
+
message: 'DX_TELEGRAM_WEBHOOK_DRY_RUN=1',
|
|
190
|
+
webhookUrl,
|
|
191
|
+
}
|
|
139
192
|
}
|
|
140
193
|
|
|
141
194
|
// 3. 调用 Telegram API 设置 Webhook
|
|
@@ -163,15 +216,38 @@ export async function handleTelegramBotDeploy(environment, projectId, orgId, tok
|
|
|
163
216
|
logger.info(`Webhook URL: ${webhookUrl}`)
|
|
164
217
|
|
|
165
218
|
// 4. 验证 Webhook 状态
|
|
166
|
-
await verifyWebhook(botToken, webhookUrl, { strict })
|
|
219
|
+
const verifyResult = await verifyWebhook(botToken, webhookUrl, { strict })
|
|
220
|
+
if (verifyResult.status === 'success') {
|
|
221
|
+
return {
|
|
222
|
+
status: 'success',
|
|
223
|
+
reason: 'verified',
|
|
224
|
+
strict,
|
|
225
|
+
webhookUrl,
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return {
|
|
230
|
+
status: strict ? 'failed' : 'warning',
|
|
231
|
+
reason: 'verify_failed',
|
|
232
|
+
strict,
|
|
233
|
+
message: verifyResult.message,
|
|
234
|
+
webhookUrl,
|
|
235
|
+
}
|
|
167
236
|
}
|
|
168
237
|
else {
|
|
169
238
|
const desc = result.description || '未知错误'
|
|
239
|
+
const message = `Telegram Webhook 设置失败: ${desc}`
|
|
170
240
|
if (strict) {
|
|
171
|
-
|
|
241
|
+
return {
|
|
242
|
+
status: 'failed',
|
|
243
|
+
reason: 'set_webhook_failed',
|
|
244
|
+
strict,
|
|
245
|
+
message,
|
|
246
|
+
webhookUrl,
|
|
247
|
+
}
|
|
172
248
|
}
|
|
173
249
|
|
|
174
|
-
logger.error(
|
|
250
|
+
logger.error(message)
|
|
175
251
|
logger.info('请手动执行以下命令(不要把明文 token/secret 写进日志):')
|
|
176
252
|
const manualPayload = JSON.stringify({
|
|
177
253
|
url: webhookUrl,
|
|
@@ -181,15 +257,28 @@ export async function handleTelegramBotDeploy(environment, projectId, orgId, tok
|
|
|
181
257
|
logger.info(
|
|
182
258
|
`curl -X POST "https://api.telegram.org/bot<YOUR_BOT_TOKEN>/setWebhook" -H "Content-Type: application/json" -d '${manualPayload}' --silent`,
|
|
183
259
|
)
|
|
260
|
+
return {
|
|
261
|
+
status: 'warning',
|
|
262
|
+
reason: 'set_webhook_failed',
|
|
263
|
+
strict,
|
|
264
|
+
message,
|
|
265
|
+
webhookUrl,
|
|
266
|
+
}
|
|
184
267
|
}
|
|
185
268
|
}
|
|
186
269
|
catch (error) {
|
|
187
270
|
const message = error?.message || String(error)
|
|
188
271
|
logger.error(`Webhook 配置失败: ${message}`)
|
|
189
272
|
|
|
190
|
-
if (strict)
|
|
191
|
-
|
|
192
|
-
|
|
273
|
+
if (!strict) {
|
|
274
|
+
logger.warn('请手动设置 Webhook(参考 apps/telegram-bot/README.md)')
|
|
275
|
+
}
|
|
276
|
+
return {
|
|
277
|
+
status: strict ? 'failed' : 'warning',
|
|
278
|
+
reason: 'runtime_error',
|
|
279
|
+
strict,
|
|
280
|
+
message,
|
|
281
|
+
}
|
|
193
282
|
}
|
|
194
283
|
}
|
|
195
284
|
|
|
@@ -315,19 +404,28 @@ async function verifyWebhook(botToken, expectedWebhookUrl, options = {}) {
|
|
|
315
404
|
|
|
316
405
|
if (expectedWebhookUrl && info.url !== expectedWebhookUrl) {
|
|
317
406
|
const message = `Webhook 未生效:期望 ${expectedWebhookUrl},实际 ${info.url || '(empty)'}`
|
|
318
|
-
if (strict)
|
|
407
|
+
if (strict) {
|
|
408
|
+
return { status: 'failed', message }
|
|
409
|
+
}
|
|
319
410
|
logger.warn(message)
|
|
411
|
+
return { status: 'warning', message }
|
|
320
412
|
}
|
|
413
|
+
return { status: 'success' }
|
|
321
414
|
}
|
|
322
415
|
else {
|
|
323
416
|
const desc = result?.description || '未知错误'
|
|
324
417
|
const message = `getWebhookInfo 失败: ${desc}`
|
|
325
|
-
if (strict)
|
|
418
|
+
if (strict) {
|
|
419
|
+
return { status: 'failed', message }
|
|
420
|
+
}
|
|
326
421
|
logger.warn(message)
|
|
422
|
+
return { status: 'warning', message }
|
|
327
423
|
}
|
|
328
424
|
}
|
|
329
425
|
catch (error) {
|
|
330
|
-
|
|
426
|
+
const message = error?.message || String(error)
|
|
427
|
+
if (strict) return { status: 'failed', message }
|
|
331
428
|
logger.warn('无法验证 Webhook 状态')
|
|
429
|
+
return { status: 'warning', message: '无法验证 Webhook 状态' }
|
|
332
430
|
}
|
|
333
431
|
}
|
package/lib/vercel-deploy.js
CHANGED
|
@@ -260,6 +260,7 @@ export async function deployToVercel(target, options = {}) {
|
|
|
260
260
|
const {
|
|
261
261
|
environment = 'staging',
|
|
262
262
|
telegramWebhook = null,
|
|
263
|
+
telegramWebhookHandler = null,
|
|
263
264
|
strictContext = true,
|
|
264
265
|
run = runVercel
|
|
265
266
|
} = options
|
|
@@ -482,13 +483,26 @@ export async function deployToVercel(target, options = {}) {
|
|
|
482
483
|
|
|
483
484
|
// Telegram Bot 部署成功后自动设置 Webhook(并做严格校验)
|
|
484
485
|
if (t === 'telegram-bot') {
|
|
485
|
-
const
|
|
486
|
-
|
|
486
|
+
const resolvedWebhookHandler = telegramWebhookHandler
|
|
487
|
+
|| (await import('./telegram-webhook.js')).handleTelegramBotDeploy
|
|
488
|
+
const webhookResult = await resolvedWebhookHandler(environment, projectId, orgId, token, {
|
|
487
489
|
deployOutput,
|
|
488
490
|
projectNameHint: 'telegram-bot',
|
|
489
491
|
...(telegramWebhook || {})
|
|
490
492
|
})
|
|
491
|
-
|
|
493
|
+
|
|
494
|
+
if (webhookResult?.status === 'success') {
|
|
495
|
+
logger.success(`${t} 部署成功(Webhook 已校验)`)
|
|
496
|
+
} else if (webhookResult?.status === 'failed') {
|
|
497
|
+
const reason = webhookResult?.message || webhookResult?.reason || '未知原因'
|
|
498
|
+
logger.error(`${t} 部署成功,但 Webhook 配置失败: ${reason}`)
|
|
499
|
+
process.exitCode = 1
|
|
500
|
+
return
|
|
501
|
+
} else {
|
|
502
|
+
const reason = webhookResult?.message || webhookResult?.reason || '未严格校验'
|
|
503
|
+
logger.warn(`${t} 部署成功,但 Webhook 未完成校验: ${reason}`)
|
|
504
|
+
logger.success(`${t} 部署成功`)
|
|
505
|
+
}
|
|
492
506
|
} else {
|
|
493
507
|
logger.success(`${t} 部署成功`)
|
|
494
508
|
}
|