codebee 0.1.82 → 0.1.84

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,6 +6,16 @@ README 元数据带回,供老版本在「发现新版本」时展示新版更
6
6
 
7
7
  ## 未发布
8
8
 
9
+ ## v0.1.84(2026-10-05)
10
+
11
+ - **代码评审新增「越范围变更提醒」**:计划锚定了涉及文件的任务,实现轮若动了清单之外的文件,评审员会被点名提醒核对(连带改动属正常、凭空多改要点出)——无人值守任务更难悄悄跑偏。纯提示词指引,不改变通过判定;旧计划/手动任务未锚定文件时不生效。
12
+
13
+ ## v0.1.83(2026-10-05)
14
+
15
+ - **用量统计模型名不再分裂**:同一模型不同大小写(如 GLM-5.3-Flash 与 glm-5.3-flash)在台账倒序读入时 2:2 平局会随机拆成两行——平局裁断补第三序(大写字母数),统计视图稳定归一。
16
+ - **测试面存量红清账六件**(-13F -2E):建书对账收紧与「done 只计确认发布」改版后断言已跟上;发布门禁测试与 e2e 口径对齐;两件旧布局/脚本式测试件改造成 discover 兼容。全量 2143 项对账零新增红。
17
+
18
+
9
19
  ## v0.1.82(2026-10-04)
10
20
 
11
21
  - **连载「多线剧情推演」开放到界面**:任务表单与流程编辑器都能设 1-3 路分支——起草前先让智能体推演几条剧情走向、择优再动笔(比同章多稿赛马省一个数量级 token)。此前该能力只能手拼 API,而且流程里配好的推演数会被任务创建/保存流程静默冲掉。
package/README.md CHANGED
@@ -33,11 +33,9 @@ Trae Agent、OpenClaw……),提供
33
33
  ---
34
34
 
35
35
  <!-- relnotes:start -->
36
- ### 最新版更新内容(v0.1.82)
36
+ ### 最新版更新内容(v0.1.84)
37
37
 
38
- - 连载「多线剧情推演」开放到界面:任务表单/流程编辑器可设 1-3 路分支,写前推演择优再动笔;流程里配好的推演数/赛马数不再被静默冲掉
39
- - 赛马复赛不再白烧:容量受限通道首轮全挂后,复赛按身份收缩提示词(大纲/前情永不动),首轮仍发全量
40
- - 降级发生可对账:重试/复赛触发降级时,步骤说明写明降了哪几层
38
+ - 代码评审新增「越范围变更提醒」:实现轮动了计划锚定文件之外的文件时,评审员会被点名核对——无人值守任务更难悄悄跑偏
41
39
  <!-- relnotes:end -->
42
40
 
43
41
 
@@ -1029,13 +1029,64 @@ def _review_depth_note(diff):
1029
1029
  return ""
1030
1030
 
1031
1031
 
1032
- def _run_review(run_id, task, workdir, reviewer, ev):
1032
+ def _norm_rel(path):
1033
+ """归一成仓库相对 posix 路径:反斜杠转正斜杠、剥 ./ 前缀。"""
1034
+ s = str(path or "").replace("\\", "/").strip()
1035
+ return s[2:] if s.startswith("./") else s
1036
+
1037
+
1038
+ def _plan_scope_files(subtasks):
1039
+ """计划全步骤涉及文件并集(保持出现顺序去重)。计划未锚定 files(旧计划/
1040
+ 手动/快路径)返回空列表——越范围检测无从对照即静默跳过。"""
1041
+ out = []
1042
+ for sub in subtasks or []:
1043
+ for f in (sub or {}).get("files") or []:
1044
+ key = str(f)
1045
+ if key and key not in out:
1046
+ out.append(key)
1047
+ return out
1048
+
1049
+
1050
+ def _scope_note(scope_files, changed_files):
1051
+ """越范围编辑提醒(agent-delegate 借鉴):计划锚定了涉及文件,而实际变更
1052
+ 超出声明清单时,点名请评审员核对是否计划外改动。文件型/目录型声明(以 /
1053
+ 结尾)都按「相等或位于其下」匹配;清单外文件只在提醒里点名,不改 pass
1054
+ 判定语义;计划未锚定文件(changed_files=None)不猜范围不提醒。"""
1055
+ declared = []
1056
+ for f in scope_files or []:
1057
+ s = _norm_rel(f)
1058
+ if s and s not in declared:
1059
+ declared.append(s)
1060
+ if not declared or changed_files is None:
1061
+ return ""
1062
+ outside = []
1063
+ for p in changed_files or []:
1064
+ s = _norm_rel(p)
1065
+ if not s or s in outside:
1066
+ continue
1067
+ if not any(s == d or s.startswith(d if d.endswith("/") else d + "/")
1068
+ for d in declared):
1069
+ outside.append(s)
1070
+ if not outside:
1071
+ return ""
1072
+ return ("\n\n## 越范围变更提醒\n计划声明的涉及文件:%s。本次变更还动了清单之外的:%s"
1073
+ "——请核对这些改动是否任务必需(公共依赖连带属正常,凭空多改要点出);"
1074
+ "若属计划锚定疏漏请如实说明,不要仅因此给 blocker。"
1075
+ % ("、".join("`%s`" % d for d in declared[:10]),
1076
+ "、".join("`%s`" % p for p in outside[:8])))
1077
+
1078
+
1079
+ def _run_review(run_id, task, workdir, reviewer, ev, scope_files=None):
1033
1080
  diff = _git_diff(workdir)
