@ranger1/dx 0.1.68 → 0.1.70
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/codex/agents/fixer.toml +38 -0
- package/codex/agents/orchestrator.toml +9 -0
- package/codex/agents/reviewer.toml +39 -0
- package/codex/agents/spark.toml +21 -0
- package/codex/skills/doctor/SKILL.md +9 -2
- package/codex/skills/doctor/scripts/doctor.sh +261 -2
- package/codex/skills/pr-review-loop/SKILL.md +202 -0
- package/codex/skills/pr-review-loop/agents/openai.yaml +4 -0
- package/codex/skills/pr-review-loop/references/agents/logic-reviewer.md +22 -0
- package/codex/skills/pr-review-loop/references/agents/pr-context.md +73 -0
- package/codex/skills/pr-review-loop/references/agents/pr-precheck.md +152 -0
- package/codex/skills/pr-review-loop/references/agents/pr-review-aggregate.md +152 -0
- package/codex/skills/pr-review-loop/references/agents/security-reviewer.md +21 -0
- package/codex/skills/pr-review-loop/references/agents/style-reviewer.md +22 -0
- package/codex/skills/pr-review-loop/references/skill-layout.md +25 -0
- package/codex/skills/pr-review-loop/scripts/gh_review_harvest.py +292 -0
- package/codex/skills/pr-review-loop/scripts/pr_context.py +351 -0
- package/codex/skills/pr-review-loop/scripts/pr_review_aggregate.py +866 -0
- package/codex/skills/pr-review-loop/scripts/test_pr_review_aggregate.py +751 -0
- package/lib/cli/help.js +1 -1
- package/lib/opencode-initial.js +11 -5
- 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
|
## 终止与收尾(强制)
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
model = "gpt-5.3-codex"
|
|
2
|
+
model_reasoning_effort = "medium"
|
|
3
|
+
approval_policy = "never"
|
|
4
|
+
sandbox_mode = "workspace-write"
|
|
5
|
+
network_access = true
|
|
6
|
+
|
|
7
|
+
developer_instructions = '''
|
|
8
|
+
你是 fix 代理。
|
|
9
|
+
|
|
10
|
+
输入必须包含:PR 编号、round、runId、fixFile。
|
|
11
|
+
缓存目录固定为 `./.cache/`,路径一律使用 `./.cache/<file>`(禁止 basename-only)。
|
|
12
|
+
|
|
13
|
+
快速失败(缺失即报错并退出):
|
|
14
|
+
- 缺 PR 编号:`{"error":"MISSING_PR_NUMBER"}`
|
|
15
|
+
- 缺 fixFile:`{"error":"MISSING_FIX_FILE"}`
|
|
16
|
+
- fixFile 不可读:`{"error":"FIX_FILE_NOT_READABLE"}`
|
|
17
|
+
- fixFile 无法解析 `IssuesToFix`:`{"error":"INVALID_FIX_FILE"}`
|
|
18
|
+
|
|
19
|
+
强制规则:
|
|
20
|
+
1. 仅处理 fixFile 中问题:`IssuesToFix` 必修;`OptionalIssues` 可修可拒绝(需写 reason),禁止范围外改动。
|
|
21
|
+
2. 每个 findingId 单独一个 commit,提交信息必须包含 findingId(示例:`fix(pr #<PR>): <FINDING_ID> <title>`)。
|
|
22
|
+
3. 每次提交后 push(首次无 upstream 可 `git push -u origin HEAD`),全部处理完再 `git push` 兜底。
|
|
23
|
+
4. 无法修复的项必须写明 reason,并记入 Rejected。
|
|
24
|
+
5. 必须维护 `./.cache/decision-log-pr<PR>.md`:按轮次追加 Fixed/Rejected,禁止覆盖历史。
|
|
25
|
+
6. Decision Log 每条必须包含:id、file、essence;预检修复允许 `file: __precheck__`。
|
|
26
|
+
7. 修复后执行 `dx lint` 与 `dx build all`;失败则不得声称完成。
|
|
27
|
+
8. 生成 `./.cache/fix-report-pr<PR>-r<ROUND>-<RUN_ID>.md`(可直接用于 PR 评论,且不包含本地绝对路径)。
|
|
28
|
+
9. 禁止执行 GitHub 评论发布动作(如 `gh pr comment` / `gh pr review`),发布由编排器负责。
|
|
29
|
+
10. 修改 `json/jsonc` 文件时必须使用脚本方式(如 python)改写,禁止手工字符串拼接导致格式损坏。
|
|
30
|
+
11. 最终响应只输出一行:`fixReportFile: ./.cache/<file>.md`;失败只输出一行 JSON 错误。
|
|
31
|
+
|
|
32
|
+
推送失败处理(强制):
|
|
33
|
+
1. 若 `git push` 失败,先判断是否为网络类失败(如 DNS 解析失败、连接拒绝、超时)。
|
|
34
|
+
2. 网络类失败必须重试当前 push 最多 2 次(总 3 次尝试),退避 2s / 5s。
|
|
35
|
+
3. 每次重试前执行轻量检查:`gh auth status`、`git remote -v`、`git ls-remote origin -h`。
|
|
36
|
+
4. 若重试后仍失败,必须返回结构化错误:`{"error":"GIT_PUSH_FAILED_NETWORK","step":"push","detail":"..."}`。
|
|
37
|
+
5. 禁止在 push 未成功时伪造“已完成修复”或输出成功 fixReportFile。
|
|
38
|
+
'''
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
model = "gpt-5.3-codex"
|
|
2
|
+
model_reasoning_effort = "medium"
|
|
3
|
+
approval_policy = "never"
|
|
4
|
+
sandbox_mode = "workspace-write"
|
|
5
|
+
network_access = true
|
|
6
|
+
|
|
7
|
+
developer_instructions = '''
|
|
8
|
+
你是 reviewer 代理。
|
|
9
|
+
|
|
10
|
+
输入必须包含:PR 编号、round、runId、contextFile、reviewerPromptFile(可选 decisionLogFile)。
|
|
11
|
+
|
|
12
|
+
强制规则:
|
|
13
|
+
1. 默认已位于 PR head 对应分支:优先直接读取工作区代码;必要时可用只读 git/gh 命令补充上下文。
|
|
14
|
+
2. 只基于当前代码与 contextFile 评审,禁止凭空猜测不存在的实现。
|
|
15
|
+
3. 忽略:纯格式化噪音、lint 已覆盖的格式问题、单测数量不足本身。
|
|
16
|
+
4. 必须先读取 `reviewerPromptFile` 并严格执行其中定义的“角色码 / 专责范围 / 专属审核词”。
|
|
17
|
+
- 若 `reviewerPromptFile` 不存在、不可读或不在 `${CODEX_HOME:-$HOME/.codex}/skills/pr-review-loop/references/agents/` 下,返回 `{"error":"INVALID_REVIEWER_PROMPT_FILE"}`。
|
|
18
|
+
- 若本文件规则与 `reviewerPromptFile` 有冲突,以 `reviewerPromptFile` 为准。
|
|
19
|
+
- reviewer 只负责当前 `reviewerPromptFile` 指定的审查视角,禁止越权扩展到其他视角。
|
|
20
|
+
5. runId 仅允许透传(格式 `<PR>-<ROUND>-<HEAD_SHORT>`),禁止自行重算或改写。
|
|
21
|
+
6. 决策日志约束(当提供 decisionLogFile 时强制生效):
|
|
22
|
+
- Fixed 不再重复提出。
|
|
23
|
+
- Rejected 除非优先级升级 >=2,否则不再提出。
|
|
24
|
+
- 匹配时必须 file 一致,不做跨文件/重命名追踪。
|
|
25
|
+
- 不质疑已修复问题的实现方式(除非发现修复引入新 bug)。
|
|
26
|
+
7. 缓存约定:统一使用 `./.cache/`,交接路径必须是 repo 相对路径(`./.cache/<file>`),禁止 basename-only。
|
|
27
|
+
8. 输出文件命名:`./.cache/review-<ROLE_CODE>-pr<PR_NUMBER>-r<ROUND>-<RUN_ID>.md`。
|
|
28
|
+
- `<ROLE_CODE>` 由 `reviewerPromptFile` 提供(例如 SEC / LOG / STY)。
|
|
29
|
+
- findings 的 `id` 前缀必须是 `<ROLE_CODE>-`。
|
|
30
|
+
9. reviewFile 内容必须是以下结构(字段名不可改):
|
|
31
|
+
- `# Review (<ROLE_CODE>)`
|
|
32
|
+
- `PR: <PR_NUMBER>`
|
|
33
|
+
- `Round: <ROUND>`
|
|
34
|
+
- `## Summary`,含 `P0/P1/P2/P3` 四行计数
|
|
35
|
+
- `## Findings`,每条 finding 包含:
|
|
36
|
+
`id / priority / category / file / line / title / description / suggestion`
|
|
37
|
+
10. 最终响应只输出一行:`reviewFile: ./.cache/<file>.md`。
|
|
38
|
+
|
|
39
|
+
'''
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
model = "gpt-5.3-codex"
|
|
2
|
+
model_reasoning_effort = "medium"
|
|
3
|
+
approval_policy = "never"
|
|
4
|
+
sandbox_mode = "workspace-write"
|
|
5
|
+
network_access = true
|
|
6
|
+
|
|
7
|
+
developer_instructions = '''
|
|
8
|
+
你是一个通用agent 根据输入的提示词,完整遵循他的要求执行任务
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
输入必须包含:
|
|
12
|
+
--prompt 提示词字符串,要求严格按照提示词执行
|
|
13
|
+
--others 其他参数根据提示词要求
|
|
14
|
+
|
|
15
|
+
强制规则:
|
|
16
|
+
如果传入的prompt是一个文件路径,必须读取文件内容作为提示词,否则直接使用传入的字符串作为提示词。
|
|
17
|
+
prompt是一个文件路径并不存在时,必须返回结构化错误:{"error":"PROMPT_FILE_NOT_FOUND","detail":"<file_path>"}
|
|
18
|
+
|
|
19
|
+
'''
|
|
20
|
+
|
|
21
|
+
|
|
@@ -33,11 +33,18 @@ bash "$CODEX_HOME/skills/doctor/scripts/doctor.sh" --max-rounds 3
|
|
|
33
33
|
|
|
34
34
|
## 脚本职责
|
|
35
35
|
|
|
36
|
-
- 并行检测:`python3`、`python` 别名、`pnpm`、`dx`、`agent-browser`、`rg`、`multi_agent
|
|
36
|
+
- 并行检测:`python3`、`python` 别名、`pnpm`、`dx`、`agent-browser`、`rg`、`multi_agent`、`~/.codex/config.toml` 关键配置。
|
|
37
37
|
- 自动修复:按平台选择安装器修复缺失项。
|
|
38
|
+
- 自动修复:确保 `~/.codex/config.toml` 含以下目标值(缺失补齐、值不符覆盖):
|
|
39
|
+
- `[features] multi_agent = true`
|
|
40
|
+
- `[agents] max_threads = 15`
|
|
41
|
+
- `[agents.fixer] description/model_reasoning_effort/config_file`
|
|
42
|
+
- `[agents.orchestrator] description/config_file`
|
|
43
|
+
- `[agents.reviewer] description/config_file`
|
|
44
|
+
- `[agents.spark] description/config_file`
|
|
38
45
|
- 强制执行:每轮都运行 `pnpm add -g @ranger1/dx@latest && dx initial`。
|
|
39
46
|
- agent-browser:安装/升级并执行 Chromium 安装。
|
|
40
|
-
-
|
|
47
|
+
- 结果输出:展示每项状态、版本、关键信息(含 `codex_config` 检测项);全部通过则退出 0,否则最多三轮后退出 1。
|
|
41
48
|
|
|
42
49
|
## 注意
|
|
43
50
|
|
|
@@ -21,6 +21,7 @@ fi
|
|
|
21
21
|
|
|
22
22
|
CACHE_ROOT="${PWD}/.cache/doctor"
|
|
23
23
|
mkdir -p "$CACHE_ROOT"
|
|
24
|
+
CODEX_HOME="${CODEX_HOME:-$HOME/.codex}"
|
|
24
25
|
|
|
25
26
|
LAST_CHECK_DIR=""
|
|
26
27
|
DX_FORCE_OK=0
|
|
@@ -177,6 +178,251 @@ ensure_multi_agent() {
|
|
|
177
178
|
echo "$line" | grep -E "experimental[[:space:]]+true" >/dev/null 2>&1
|
|
178
179
|
}
|
|
179
180
|
|
|
181
|
+
ensure_codex_config() {
|
|
182
|
+
local cfg_dir cfg_file tmp_file
|
|
183
|
+
cfg_dir="$CODEX_HOME"
|
|
184
|
+
cfg_file="$cfg_dir/config.toml"
|
|
185
|
+
tmp_file="$cfg_file.tmp.$$"
|
|
186
|
+
|
|
187
|
+
mkdir -p "$cfg_dir"
|
|
188
|
+
if [[ ! -f "$cfg_file" ]]; then
|
|
189
|
+
: >"$cfg_file"
|
|
190
|
+
fi
|
|
191
|
+
|
|
192
|
+
awk '
|
|
193
|
+
BEGIN {
|
|
194
|
+
in_features=0; in_agents=0; in_fixer=0; in_orch=0; in_reviewer=0; in_spark=0;
|
|
195
|
+
features_emitted=0; agents_emitted=0; fixer_emitted=0; orch_emitted=0; reviewer_emitted=0; spark_emitted=0;
|
|
196
|
+
features_multi_written=0; agents_max_threads_written=0;
|
|
197
|
+
fixer_desc_written=0; fixer_reasoning_written=0; fixer_cfg_written=0;
|
|
198
|
+
orch_desc_written=0; orch_cfg_written=0;
|
|
199
|
+
reviewer_desc_written=0; reviewer_cfg_written=0;
|
|
200
|
+
spark_desc_written=0; spark_cfg_written=0;
|
|
201
|
+
}
|
|
202
|
+
function trim(s) { gsub(/^[[:space:]]+|[[:space:]]+$/, "", s); return s }
|
|
203
|
+
function reset_sections() {
|
|
204
|
+
in_features=0; in_agents=0; in_fixer=0; in_orch=0; in_reviewer=0; in_spark=0;
|
|
205
|
+
}
|
|
206
|
+
function flush_features() {
|
|
207
|
+
if (!features_emitted) return;
|
|
208
|
+
if (!features_multi_written) print "multi_agent = true";
|
|
209
|
+
}
|
|
210
|
+
function flush_agents() {
|
|
211
|
+
if (!agents_emitted) return;
|
|
212
|
+
if (!agents_max_threads_written) print "max_threads = 15";
|
|
213
|
+
}
|
|
214
|
+
function flush_fixer() {
|
|
215
|
+
if (!fixer_emitted) return;
|
|
216
|
+
if (!fixer_desc_written) print "description = \"bug fixer\"";
|
|
217
|
+
if (!fixer_reasoning_written) print "model_reasoning_effort = \"medium\"";
|
|
218
|
+
if (!fixer_cfg_written) print "config_file = \"~/.codex/agents/fixer.toml\"";
|
|
219
|
+
}
|
|
220
|
+
function flush_orch() {
|
|
221
|
+
if (!orch_emitted) return;
|
|
222
|
+
if (!orch_desc_written) print "description = \"orchestrator\"";
|
|
223
|
+
if (!orch_cfg_written) print "config_file = \"~/.codex/agents/orchestrator.toml\"";
|
|
224
|
+
}
|
|
225
|
+
function flush_reviewer() {
|
|
226
|
+
if (!reviewer_emitted) return;
|
|
227
|
+
if (!reviewer_desc_written) print "description = \"reviewer\"";
|
|
228
|
+
if (!reviewer_cfg_written) print "config_file = \"~/.codex/agents/reviewer.toml\"";
|
|
229
|
+
}
|
|
230
|
+
function flush_spark() {
|
|
231
|
+
if (!spark_emitted) return;
|
|
232
|
+
if (!spark_desc_written) print "description = \"spark\"";
|
|
233
|
+
if (!spark_cfg_written) print "config_file = \"~/.codex/agents/spark.toml\"";
|
|
234
|
+
}
|
|
235
|
+
function flush_active_section() {
|
|
236
|
+
if (in_features) flush_features();
|
|
237
|
+
if (in_agents) flush_agents();
|
|
238
|
+
if (in_fixer) flush_fixer();
|
|
239
|
+
if (in_orch) flush_orch();
|
|
240
|
+
if (in_reviewer) flush_reviewer();
|
|
241
|
+
if (in_spark) flush_spark();
|
|
242
|
+
}
|
|
243
|
+
function enter_section(line) {
|
|
244
|
+
if (line == "[features]") {
|
|
245
|
+
in_features=1; features_emitted=1;
|
|
246
|
+
return;
|
|
247
|
+
}
|
|
248
|
+
if (line == "[agents]") {
|
|
249
|
+
in_agents=1; agents_emitted=1;
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (line == "[agents.fixer]") {
|
|
253
|
+
in_fixer=1; fixer_emitted=1;
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
if (line == "[agents.orchestrator]") {
|
|
257
|
+
in_orch=1; orch_emitted=1;
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
if (line == "[agents.reviewer]") {
|
|
261
|
+
in_reviewer=1; reviewer_emitted=1;
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
if (line == "[agents.spark]") {
|
|
265
|
+
in_spark=1; spark_emitted=1;
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
{
|
|
270
|
+
line=$0;
|
|
271
|
+
t=trim(line);
|
|
272
|
+
if (match(t, /^\[[^]]+\]$/)) {
|
|
273
|
+
flush_active_section();
|
|
274
|
+
reset_sections();
|
|
275
|
+
enter_section(t);
|
|
276
|
+
print line;
|
|
277
|
+
next;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (in_features && match(t, /^multi_agent[[:space:]]*=/)) {
|
|
281
|
+
if (!features_multi_written) {
|
|
282
|
+
print "multi_agent = true";
|
|
283
|
+
features_multi_written=1;
|
|
284
|
+
}
|
|
285
|
+
next;
|
|
286
|
+
}
|
|
287
|
+
if (in_agents && match(t, /^max_threads[[:space:]]*=/)) {
|
|
288
|
+
if (!agents_max_threads_written) {
|
|
289
|
+
print "max_threads = 15";
|
|
290
|
+
agents_max_threads_written=1;
|
|
291
|
+
}
|
|
292
|
+
next;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
if (in_fixer && match(t, /^description[[:space:]]*=/)) {
|
|
296
|
+
if (!fixer_desc_written) { print "description = \"bug fixer\""; fixer_desc_written=1; }
|
|
297
|
+
next;
|
|
298
|
+
}
|
|
299
|
+
if (in_fixer && match(t, /^model_reasoning_effort[[:space:]]*=/)) {
|
|
300
|
+
if (!fixer_reasoning_written) { print "model_reasoning_effort = \"medium\""; fixer_reasoning_written=1; }
|
|
301
|
+
next;
|
|
302
|
+
}
|
|
303
|
+
if (in_fixer && match(t, /^config_file[[:space:]]*=/)) {
|
|
304
|
+
if (!fixer_cfg_written) { print "config_file = \"~/.codex/agents/fixer.toml\""; fixer_cfg_written=1; }
|
|
305
|
+
next;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
if (in_orch && match(t, /^description[[:space:]]*=/)) {
|
|
309
|
+
if (!orch_desc_written) { print "description = \"orchestrator\""; orch_desc_written=1; }
|
|
310
|
+
next;
|
|
311
|
+
}
|
|
312
|
+
if (in_orch && match(t, /^config_file[[:space:]]*=/)) {
|
|
313
|
+
if (!orch_cfg_written) { print "config_file = \"~/.codex/agents/orchestrator.toml\""; orch_cfg_written=1; }
|
|
314
|
+
next;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (in_reviewer && match(t, /^description[[:space:]]*=/)) {
|
|
318
|
+
if (!reviewer_desc_written) { print "description = \"reviewer\""; reviewer_desc_written=1; }
|
|
319
|
+
next;
|
|
320
|
+
}
|
|
321
|
+
if (in_reviewer && match(t, /^config_file[[:space:]]*=/)) {
|
|
322
|
+
if (!reviewer_cfg_written) { print "config_file = \"~/.codex/agents/reviewer.toml\""; reviewer_cfg_written=1; }
|
|
323
|
+
next;
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
if (in_spark && match(t, /^description[[:space:]]*=/)) {
|
|
327
|
+
if (!spark_desc_written) { print "description = \"spark\""; spark_desc_written=1; }
|
|
328
|
+
next;
|
|
329
|
+
}
|
|
330
|
+
if (in_spark && match(t, /^config_file[[:space:]]*=/)) {
|
|
331
|
+
if (!spark_cfg_written) { print "config_file = \"~/.codex/agents/spark.toml\""; spark_cfg_written=1; }
|
|
332
|
+
next;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
print line;
|
|
336
|
+
}
|
|
337
|
+
END {
|
|
338
|
+
flush_active_section();
|
|
339
|
+
|
|
340
|
+
if (!features_emitted) {
|
|
341
|
+
print "";
|
|
342
|
+
print "[features]";
|
|
343
|
+
print "multi_agent = true";
|
|
344
|
+
}
|
|
345
|
+
if (!agents_emitted) {
|
|
346
|
+
print "";
|
|
347
|
+
print "[agents]";
|
|
348
|
+
print "max_threads = 15";
|
|
349
|
+
}
|
|
350
|
+
if (!fixer_emitted) {
|
|
351
|
+
print "";
|
|
352
|
+
print "[agents.fixer]";
|
|
353
|
+
print "description = \"bug fixer\"";
|
|
354
|
+
print "model_reasoning_effort = \"medium\"";
|
|
355
|
+
print "config_file = \"~/.codex/agents/fixer.toml\"";
|
|
356
|
+
}
|
|
357
|
+
if (!orch_emitted) {
|
|
358
|
+
print "";
|
|
359
|
+
print "[agents.orchestrator]";
|
|
360
|
+
print "description = \"orchestrator\"";
|
|
361
|
+
print "config_file = \"~/.codex/agents/orchestrator.toml\"";
|
|
362
|
+
}
|
|
363
|
+
if (!reviewer_emitted) {
|
|
364
|
+
print "";
|
|
365
|
+
print "[agents.reviewer]";
|
|
366
|
+
print "description = \"reviewer\"";
|
|
367
|
+
print "config_file = \"~/.codex/agents/reviewer.toml\"";
|
|
368
|
+
}
|
|
369
|
+
if (!spark_emitted) {
|
|
370
|
+
print "";
|
|
371
|
+
print "[agents.spark]";
|
|
372
|
+
print "description = \"spark\"";
|
|
373
|
+
print "config_file = \"~/.codex/agents/spark.toml\"";
|
|
374
|
+
}
|
|
375
|
+
}' "$cfg_file" >"$tmp_file"
|
|
376
|
+
|
|
377
|
+
mv "$tmp_file" "$cfg_file"
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
check_codex_config() {
|
|
381
|
+
local cfg_file
|
|
382
|
+
cfg_file="$CODEX_HOME/config.toml"
|
|
383
|
+
[[ -f "$cfg_file" ]] || return 1
|
|
384
|
+
|
|
385
|
+
awk '
|
|
386
|
+
BEGIN {
|
|
387
|
+
in_features=0; in_agents=0; in_fixer=0; in_orch=0; in_reviewer=0; in_spark=0;
|
|
388
|
+
ok_features=0; ok_threads=0; ok_fixer_desc=0; ok_fixer_reason=0; ok_fixer_cfg=0;
|
|
389
|
+
ok_orch_desc=0; ok_orch_cfg=0; ok_reviewer_desc=0; ok_reviewer_cfg=0; ok_spark_desc=0; ok_spark_cfg=0;
|
|
390
|
+
}
|
|
391
|
+
function trim(s) { gsub(/^[[:space:]]+|[[:space:]]+$/, "", s); return s }
|
|
392
|
+
{
|
|
393
|
+
line=trim($0);
|
|
394
|
+
sub(/[[:space:]]+#.*$/, "", line);
|
|
395
|
+
if (line ~ /^\[[^]]+\]$/) {
|
|
396
|
+
in_features=(line=="[features]");
|
|
397
|
+
in_agents=(line=="[agents]");
|
|
398
|
+
in_fixer=(line=="[agents.fixer]");
|
|
399
|
+
in_orch=(line=="[agents.orchestrator]");
|
|
400
|
+
in_reviewer=(line=="[agents.reviewer]");
|
|
401
|
+
in_spark=(line=="[agents.spark]");
|
|
402
|
+
next;
|
|
403
|
+
}
|
|
404
|
+
if (in_features && line ~ /^multi_agent[[:space:]]*=[[:space:]]*true$/) ok_features=1;
|
|
405
|
+
if (in_agents && line ~ /^max_threads[[:space:]]*=[[:space:]]*15$/) ok_threads=1;
|
|
406
|
+
if (in_fixer && line ~ /^description[[:space:]]*=[[:space:]]*"bug fixer"$/) ok_fixer_desc=1;
|
|
407
|
+
if (in_fixer && line ~ /^model_reasoning_effort[[:space:]]*=[[:space:]]*"medium"$/) ok_fixer_reason=1;
|
|
408
|
+
if (in_fixer && line ~ /^config_file[[:space:]]*=[[:space:]]*"~\/\.codex\/agents\/fixer\.toml"$/) ok_fixer_cfg=1;
|
|
409
|
+
if (in_orch && line ~ /^description[[:space:]]*=[[:space:]]*"orchestrator"$/) ok_orch_desc=1;
|
|
410
|
+
if (in_orch && line ~ /^config_file[[:space:]]*=[[:space:]]*"~\/\.codex\/agents\/orchestrator\.toml"$/) ok_orch_cfg=1;
|
|
411
|
+
if (in_reviewer && line ~ /^description[[:space:]]*=[[:space:]]*"reviewer"$/) ok_reviewer_desc=1;
|
|
412
|
+
if (in_reviewer && line ~ /^config_file[[:space:]]*=[[:space:]]*"~\/\.codex\/agents\/reviewer\.toml"$/) ok_reviewer_cfg=1;
|
|
413
|
+
if (in_spark && line ~ /^description[[:space:]]*=[[:space:]]*"spark"$/) ok_spark_desc=1;
|
|
414
|
+
if (in_spark && line ~ /^config_file[[:space:]]*=[[:space:]]*"~\/\.codex\/agents\/spark\.toml"$/) ok_spark_cfg=1;
|
|
415
|
+
}
|
|
416
|
+
END {
|
|
417
|
+
ok = ok_features && ok_threads &&
|
|
418
|
+
ok_fixer_desc && ok_fixer_reason && ok_fixer_cfg &&
|
|
419
|
+
ok_orch_desc && ok_orch_cfg &&
|
|
420
|
+
ok_reviewer_desc && ok_reviewer_cfg &&
|
|
421
|
+
ok_spark_desc && ok_spark_cfg;
|
|
422
|
+
exit(ok ? 0 : 1);
|
|
423
|
+
}' "$cfg_file"
|
|
424
|
+
}
|
|
425
|
+
|
|
180
426
|
force_dx() {
|
|
181
427
|
if ! install_pnpm; then
|
|
182
428
|
DX_FORCE_OK=0
|
|
@@ -287,12 +533,20 @@ run_parallel_checks() {
|
|
|
287
533
|
fi
|
|
288
534
|
) &
|
|
289
535
|
|
|
536
|
+
(
|
|
537
|
+
if check_codex_config; then
|
|
538
|
+
write_check_file "codex_config" "1" "$CODEX_HOME/config.toml" "ok" "$dir/codex_config.res"
|
|
539
|
+
else
|
|
540
|
+
write_check_file "codex_config" "0" "$CODEX_HOME/config.toml" "config.toml 缺失或配置不符合要求" "$dir/codex_config.res"
|
|
541
|
+
fi
|
|
542
|
+
) &
|
|
543
|
+
|
|
290
544
|
wait
|
|
291
545
|
LAST_CHECK_DIR="$dir"
|
|
292
546
|
}
|
|
293
547
|
|
|
294
548
|
all_good() {
|
|
295
|
-
local keys="python3 python_alias pnpm dx agent_browser rg multi_agent"
|
|
549
|
+
local keys="python3 python_alias pnpm dx agent_browser rg multi_agent codex_config"
|
|
296
550
|
local k
|
|
297
551
|
for k in $keys; do
|
|
298
552
|
if ! check_ok "$k"; then
|
|
@@ -309,7 +563,7 @@ print_report() {
|
|
|
309
563
|
printf '%-14s | %-4s | %-40s | %s\n' "检查项" "状态" "版本" "说明"
|
|
310
564
|
printf '%-14s-+-%-4s-+-%-40s-+-%s\n' "--------------" "----" "----------------------------------------" "------------------------------"
|
|
311
565
|
|
|
312
|
-
local keys="python3 python_alias pnpm dx agent_browser rg multi_agent"
|
|
566
|
+
local keys="python3 python_alias pnpm dx agent_browser rg multi_agent codex_config"
|
|
313
567
|
local k ok txt ver msg
|
|
314
568
|
for k in $keys; do
|
|
315
569
|
ok="$(read_field "$k" 2)"
|
|
@@ -368,6 +622,11 @@ for round in $(seq 1 "$MAX_ROUNDS"); do
|
|
|
368
622
|
ensure_multi_agent || true
|
|
369
623
|
fi
|
|
370
624
|
|
|
625
|
+
if ! check_ok "codex_config"; then
|
|
626
|
+
echo "[doctor] 修正 ~/.codex/config.toml 关键配置"
|
|
627
|
+
ensure_codex_config || true
|
|
628
|
+
fi
|
|
629
|
+
|
|
371
630
|
echo "[doctor] 强制执行 dx 安装与初始化"
|
|
372
631
|
force_dx || true
|
|
373
632
|
|