codebee 0.1.88 → 0.1.90

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.90(2026-10-07)
10
+
11
+ - **英文界面 54 处文案补全**:首次建立 app.js 全量 `t()` 字面量↔词条对账(1,726 唯一键实测),补齐 54 键缺失词条——英文界面 toast/状态/弹窗标题/表单标签不再中文裸奔(加载失败/插件安装/重试任务等)。
12
+ - **对账测试契约锁定**:新增全量对账测试(解析面自守防漂移)+54 键点名锁定(防部分回退),日后加文案漏词条先红。
13
+
14
+ ## v0.1.89(2026-10-07)
15
+
16
+ - **连载起草「相关历史章节推荐」**:起草前情注入新增历史章回看指针——用连载追踪里逐章持久化的伏笔/人物/事实记录,与本章大纲要点做纯本地重叠计分(零模型调用、零额外存储),按命中行数推荐最相关的至多 3 个历史章摘录供起草时回看;近 2 章窗口外的伏笔回收、人物回场不再只靠账本督促兜底;零匹配零输出(老书无感)。
17
+ - **经验库存量去重**:新增教训并类管理通道(历史标题与正文留痕、召回证据并入主条不缩水),存量近重复教训 8→3 条并类、1 条归位分类,经验库 73→68 条——重复教训不再稀释召回排序。
18
+
9
19
  ## v0.1.88(2026-10-06)
10
20
 
11
21
  - **封面生成前提示词预览确认**:「生成封面」先只读展示将使用的图像提示词(新增 GET /api/tasks/{id}/cover/prompt,不触发任何模型/图像调用),确认后才走付费生成链——防误触花钱、封面元素所见即所得;取消零请求。
package/README.md CHANGED
@@ -33,10 +33,10 @@ Trae Agent、OpenClaw……),提供
33
33
  ---
34
34
 
35
35
  <!-- relnotes:start -->
36
- ### 最新版更新内容(v0.1.88)
36
+ ### 最新版更新内容(v0.1.90)
37
37
 
38
- - 封面生成前提示词预览确认:点「生成封面」先只读展示图像提示词,确认后才调用图像接口——防误触付费、所见即所得
39
- - 调研沉淀与封面预览 12 项回归测试入库
38
+ - 英文界面 54 处文案补全:全量 t() 字面量对账首次建立,英文界面不再中文裸奔
39
+ - 新增对账测试契约锁定:加文案漏词条先红
40
40
  <!-- relnotes:end -->
41
41
 
42
42
 
@@ -2587,6 +2587,55 @@ def _serial_shrunk_block(lessons, bible, kb_block, budget=12000):
2587
2587
  return "\n\n".join(p for p in (sk2, bible2, kb_block) if p), note
2588
2588
 
2589
2589
 