1034
1081
  prompt = (CODE_REVIEW_PROMPT
1035
1082
  .replace("__GOAL__", task["goal"])
1036
1083
  .replace("__VERIFY__", task.get("verify_command") or "(未配置)")
1037
1084
  .replace("__DIFF__", diff or "(无法获取 git diff,请综合任务目标谨慎评审)"))
1038
1085
  prompt += _review_depth_note(diff)
1086
+ if scope_files:
1087
+ from . import gitmod
1088
+ changed = [f.get("path") for f in (gitmod.collect_changes(workdir).get("files") or [])]
1089
+ prompt += _scope_note(scope_files, changed)
1039
1090
  if task.get("context"):
1040
1091
  prompt += "\n\n## 原始背景与附件要求\n" + task["context"]
1041
1092
  res = _run_step(run_id, "review", reviewer, prompt, workdir, readonly=True, ev=ev,
@@ -1654,7 +1705,8 @@ def _run_code(run, task, agents, ev, stats, mode):
1654
1705
  else:
1655
1706
  verify_fail_streak[0] = 0
1656
1707
  # 先让确定性验证落盘,再执行模型评审;终态判断会同时使用两份证据。
1657
- review_json = _run_review(run_id, task, workdir, modelhub.bind_agent(reviewer, difficulty), ev)
1708
+ review_json = _run_review(run_id, task, workdir, modelhub.bind_agent(reviewer, difficulty), ev,
1709
+ scope_files=_plan_scope_files(subtasks))
1658
1710
  return review_json, verify_pass, verify_ran
1659
1711
 
1660
1712
  verify_fail_streak = [0] # gate:verify 连败计数(>=2 轮恢复评审参与诊断)
@@ -4194,6 +4246,24 @@ def _run_serial_review(run, task, agents, ev, stats, mode, critics, impl, route,
4194
4246
  results[idx] = gj
4195
4247
  return
4196
4248
  gtpl = SERIAL_GLOBAL_PROMPT
4249
+ if start > 1:
4250
+ # 批次评审口径:连载中段批次不能拿全书开篇与高潮段的标准审
4251
+ # (实案:黄金三章口径被用来扣批首章开篇分、承段被按高潮段
4252
+ # 密度打节奏 5.0、伏笔揭示位在后批章纲的被判悬置)。口径只
4253
+ # 纠正评审对象的范围与基准,重复/人设/文风类问题照常计。
4254
+ gtpl = gtpl.replace(
4255
+ "## 全书目标",
4256
+ "## 批次评审口径(系统注入)\n"
4257
+ "- 本次送审批次为全书第 %d—%d 章(连载中段批次),文本中的前文节选仅供衔接核对;\n"
4258
+ "- 「黄金一章/黄金三章」口径仅适用于全书第 1—3 章,不得据此扣减本批批首章的开篇分;\n"
4259
+ "- 本批各章的既定事件以工作目录「章纲/」下的锁定章纲为准(可自行查阅):承段、"
4260
+ "过渡章的节奏分应对照章纲既定事件是否落实与章末钩子是否成立,"
4261
+ "不以高潮段的事件密度为统一标准;\n"
4262
+ "- 「伏笔悬置」类 major 须先核对章纲的揭示位安排:揭示位写在后批章纲中的伏笔"
4263
+ "不算悬置,无任何安排的悬置才成立;\n"
4264
+ "- 重复叙述、人设崩坏、文风漂移、真实前后矛盾照常计 major——本口径只纠正评审"
4265
+ "对象的范围与基准,不是放水。\n\n"
4266
+ "## 全书目标" % (start, end), 1)
4197
4267
  if bible:
4198
4268
  gtpl = gtpl.replace("## 全书目标", bible + "\n\n## 全书目标", 1)
4199
4269
  res = _run_step(run_id, "global-critique", bound[idx],
@@ -5276,9 +5346,12 @@ def mark_task_plan(workdir, index, status):
5276
5346
 
5277
5347
 
5278
5348
  def _workdir_blocker(task, run_id):
5279
- """同工作目录互斥:返回占用该目录的运行中/排队任务(无则 None)。
5349
+ """同工作目录互斥:返回占用该目录的任务(无则 None)。
5280
5350
  任务计划/项目记忆/任务分支检出都是工作目录级共享状态,并行会互相覆盖
5281
- (2026-09-23 禅道双单实案),故同目录只允许一个任务在跑。"""
5351
+ (2026-09-23 禅道双单实案),故同目录只允许一个任务在跑。占用者只认
5352
+ **真正在跑**(running)的 run:2026-10-05 实案——三个同目录任务全部
5353
+ queued 时,排队中的兄弟互相被当成占用者,各自退避 60s 形成活锁,
5354
+ 谁也起不来;排队者是「同样在等」而不是「占着」。"""
5282
5355
  wd = (task.get("workdir") or "").rstrip("/\\")
5283
5356
  if not wd:
5284
5357
  return None
@@ -5287,7 +5360,8 @@ def _workdir_blocker(task, run_id):
5287
5360
  or t.get("status") not in ("running", "queued")
5288
5361
  or (t.get("workdir") or "").rstrip("/\\") != wd):
5289
5362
  continue
5290
- if jobs._task_active_run(t.get("id"), exclude_run_id=run_id):
5363
+ blk = jobs._task_active_run(t.get("id"), exclude_run_id=run_id)
5364
+ if blk is not None and blk.get("status") == "running":
5291
5365
  return t
5292
5366
  return None
5293
5367
 
package/app/core/usage.py CHANGED
@@ -679,7 +679,8 @@ def _group(records, key):
679
679
  def _model_display_map(records):
680
680
  """模型名归一映射 {casefold: 展示名}:同一模型不同大小写(GLM-5.3-Flash 与
681
681
  glm-5.3-flash)会被拆成两行统计,这里把 casefold 相同的归为一组,
682
- 展示名取组内出现次数最多的原始写法(平局取更长写法,信息更全)。"""
682
+ 展示名取组内出现次数最多的原始写法(平局取更长写法,再平局取大写字母
683
+ 更多的规范形——台账倒序读入时 2:2 平局的裁断不再随记录顺序漂移)。"""
683
684
  canon = {}
684
685
  for r in records:
685
686
  name = str(r.get("model") or "") or "unknown"
@@ -690,7 +691,8 @@ def _model_display_map(records):
690
691
  display = {}
691
692
  for k, c in canon.items():
692
693
  display[k] = max(c["names"].items(),
693
- key=lambda kv: (kv[1], len(kv[0])))[0]
694
+ key=lambda kv: (kv[1], len(kv[0]),
695
+ sum(ch.isupper() for ch in kv[0])))[0]
694
696
  return display
695
697
 
696
698
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codebee",
3
- "version": "0.1.82",
3
+ "version": "0.1.84",
4
4
  "description": "CodeBee · 多智能体编排台 — 统一编排本机 AI 编码 CLI(Codex / Claude Code / QwenCode / OpenCode / Aider…):目标→拆解→路由→执行→验证→跨厂商评审→修复→报告。纯 Python 标准库实现,本地 Web UI。",
5
5
  "license": "MIT",
6
6
  "bin": {