codebee 0.1.8 → 0.1.10

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
@@ -4,6 +4,22 @@ CodeBee 的用户可感知变更记录。发布新版时:最上面加一节,
4
4
  `<!-- relnotes:start -->…<!-- relnotes:end -->` 段(那段会被 `npm view` 的
5
5
  README 元数据带回,供老版本在「发现新版本」时展示新版更新内容)。
6
6
 
7
+ ## v0.1.10(2026-09-18)
8
+
9
+ - Git 工作台「建 PR」支持自定义标题:提交信息框有内容时自动兼作 PR 标题(一处输入两用)
10
+ - Best-of-N 败者精华并入修订:终审从落选候选稿提炼的优点随评审意见一并喂给作者
11
+ - 报告与对话的围栏代码块统一渲染;竞品调研知识库(docs/borrow-log/knowledge.md)建立并沉淀 40+ 项目
12
+
13
+ ## v0.1.9(2026-09-18)
14
+
15
+ - 类型菜单项显示成本预估:每个任务类型一行「≈N tokens · N 次」(近 90 天同类台账中位数,无样本自动隐藏)
16
+ - 详情页步骤卡新增「实际派发模型」徽章:换将/链回退时一眼看清每步实际打了哪个模型
17
+ - 直连对话新增「建议追问」芯片:助手回答尾部最多 3 条可点建议,点击回填输入框(借鉴 freebuff)
18
+ - 新建任务支持 Best-of-N 候选并发(评审类单稿任务):多路不同写法策略并行起草,终审择优并吸收落选稿优点
19
+ - 换将超窗预检:切到小上下文模型前先按其容量预压缩,避免第一个请求被拒
20
+ - 外部触发 Webhook:POST /api/hooks/run(X-CodeBee-Token 令牌鉴权,未配置仅限本机)
21
+ - Git 工作台新增「建 PR」:推送当前分支并调 gh 创建 PR(base 自动识别 main/master)
22
+
7
23
  ## v0.1.8(2026-09-18)
8
24
 
9
25
  - README 全面重写:功能导览 + 9 张实机截图,补齐蜂巢/经验库/插件市场/自动化/对话模式等章节