2590
+ _RELATED_ROW_CHARS = 80 # 单行摘录截断(记录行本体可达 1000 字,注入面只留指针)
2591
+ _RELATED_ROWS_PER_CH = 3 # 每章最多摘录的行数
2592
+ _RELATED_MIN_GRAMS = 2 # 单行命中门槛:bigram 重叠数(1 个重叠噪音过高)
2593
+
2594
+
2595
+ def _related_chapters_note(tracking_state, ch, current=0, max_n=3):
2596
+ """连载起草的「相关历史章节推荐」(纯本地重叠计分,零 LLM 调用零存储写入)。
2597
+
2598
+ 前情注入只看近 2 章结尾+findings 摘要,中期记忆(伏笔回收/人物回场)此前
2599
+ 只有账本督促兜底;story_tracking 已逐章持久化 facts/characters/foreshadowing,
2600
+ 这里拿本章大纲要点(beats/hook/highlight)与各历史章记录行做字符 bigram
2601
+ 重叠计分(复用 skills._text_bigrams,口径与经验库召回一致),按命中行数挑
2602
+ 最相关的 max_n 章输出「第 N 章:相关行摘录」指针。零匹配/无状态返回空串
2603
+ (老书零噪音);current 传当前全书章号时只看更早的章(重跑已提交章不跟
2604
+ 自己的记录自证)。"""
2605
+ ch = ch or {}
2606
+ probe = skills._text_bigrams(" ".join(
2607
+ str(ch.get(k) or "") for k in ("beats", "hook", "highlight")))
2608
+ if not probe:
2609
+ return ""
2610
+ scored = []
2611
+ for rec in (tracking_state or {}).get("chapters") or []:
2612
+ try:
2613
+ no = int(rec.get("chapter") or 0)
2614
+ except (TypeError, ValueError):
2615
+ continue
2616
+ if no < 1 or (current and no >= current):
2617
+ continue
2618
+ rows = [str((x or {}).get("text") or "") for x in rec.get("foreshadowing") or []]
2619
+ rows += [str(x) for x in rec.get("characters") or []]
2620
+ rows += [str(x) for x in rec.get("facts") or []]
2621
+ hits = []
2622
+ for row in rows:
2623
+ row = row.strip()
2624
+ if row and len(probe & skills._text_bigrams(row)) >= _RELATED_MIN_GRAMS:
2625
+ hits.append(row[:_RELATED_ROW_CHARS]
2626
+ + ("…" if len(row) > _RELATED_ROW_CHARS else ""))
2627
+ if hits:
2628
+ scored.append((len(hits), no, hits))
2629
+ scored.sort(key=lambda x: (-x[0], x[1]))
2630
+ take = scored[:max(0, int(max_n or 0))]
2631
+ if not take:
2632
+ return ""
2633
+ lines = ["### 相关历史章节(按本章大纲要点重叠检出,起草前可回看)"]
2634
+ for _, no, hits in take:
2635
+ lines.append("- 第 %d 章:%s" % (no, ";".join(hits[:_RELATED_ROWS_PER_CH])))
2636
+ return "\n".join(lines)
2637
+
2638
+
2590
2639
  def _critic_lens(critics, agent):
2591
2640
  """该评审的专属视角;单评审/手动指定时不播种(无从轮换,也别稀释注意力)。"""
2592
2641
  try:
