codebee 0.1.61 → 0.1.63

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/CHANGELOG.md CHANGED
@@ -6,23 +6,26 @@ README 元数据带回,供老版本在「发现新版本」时展示新版更
6
6
 
7
7
  ## 未发布
8
8
 
9
+ ## v0.1.63(2026-09-24)
10
+
11
+ - 0.1.62 被并行发布占位(旧 HEAD,不含 runner 修复);本版为完整版
12
+
13
+ ## v0.1.62(2026-09-24)
14
+
9
15
  ### ✨ 新功能
10
16
 
11
- - **工作汇报能直接取禅道数了**:新建「工作汇报」任务时,若已配置禅道集成,起草阶段自动把「分配给我的活跃任务 + 指派给我的活跃 Bug」聚合成本周工作素材注入起草提示(如实取材、缺失数字留待补、勿虚构业绩)——不再只靠你贴流水账。禅道未配置或临时不可达时静默跳过,起草照常。
12
- - **直连对话把「思考过程」打印出来了**:内置智能体改走流式(SSE),模型的思维链(DeepSeek/vLLM 系 `reasoning_content`、Anthropic `thinking` 块)边生成边实时打印进对话时间线,工具调用与正文增量同步显示——此前整轮回答只有三个点的打字动画,几十秒黑箱干等。运行中思考块常开实时增长;回答收尾后收成「思考过程」折叠摘要(带字数,点开回看),思维链同时进步骤日志。网关不支持流式时自动回落非流式(思考字段仍从响应体兜底抽取),取消/多 KEY 换链语义不变。
13
- - **日志抽屉认识 claude 事件流了**:claude 步骤日志此前整段原样 JSON,模型长思考时 `thinking_tokens` 心跳每个流式分片刷一条(真实案:3.2MB 步骤日志 15828 条),把正文顶出尾部窗口。现在抽屉视图按邻近组折叠成一行「— 思考中(心跳 ×N 已折叠,估算 ~M tokens)—」,会话启动/API 重试/思考摘要/正文/收尾统计各自翻译成可读行(API 重试逐条保留——429 与断连诊断金矿);只影响显示,原始日志与结果解析不动。
14
- - 新增**网页成品实时预览**:代码任务跑完,详情页多出「预览」页签——「运行视图」把工作目录里的入口 HTML 真跑起来(iframe 里 style.css / script.js 这些相对引用照常生效,改完点「刷新」即看新版),旁边一排文件页签直接读源码(行号 + 高亮,与成果预览同款),右上角「打开新窗口」给真全屏。借鉴对话式编程产品"边聊边看效果"的体验:终态代码任务跑出了可打开的网页成品时,打开详情直接落在预览;直连对话任务的对话胶囊里也有「预览」入口。没有网页成品的任务(小说、普通脚本)完全不出现这个页签。安全边界:预览是只读静态挂载,只认静态扩展名白名单、拒绝路径穿越与隐藏目录;访问令牌走路径段(iframe 子资源继承不了查询串),鉴权与 /api/* 同一把尺子。
15
- - **直连对话会动手修了**:内置智能体新增 `run_command`,诊断、修复、改配置、重启服务等命令直接在你机器上真实执行(与 codex/claude 全权沙箱同信任档,无确认闸),退出码与输出回给智能体接力下一步——不再只甩一份「照着做」的指南。超时/取消即强杀进程树;Windows 提权命令自动走 UAC 弹窗(点一次允许即可)。顺带修掉一个底层隐患:子进程杀树后管道关闭不再死等漏网孙进程自然退出(此前会让超时杀进程卡满命令时长)。
16
- - 连载小说支持**分卷**:新建任务时给「每卷章数」(默认预填 20,清空 = 不分卷),或在「指定卷结构」里写明各卷(也能直接在任务目标里写「第一卷 少年初入江湖 第1-20章;卷二 风云再起 21-40章」,自动识别)。分卷贯穿四个环节:① 大纲按卷规划,产出卷名与卷弧光(用户给了卷名就原样沿用);② 每章起草与评审都带上「第几卷第几章、是不是卷末」,卷末章按本卷高潮与卷末钩子收束;③ 合并成书插入「第 X 卷 《卷名》」分隔;④ 运行详情的章节评审卡与发布页章节清单按卷分组。卷边界由全书章号确定性推导,续写批次自动接上同一卷、不会把一卷劈成两半。
17
+ - **任务计划活起来了**:`.codebee/task_plan.md` 从静态清单升级为随执行实时推进的活文档——每个子任务起跑标 `[>]`、成功翻 `[x]`、失败标 `[!]`(换将重试成功自动翻正)。任务崩溃、续跑、换将时打开计划文件一眼看到断点走到哪步;回写失败静默,绝不影响任务执行。
18
+ - **skill 装前扫描认得投毒特征了**:新增四组静态特征——下载即执行(`curl|sh` 管道、PowerShell `Invoke-Expression` 投放)、持久化驻留(crontab/计划任务/注册表自启动键,直接判高风险)、常见外传信道(pastebin/webhook.site/ngrok 隧道)、挖矿特征(stratum/xmrig)。中文叙述词零误报。
19
+ - **代码实现不再「顺手加固」了**:实现/修复提示词内置 HERO 反过度防御块——不加任务没要的哈希与校验和、不铺层层边界分支、不自造评分标准、不做顺手加固;只约束「提出什么」不约束「检查什么」,真实风险照找、写进总结由你决定。改动面更贴任务目标,少一轮「修过度工程」的返工。
17
20
 
18
- ### ⚡ 性能
21
+ ### 📒 补记(更早已上线、此前未入版本节)
19
22
 
20
- - **多评审并发**:章节评审与全书评审的多位评审从排队串行改为并发执行——评审占连载运行总时长的六到七成,而各评审读的是同一份稿件、各自独立打分,串行等待纯属时间叠加。每位评审的得分、逐项目标审稿(event_check)与资源账本(ledger)仍按原顺序合并,评分口径与串行版完全一致;某位评审的管道异常照旧上抛打断。同章两评审实测墙钟约 7.2s → 4.2s。
21
- - **超时不再原样重烧**:章稿起草失败重试加「新变量」闸门——上一次就是超时/停滞收场、且这次的提示词与上次逐字节相同时(缩上下文降级未能生效的场景),不再用同样输入再烧一整轮 2400 秒,直接跳到换将(换 CLI/模型才是新机会)。
23
+ - 直连对话流式打印思考过程 + 网页成品实时预览页签 + 直连 `run_command` 真执行 + 连载分卷 + 多评审并发(同章两评审 7.2s→4.2s)+ 超时原样重烧闸门 + 429 限流与欠费同口径切备用 KEY + 工作汇报取禅道数 + 日志抽屉折叠 claude 思考心跳。
22
24
 
23
- ### 🛠 问题修复
25
+ ## v0.1.62(2026-09-24)
24
26
 
25
- - **首选 KEY 超限自动切备用了**:同厂商多密钥此前只认欠费类文案——首选 KEY 撞上 429 限流(智谱「并发数超过限制」「每分钟Token数已超过上限」、claude 的 rate_limit_error、codex 的 "429 Too Many Requests" 等)只记一笔错误、不进冷却,每个新步骤仍从超限的首选 KEY 重新烧起。现在限流文案与欠费同口径:进冷却 30 分钟、密钥镜像自动切下一把、链展开跳过冷却中的 KEY(到期或「恢复」按钮一键回首选)。顺带补一处漏账:无显式链时「换模型回退」的链条目不带 KEY 标记,这类重试失败此前完全不记 KEY 账。
27
+ - 修复评审「命令行太长」:垫片检测此前只看首个参数(是 cmd.exe),漏判了真正的 .cmd 垫片——中等长度评审提示词直接撞 Windows 8191 上限。现扫全部启动参数
28
+ - 代码修复步超时 1200→2400 秒:真实排查型修复(读仓库/追调用链)不再被中途砍死
26
29
 
27
30
  ## v0.1.61(2026-09-24)
28
31
 
package/README.md CHANGED
@@ -20,13 +20,11 @@ Kimi Code、MiMo Code、Grok Build、Pi、DeepSeek Harness……),提供
20
20
  零第三方依赖:纯 Python 标准库(3.8+),本地 Web 界面,数据全部落盘可回放,
21
21
  不会把你的任务内容交给任何第三方。
22
22
 
23
- <!-- relnotes:start -->
24
- ### 最新版更新内容(v0.1.61)
25
23
 
26
- - 修复 mimo 评审器永远「Invalid API Key」:Key 通道缺失(非 Key 失效),现自动注入配置
27
- - 「完成·未达标」琥珀胶囊:跑完但评审未过不再伪装「完成」
28
- - 同工作目录任务自动排队,互不覆盖
29
- <!-- relnotes:end -->
24
+ ### 最新版更新内容(v0.1.63)
25
+
26
+ - 修复评审「命令行太长」(垫片漏判);修复步超时提至 2400 秒
27
+
30
28
 
31
29
  ---
32
30
 
@@ -132,7 +132,11 @@ DEFAULT_CATALOG = [
132
132
  "note": "xAI 终端编码智能体;可执行名是 grok(不是 grok-build);"
133
133
  "默认模型在 ~/.grok/config.toml 的 [models] default(JSON 版配置不存在)",
134
134
  "detect": {"cli": "grok"},
135
- "orch": {"kind": "generic", "command": "grok", "argv_template": ["-p", "{prompt}"]},
135
+ # Grok's CLI retries a failed reqwest connection internally. Keep the
136
+ # adapter's single attempt bounded so a dead endpoint does not consume
137
+ # the entire 20-minute generic timeout before failover.
138
+ "orch": {"kind": "generic", "command": "grok", "argv_template": ["-p", "{prompt}"],
139
+ "timeout_ms": 180000, "stall_timeout_s": 120},
136
140
  "config": {"path": "~/.grok/config.toml", "format": "toml-section",
137
141
  "model_key": "models.default"},
138
142
  "install": "npm install -g @xai-official/grok",
@@ -319,19 +323,20 @@ def _apply_config_patch(entries):
319
323
  e["config"] = dict(patch)
320
324
 
321
325
 
322
- def _apply_stall_patch(entries):
323
- """存量数据幂等补齐:qwencode 补 stall_timeout_s=900(2026-09-22 实案)。
324
-
325
- data/catalog.json 生成后不会再随版本重写,老清单里的 qwencode 没有
326
- 停滞看门狗配置(当时按「结束才一次性输出」留 0);实际验证 qwen 评审
327
- 会先流式吐内容再卡死在 MCP 收尾,静默看门狗能兜住。用户手写过该字段的
328
- 不覆盖(包括显式写 0 关闭的)。"""
329
- for e in entries:
330
- if e.get("id") != "qwencode":
331
- continue
332
- orch = e.get("orch")
333
- if isinstance(orch, dict) and "stall_timeout_s" not in orch:
334
- orch["stall_timeout_s"] = 900
326
+ def _apply_stall_patch(entries):
327
+ """为存量清单补齐 CLI 看门狗和单步上限。
328
+
329
+ data/catalog.json 生成后不会再随版本重写,用户手写过的字段不覆盖
330
+ (包括显式写 0 关闭的)。"""
331
+ for e in entries:
332
+ orch = e.get("orch")
333
+ if not isinstance(orch, dict):
334
+ continue
335
+ if e.get("id") == "qwencode":
336
+ orch.setdefault("stall_timeout_s", 900)
337
+ elif e.get("id") == "grok-build":
338
+ orch.setdefault("timeout_ms", 180000)
339
+ orch.setdefault("stall_timeout_s", 120)
335
340
 
336
341
 
337
342
  def _apply_install_patch(entries):
@@ -722,6 +722,10 @@ __CONTEXT__
722
722
 
723
723
  ## 要求
724
724
  - 修改要最小化、聚焦任务目标;不要无关重构。
725
+ - 反过度防御(借鉴 HERO:只约束你「提出」的方案,不约束你「检查」的范围)——
726
+ 不要给没要求的数据加哈希/校验和;不要为内部脚本铺层层边界分支;
727
+ 不要自造评分标准或质量闸门;超出任务目标的「顺手加固」一律不做。
728
+ 真实风险照样要找:发现就写进总结,由人决定要不要修。
725
729
  - 完成后只用 3-5 句话总结你改了什么、为什么。
726
730
  __VERIFY_HINT__"""
727
731
 
@@ -735,6 +739,8 @@ __ISSUES__
735
739
 
736
740
  ## 要求
737
741
  - 只针对上述问题修复;不要无关重构。
742
+ - 修复轮同样反过度防御:不加任务没要的哈希/边界分支/评分标准/顺手加固;
743
+ 真实风险写进说明,不擅自扩大改动面。
738
744
  - 完成后用 2-3 句话说明改了什么。
739
745
  __VERIFY_HINT__"""
740
746
 
@@ -1203,6 +1209,7 @@ def _run_code(run, task, agents, ev, stats, mode):
1203
1209
  store.update_run(run_id, route=route)
1204
1210
 
1205
1211
  def implement_all(impl_agent, prefix_note):
1212
+ nonlocal reviewer
1206
1213
  # 会话延续只对原实现者有效;换将后新智能体没有该会话,必须丢弃
1207
1214
  use_resume = (resume_ctx["session"]
1208
1215
  if (resume_ctx and impl_agent["id"] == resume_ctx["agent"]["id"]) else None)
@@ -1247,6 +1254,7 @@ def _run_code(run, task, agents, ev, stats, mode):
1247
1254
  .replace("__CONTEXT__", task.get("context") or "(无)")
1248
1255
  .replace("__VERIFY_HINT__", _verify_hint(task))) + prog
1249
1256
  role = "implement" if len(subtasks) == 1 else "implement-%d/%d" % (i + 1, len(subtasks))
1257
+ mark_task_plan(workdir, i + 1, "run") # 活计划:起跑即标进行中
1250
1258
  res = _run_step(run_id, role, agt_b, prompt, step_wd,
1251
1259
  readonly=False, ev=ev,
1252
1260
  note=prefix_note if i == 0 else "",
@@ -1265,7 +1273,9 @@ def _run_code(run, task, agents, ev, stats, mode):
1265
1273
  except Exception:
1266
1274
  pass
1267
1275
  if not res["ok"]:
1276
+ mark_task_plan(workdir, i + 1, "fail")
1268
1277
  return False, res
1278
+ mark_task_plan(workdir, i + 1, "done")
1269
1279
  return True, res
1270
1280
 
1271
1281
  ok, res = _run_one(impl_agent)
@@ -1293,8 +1303,16 @@ def _run_code(run, task, agents, ev, stats, mode):
1293
1303
  # (超时等)仍只换一次,防着在坏候选上再烧一整个超时。
1294
1304
  if mode == "auto" and impl_agent.get("mode") == "real":
1295
1305
  tried = {impl_agent["id"], "mock-a", "mock-b"}
1306
+ dead_ids = {impl_agent["id"]} # 实现步已失败的原实现者,属已知死候选
1296
1307
  notes = []
1297
1308
  dead_ups = [] # 配额死亡候选的上游集合:换将优先异上游
1309
+ # 原实现者若死于配额,其上游(网关/账号)也一并判入死池——否则第一棒
1310
+ # 换将不知道同网关候选已死,评审者重选更会把「与死者同上游」的候选
1311
+ # 继续当活口,评审撞同一条失效网关白烧一轮后误报「评审器故障」。
1312
+ if runner._quota_error(res.get("error") or ""):
1313
+ ups0 = router.agent_upstreams(impl_agent["id"])
1314
+ if ups0:
1315
+ dead_ups.append(ups0)
1298
1316
  prev_id = impl_agent["id"]
1299
1317
  other = None
1300
1318
  while True:
@@ -1310,6 +1328,14 @@ def _run_code(run, task, agents, ev, stats, mode):
1310
1328
  ok2, res = _run_one(other)
1311
1329
  if ok2:
1312
1330
  route_note = ";".join(notes + [note])
1331
+ # 换将成功:预先选定的评审者可能在实现步走查时被证伪为死链
1332
+ # (quota/限流秒死),且死者同上游(同网关)的候选同样不可信。
1333
+ # 按「排除本轮已知死者 + 同上游候选」的池重选评审者,否则评审
1334
+ # 撞同一条失效网关,白烧一轮后误报「评审器故障」。
1335
+ if workflow["review_required"]:
1336
+ reviewer, route["reviewer"] = router.pick_reviewer(
1337
+ agents, other, "code", stats,
1338
+ exclude=dead_ids, dead_upstreams=dead_ups)
1313
1339
  store.update_run(run_id, error="", route_note=route_note)
1314
1340
  _record_actual_route(
1315
1341
  run_id, task, agents, stats, other,
@@ -1320,6 +1346,7 @@ def _run_code(run, task, agents, ev, stats, mode):
1320
1346
  return True
1321
1347
  notes.append(note)
1322
1348
  tried.add(other["id"])
1349
+ dead_ids.add(other["id"])
1323
1350
  prev_id = other["id"]
1324
1351
  if runner._quota_error(res.get("error") or ""):
1325
1352
  ups = router.agent_upstreams(other["id"])
@@ -1390,7 +1417,7 @@ def _run_code(run, task, agents, ev, stats, mode):
1390
1417
  .replace("__VERIFY_HINT__", _verify_hint(task)))
1391
1418
  prompt = attachments.append_task_context(prompt, task)
1392
1419
  res = _run_step(run_id, "fix-r%d" % round_no, modelhub.bind_agent(impl, difficulty),
1393
- prompt, workdir, readonly=False, ev=ev,
1420
+ prompt, workdir, readonly=False, ev=ev, timeout=2400,
1394
1421
  note="自动修复第 %d 轮" % round_no,
1395
1422
  resume=resume_ctx["session"] if resume_ctx else impl_sid[0],
1396
1423
  require_tools=True)
@@ -4106,14 +4133,47 @@ def _write_task_plan(task, workdir, plan):
4106
4133
  return ""
4107
4134
  target.parent.mkdir(parents=True, exist_ok=True)
4108
4135
  lines = ["# 任务计划", "", "来源:%s" % (plan or {}).get("source", "?"), ""]
4136
+ # checkbox 形态:mark_task_plan 按行号翻 [x]/[!]/[>],断点一眼可见
4109
4137
  for i, s in enumerate((plan or {}).get("steps") or [], 1):
4110
- lines.append("%d. %s" % (i, str(s.get("detail") or s.get("title") or "")[:200]))
4138
+ lines.append("%d. [ ] %s" % (i, str(s.get("detail") or s.get("title") or "")[:200]))
4111
4139
  target.write_text("\n".join(lines) + "\n", encoding="utf-8")
4112
4140
  return str(target)
4113
4141
  except Exception:
4114
4142
  return ""
4115
4143
 
4116
4144
 
4145
+ _PLAN_MARK = {"done": "x", "fail": "!", "run": ">"}
4146
+
4147
+
4148
+ def mark_task_plan(workdir, index, status):
4149
+ """活计划回写:把 .codebee/task_plan.md 第 index 项(1 基)的勾选框
4150
+ 翻成 [x](完成)/[!](失败)/[>](进行中)。planning-with-files 的断点
4151
+ 可见性:计划文件随执行实时推进,崩溃/换将/续跑时看文件即知走到哪步。
4152
+ 幂等覆盖(换将重试成功 [!]→[x]);失败静默——回写绝不挡执行。"""
4153
+ try:
4154
+ from pathlib import Path as _P
4155
+ import re as _re
4156
+ mark = _PLAN_MARK.get(str(status))
4157
+ idx = int(index)
4158
+ if not mark or idx < 1 or not workdir:
4159
+ return False
4160
+ root = _P(workdir).resolve()
4161
+ target = (root / ".codebee" / "task_plan.md").resolve()
4162
+ if root not in target.parents or not target.is_file():
4163
+ return False
4164
+ pat = _re.compile(r"^(\d+)\. \[[ x!>]\] ")
4165
+ lines = target.read_text("utf-8").splitlines()
4166
+ for k, ln in enumerate(lines):
4167
+ m = pat.match(ln)
4168
+ if m and int(m.group(1)) == idx:
4169
+ lines[k] = "%d. [%s] %s" % (idx, mark, ln[m.end():])
4170
+ target.write_text("\n".join(lines) + "\n", encoding="utf-8")
4171
+ return True
4172
+ return False
4173
+ except Exception:
4174
+ return False
4175
+
4176
+
4117
4177
  def _workdir_blocker(task, run_id):
4118
4178
  """同工作目录互斥:返回占用该目录的运行中/排队任务(无则 None)。
4119
4179
  任务计划/项目记忆/任务分支检出都是工作目录级共享状态,并行会互相覆盖