package/app/ui/app.js CHANGED
@@ -53,19 +53,49 @@ function renderTypeOptions() {
53
53
  function renderTypeMenu() {
54
54
  const menu = $("type-menu");
55
55
  if (!menu || !S.flows) return;
56
- menu.innerHTML = (S.flows || []).map((f) =>
57
- '<button type="button" class="type-item" role="option" data-v="' + esc(f.id) + '" onclick="pickType(\'' + esc(f.id) + '\')">' +
56
+ menu.innerHTML = (S.flows || []).map((f) => {
57
+ const est = S.flowEstimates && S.flowEstimates[f.id];
58
+ return '<button type="button" class="type-item" role="option" data-v="' + esc(f.id) + '" onclick="pickType(\'' + esc(f.id) + '\')">' +
58
59
  '<span class="ti-ico" aria-hidden="true">' + flowIconHtml(f) + "</span>" +
59
60
  '<span class="ti-body"><span class="ti-name">' + esc(t(f.name)) +
60
61
  (f.builtin ? "" : '<em class="ti-tag">' + t("自定义") + "</em>") + "</span>" +
61
- '<span class="ti-desc">' + esc(flowDesc(f)) + "</span></span>" +
62
+ '<span class="ti-desc">' + esc(flowDesc(f)) + "</span>" +
63
+ (est ? '<span class="ti-est">' + esc(t("≈{0} tokens · {1}次", fmtTok(est.median_tokens), est.samples)) + "</span>" : "") +
64
+ "</span>" +
62
65
  '<svg class="ico ti-check" aria-hidden="true"><use href="#i-check"></use></svg>' +
63
- "</button>").join("")
66
+ "</button>";
67
+ }).join("")
64
68
  /* 底部固定入口:管理流程替代原工具条上的「管理」按钮(简化 composer 工具行) */
65
69
  + '<div class="type-menu-foot"><button type="button" class="type-item" onclick="manageFlowsFromMenu()">' +
66
70
  '<span class="ti-ico" aria-hidden="true"><svg class="ico"><use href="#i-gear"></use></svg></span>' +
67
71
  '<span class="ti-body"><span class="ti-name">' + esc(t("管理任务类型…")) + "</span></span></button></div>";
68
72
  syncTypeBtn();
73
+ fetchFlowEstimates(); // 异步回填预估行(就地更新,不重建菜单)
74
+ }
75
+
76
+ /* 类型菜单的成本/次数预估(借鉴 omnigent,数据源 /api/usage/estimate):
77
+ * 拉到手后就地更新菜单项——菜单开着也不重建 DOM,不打断滚动/悬停 */
78
+ async function fetchFlowEstimates() {
79
+ if (!S.flows) return;
80
+ const targets = S.flows.slice(0, 10);
81
+ const results = await Promise.all(targets.map(async (f) => {
82
+ try {
83
+ const d = await api("/api/usage/estimate?type=" + encodeURIComponent(f.id) + "&days=90");
84
+ return [f.id, (d && d.samples > 0) ? d : null];
85
+ } catch (e) { return [f.id, null]; }
86
+ }));
87
+ S.flowEstimates = Object.fromEntries(results.filter(([, d]) => d));
88
+ const menu = $("type-menu");
89
+ if (!menu) return;
90
+ menu.querySelectorAll(".type-item[data-v]").forEach((b) => {
91
+ const d = S.flowEstimates[b.dataset.v];
92
+ const body = b.querySelector(".ti-body");
93
+ if (!d || !body || body.querySelector(".ti-est")) return;
94
+ const est = document.createElement("span");
95
+ est.className = "ti-est";
96
+ est.textContent = t("≈{0} tokens · {1}次", fmtTok(d.median_tokens), d.samples);
97
+ body.appendChild(est);
98
+ });
69
99
  }
70
100
  window.manageFlowsFromMenu = function () {
71
101
  toggleTypeMenu(false);
@@ -3488,6 +3518,7 @@ async function renderRunDetail() {
3488
3518
  '<span class="n">' + String(s.n).padStart(2, "0") + "</span>" +
3489
3519
  '<span class="role">' + esc(s.role) + "</span>" +
3490
3520
  '<span class="who">' + esc(t(s.agent_label || s.agent)) + "</span>" +
3521
+ (s.model ? '<span class="st-model" title="' + esc(t("实际派发模型")) + '">' + esc(s.model) + "</span>" : "") +
3491
3522
  '<span class="sum">' + esc((s.note ? "◆ " + s.note + " — " : "") + (s.summary || "")) + "</span>" +
3492
3523
  '<span class="dur">' + (s.duration_s != null ? s.duration_s + "s" : "") + "</span>" +
3493
3524
  statusChip(s.status) +
@@ -4068,8 +4099,13 @@ window.gitWbFetch = function () { return _gitWbPost("fetch", null, t("已抓取
4068
4099
  window.gitWbPull = function () { return _gitWbPost("pull", null, t("已拉取远程更新")); };
4069
4100
  window.gitWbPush = function () { return _gitWbPost("push", null, t("已推送到远程")); };
4070
4101
  window.gitWbPrCreate = async function () {
4071
- if (!await uiConfirm(t("把当前分支推送到远程并用 gh 创建 PR?(目标分支自动取 main/master)"), { ok: t("建 PR") })) return null;
4072
- const res = await _gitWbPost("pr_create", null,
4102
+ // 提交信息框有字时兼作 PR 标题(一处输入两用,不为 PR 单开输入框)
4103
+ const mt = ((($("gwb-msg") || {}).value || "").trim());
4104
+ const q = mt
4105
+ ? t("把当前分支推送到远程并用 gh 创建 PR?(目标分支自动取 main/master;提交信息框内容将作为 PR 标题)")
4106
+ : t("把当前分支推送到远程并用 gh 创建 PR?(目标分支自动取 main/master)");
4107
+ if (!await uiConfirm(q, { ok: t("建 PR") })) return null;
4108
+ const res = await _gitWbPost("pr_create", mt ? { title: mt.slice(0, 120) } : null,
4073
4109
  (r) => (r && r.url ? t("PR 已创建:") + r.url : t("PR 已创建")));
4074
4110
  if (res && res.url) window.open(res.url, "_blank", "noopener");
4075
4111
  return res;
package/app/ui/i18n.js CHANGED
@@ -681,6 +681,7 @@
681
681
  "建 PR": "Create PR",
682
682
  "推送当前分支并用 gh 创建 PR(目标分支自动取 main/master)": "Push current branch and create a PR with gh (base auto-detected: main/master)",
683
683
  "把当前分支推送到远程并用 gh 创建 PR?(目标分支自动取 main/master)": "Push current branch and create a PR with gh? (base auto-detected: main/master)",
684
+ "把当前分支推送到远程并用 gh 创建 PR?(目标分支自动取 main/master;提交信息框内容将作为 PR 标题)": "Push current branch and create a PR with gh? (base auto-detected: main/master; the commit message box will be used as the PR title)",
684
685
  "PR 已创建:": "PR created: ",
685
686
  "PR 已创建": "PR created",
686
687
  "背景信息、约束、相关文件(可空)": "Background, constraints, related files (optional)",
@@ -699,6 +700,8 @@
699
700
  "实现 → 验证 → 评审": "Implement → verify → review",
700
701
  "起草 → 多维评审 → 门禁": "Draft → multi-dim review → gate",
701
702
  "大纲 → 逐章起草评审 → 合并(可续跑)": "Outline → per-chapter draft & review → merge (resumable)",
703
+ "≈{0} tokens · {1}次": "≈{0} tokens · {1} runs",
704
+ "实际派发模型": "Dispatched model",
702
705
  "实现": "Implement",
703
706
  "起草": "Draft",
704
707
  "大纲": "Outline",
package/app/ui/style.css CHANGED
@@ -5038,3 +5038,14 @@ body.welcome-open { overflow: hidden; }
5038
5038
  .welcome-right { display: none; }
5039
5039
  .welcome-card { width: 100%; }
5040
5040
  }
5041
+
5042
+ /* 类型菜单项的成本/次数预估行(借鉴 omnigent pre-run estimate):小字弱化,
5043
+ * 挂在描述下方;无同类样本的类型不显示 */
5044
+ .ti-est { color: var(--muted); font-size: 10.5px; opacity: .85; }
5045
+
5046
+ /* 步骤卡「实际派发模型」小徽章(借鉴 gsd-pi routing provenance):换将/链回退时
5047
+ * 一眼看清这步到底打了哪个模型;老步骤无 model 字段不显示 */
5048
+ .step .st-model {
5049
+ font-size: 10.5px; color: var(--muted); opacity: .9;
5050
+ border: 1px solid var(--border); border-radius: 999px; padding: 0 7px; line-height: 16px;
5051
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codebee",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "CodeBee · 多智能体编排台 — 统一编排本机 AI 编码 CLI(Codex / Claude Code / QwenCode / OpenCode / Aider…):目标→拆解→路由→执行→验证→跨厂商评审→修复→报告。纯 Python 标准库实现,本地 Web UI。",
5
5
  "license": "MIT",
6
6
  "bin": {