@@ -3411,6 +3460,16 @@ def _run_serial_review(run, task, agents, ev, stats, mode, critics, impl, route,
3411
3460
  prev += "\n\n## 此前章节发现摘要\n" + fd_txt[:3000]
3412
3461
  except Exception:
3413
3462
  pass
3463
+ # 相关历史章节推荐(story_tracking 逐章 facts/characters/foreshadowing
3464
+ # 与本章大纲要点的纯本地重叠计分):近 2 章窗口外的伏笔回收/人物回场
3465
+ # 给显式指针,经 prev 注入路径自然随降级块走(不新增预算口子);
3466
+ # 零匹配零输出(老书零噪音),失败静默。
3467
+ try:
3468
+ rel = _related_chapters_note(tracking_state, ch, current=i)
3469
+ if rel:
3470
+ prev += "\n\n" + rel
3471
+ except Exception:
3472
+ pass
3414
3473
 
3415
3474
  # 评审-修订(每章至多 1 轮修订)
3416
3475
  rounds_used = 1
@@ -513,6 +513,63 @@ def lesson_op(lesson_id, op):
513
513
  return None
514
514
 
515
515
 
516
+ def merge_lessons(primary_id, duplicate_ids):
517
+ """把近重复教训并为主条(存量聚簇的管理通道;upsert_lesson 合并路径的管理版)。
518
+
519
+ 自动去重只拦沉淀时的近似题(bigram 包含度 ≥0.8),语义近但措辞散的存量
520
+ 聚簇没有并类通道。语义=upsert 合并语义的延伸:被并条标题进主条
521
+ merged_titles(去重封顶 8,溯源+变体检索可见)、正文进 revisions 留痕
522
+ (封顶 5,带 merged_from 指明来源条),注入/结局证据计数(hits/lost/
523
+ useless/won/seen)并入主条——召回排序的 karma 证据不因合并缩水;正文与
524
+ 分类以主条为准(不批量重写内容)。返回错误说明或 None。
525
+ """
526
+ dup_ids = []
527
+ for x in (duplicate_ids or []):
528
+ did = str(x or "").strip()
529
+ if did and did not in dup_ids:
530
+ dup_ids.append(did)
531
+ if not dup_ids:
532
+ return "缺少被并条目"
533
+ with _LOCK:
534
+ data = _load()
535
+ items = data.get("lessons") or []
536
+ by_id = {}
537
+ for x in items:
538
+ by_id[x.get("id")] = x
539
+ primary = by_id.get(primary_id)
540
+ if not primary:
541
+ return "主条不存在"
542
+ if primary_id in dup_ids:
543
+ return "主条不能同时是被并条目"
544
+ dups = []
545
+ for did in dup_ids:
546
+ d = by_id.get(did)
547
+ if not d:
548
+ return "被并条目不存在 " + did
549
+ dups.append(d)
550
+ revs = primary.setdefault("revisions", [])
551
+ titles = primary.setdefault("merged_titles", [])
552
+ primary_title = str(primary.get("title") or "")
553
+ for d in dups:
554
+ content = str(d.get("content") or "")
555
+ if content:
556
+ revs.append(revisions.revision_record(
557
+ "skrev", content, source=d.get("source") or "",
558
+ extra={"content": content, "merged_from": d.get("id")}))
559
+ title = str(d.get("title") or "")
560
+ if title and title != primary_title and title not in titles:
561
+ titles.append(title)
562
+ for k in ("hits", "lost", "useless", "won", "seen"):
563
+ primary[k] = int(primary.get(k) or 0) + int(d.get(k) or 0)
564
+ primary["revisions"] = revs[-5:]
565
+ primary["merged_titles"] = titles[-8:]
566
+ primary["updated_at"] = _now()
567
+ drop = {d.get("id") for d in dups}
568
+ data["lessons"] = [x for x in items if x.get("id") not in drop]
569
+ _save(data)
570
+ return None
571
+
572
+
516
573
  def pack_op(pack_id, op):
517
574
  """启用/停用包(内置与用户自建均可停用;用户包不可通过此接口删除,删文件即可)。"""
518
575
  if op not in ("enable", "disable"):
package/app/ui/i18n.js CHANGED
@@ -2991,6 +2991,64 @@
2991
2991
  "导出报告(Markdown)": "Export report (Markdown)",
2992
2992
  "选择一个任务开始工作": "Pick a task to start working",
2993
2993
  "重新运行": "Re-run",
2994
+ // —— EN 词条收尾补全(2026-10-07 巡检 G 专项·JS 侧 t() 字面量对账首次建立:
2995
+ // app.js 全部 t("字面量") 键中 54 键缺词条(英文界面 toast/状态/弹窗中文
2996
+ // 裸奔);本批补齐并由 tests/test_borrow_iteration.py 全量锁定,日后加文案
2997
+ // 漏词条先红。拼接片段照实收词条("共 "/" · 吞吐 " 同例)——
2998
+ "请先选择任务": "Pick a task first",
2999
+ "正在读取任务详情…": "Loading task details…",
3000
+ "读取任务详情失败:": "Failed to load task details: ",
3001
+ "未命名": "Untitled",
3002
+ "↻ 重试任务": "↻ Retry task",
3003
+ "↻ 从超时进度继续": "↻ Resume from timeout",
3004
+ "从最近一次已保存的大纲和已完成章节断点续跑": "Resume from the last saved outline and finished chapters",
3005
+ "暂无运行步骤": "No run steps yet",
3006
+ "加载失败": "Load failed",
3007
+ "正在加载…": "Loading…",
3008
+ "正在读取报告…": "Loading report…",
3009
+ "报告读取失败({0}),稍后可重试": "Failed to read report ({0}) — retry later",
3010
+ "点击“成果”页签后加载报告和成品文件": "Open the \"Results\" tab to load the report and output files",
3011
+ "本次运行排队中:实时进度看「步骤」页签": "This run is queued — watch the \"Steps\" tab for live progress",
3012
+ "我已在平台提交": "I've submitted on the platform",
3013
+ "建书未确认:": "Book not confirmed: ",
3014
+ "填稿已完成,请先在浏览器里提交,再点击确认": "Draft fill finished — submit in the browser first, then click confirm",
3015
+ "已确认提交,台账已更新": "Submission confirmed — ledger updated",
3016
+ "确认提交失败:": "Failed to confirm submission: ",
3017
+ "将从最靠前的待发章节开始填稿(共 {0} 章待发)。本轮只填一章并停在表单页,由你在浏览器里确认提交;提交后点击“我已在平台提交”,再选择下一章。护栏(每日上限/连续失败暂停)生效。继续?": "About to fill from the earliest pending chapter ({0} pending). This round fills one chapter and stops at the form page — confirm the submission in your browser, click \"I've submitted on the platform\", then pick the next chapter. Guardrails (daily cap / consecutive-failure pause) apply. Continue?",
3018
+ "正在填第一章稿——填好后请在浏览器窗口里确认提交,再重新校准": "Filling chapter 1 — once done, confirm the submission in the browser window, then recalibrate",
3019
+ "Blocked:": "Blocked: ",
3020
+ "契约已更新": "Contract updated",
3021
+ "🕘 流程版本历史:": "🕘 Flow version history: ",
3022
+ "内容指纹(重装突变对账用)": "Content fingerprint (reinstall mutation reconciliation)",
3023
+ "指纹 ": "Fingerprint ",
3024
+ "自述:": "Self-description: ",
3025
+ "技能 ": "Skills ",
3026
+ "插件加载失败": "Failed to load plugins",
3027
+ "还没有发现本地插件": "No local plugins found yet",
3028
+ "插件安装成功": "Plugin installed",
3029
+ "安装失败": "Install failed",
3030
+ "插件已启用": "Plugin enabled",
3031
+ "插件已停用": "Plugin disabled",
3032
+ "卸载该插件?技能包和本地插件副本会被移除。": "Uninstall this plugin? The skill pack and the local plugin copy will be removed.",
3033
+ "插件已卸载": "Plugin uninstalled",
3034
+ "卸载失败": "Uninstall failed",
3035
+ "(行 ": "(line ",
3036
+ " 个文件 · ": " files · ",
3037
+ "评审维度(2-6 个,逗号分隔)": "Review dimensions (2-6, comma-separated)",
3038
+ "例:正确性,可读性": "e.g. correctness, readability",
3039
+ "题目要求(一句话,给裁判看)": "Requirement (one line, shown to the judge)",
3040
+ "题目内容 ": "Problem content ",
3041
+ "(发给候选模型的完整题面,≤2000 字)": "(full problem text sent to the candidate model, ≤2000 chars)",
3042
+ "样题已添加": "Sample added",
3043
+ "删除这道自定义样题?历史评测结果保留。": "Delete this custom sample? Past eval results are kept.",
3044
+ "把这段样题分享码发给任何人,对方在「添加样题 → 导入」粘贴即可:": "Send this sample share code to anyone — they paste it under \"Add sample → Import\": ",
3045
+ "📤 导出样题": "📤 Export sample",
3046
+ "粘贴样题分享码(CBSAMP1. 开头),ID 冲突自动换号。": "Paste the sample share code (starts with CBSAMP1.); conflicting IDs are renumbered automatically.",
3047
+ "📥 导入样题分享码": "📥 Import sample share code",
3048
+ "已导入样题「": "Imported sample \"",
3049
+ "P95 ": "P95 ",
3050
+ "复制失败,请手动长按/右键复制": "Copy failed — long-press / right-click to copy manually",
3051
+ "✓ 远程端点连通,可上传": "✓ Remote endpoint reachable, ready to upload",
2994
3052
  };
2995
3053
 
2996
3054
  // ---------- 工具 ----------
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codebee",
3
- "version": "0.1.88",
3
+ "version": "0.1.90",
4
4
  "description": "CodeBee · 多智能体编排台 — 统一编排本机 AI 编码 CLI(Codex / Claude Code / QwenCode / OpenCode / Aider…):目标→拆解→路由→执行→验证→跨厂商评审→修复→报告。纯 Python 标准库实现,本地 Web UI。",
5
5
  "license": "MIT",
6
6
  "bin": {