codebee 0.1.23 → 0.1.25

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/app/pet.py CHANGED
@@ -1283,7 +1283,8 @@ class PetApp:
1283
1283
  command=lambda: self._set_lang("en"),
1284
1284
  variable=self._lang_var, value="en")
1285
1285
  m.add_separator()
1286
- m.add_command(label=self._L("close"), command=self._bye)
1286
+ m.add_command(label=self._L("close"),
1287
+ command=lambda: self._bye(write_setting=True))
1287
1288
  return m
1288
1289
 
1289
1290
  def _set_mode(self, mode):
@@ -1308,6 +1309,8 @@ class PetApp:
1308
1309
  cv = self.cv
1309
1310
  self._press = None
1310
1311
  self._moved = False
1312
+ self._drag_to = None
1313
+ self._drag_pending = False
1311
1314
  cv.bind("<ButtonPress-1>", self._on_press)
1312
1315
  cv.bind("<B1-Motion>", self._on_motion)
1313
1316
  cv.bind("<ButtonRelease-1>", self._on_release)
@@ -1316,22 +1319,32 @@ class PetApp:
1316
1319
  self.root.protocol("WM_DELETE_WINDOW", self._bye)
1317
1320
 
1318
1321
  def _on_press(self, e):
1319
- self._press = e
1322
+ # 窗口拖动起点:屏幕坐标 + 窗口原点一起记(scan_mark/scan_dragto 是
1323
+ # canvas 系 widget 的子命令,顶层窗口没有——此前绑定在这里的拖动
1324
+ # 实际全部抛 AttributeError 被 except 吞掉,表现为「拖不动」)
1325
+ self._press = (e.x_root, e.y_root, self.root.winfo_x(), self.root.winfo_y())
1320
1326
  self._moved = False
1321
- try:
1322
- self.root.scan_mark(e.x_root, e.y_root) # Tk 内置 C 级拖动,跟手
1323
- except Exception:
1324
- pass
1325
1327
 
1326
1328
  def _on_motion(self, e):
1327
1329
  if not self._press:
1328
1330
  return
1329
- if (abs(e.x - self._press.x) + abs(e.y - self._press.y) > 4):
1331
+ px, py, wx, wy = self._press
1332
+ if (abs(e.x_root - px) + abs(e.y_root - py) > 4):
1330
1333
  self._moved = True
1331
- # 逐事件 geometry() 会把透明层窗拖成PPT(每次回调都走 Python+重排);
1332
- # scan_dragto C 里完成同样的移动,丝滑
1334
+ # geometry 逐事件会卡成 PPT;这里合并到 ~60fps 节流(事件风暴只在
1335
+ # 节流窗内记终点,一次 geometry 落位),实测跟手且不吃 CPU
1336
+ self._drag_to = (wx + (e.x_root - px), wy + (e.y_root - py))
1337
+ if self._drag_pending:
1338
+ return
1339
+ self._drag_pending = True
1340
+ self.root.after(16, self._apply_drag)
1341
+
1342
+ def _apply_drag(self):
1343
+ self._drag_pending = False
1344
+ if not self._drag_to:
1345
+ return
1333
1346
  try:
1334
- self.root.scan_dragto(e.x_root, e.y_root, 1)
1347
+ self.root.geometry("+%d+%d" % self._drag_to)
1335
1348
  except Exception:
1336
1349
  pass
1337
1350
 
@@ -1344,7 +1357,17 @@ class PetApp:
1344
1357
  else:
1345
1358
  self._open_ui()
1346
1359
 
1347
- def _bye(self):
1360
+ def _bye(self, write_setting=False):
1361
+ """退出。write_setting=True(右键菜单「关闭桌宠」)先把 pet_enabled=False
1362
+ 写回服务端设置——否则看护/下次启动都会按设置里的 enabled 把蜜蜂复活,
1363
+ 用户点关闭等于没关(2026-09-21 用户实测「宠物关不了」的根因:菜单
1364
+ 关闭只销毁窗口不落设置,与注释宣称的契约相反)。服务端 pet_enabled
1365
+ 已为 False 的自离路径(轮询发现/miss 超限)无需再写。"""
1366
+ if write_setting:
1367
+ try:
1368
+ self._post_settings({"pet_enabled": False})
1369
+ except Exception:
1370
+ pass
1348
1371
  try:
1349
1372
  self._save_cfg(x=self.root.winfo_x(), y=self.root.winfo_y())
1350
1373
  except Exception:
package/app/ui/app.js CHANGED
@@ -2026,7 +2026,8 @@ async function createTask() {
2026
2026
  msg.textContent = t("目标有点简短,先问几个问题…");
2027
2027
  try {
2028
2028
  const cq = await api("/api/tasks/clarify", {
2029
- method: "POST", timeout: 75000,
2029
+ // 澄清只是增强,不能让建任务被模型调用拖住;超时后直接按原目标开跑。
2030
+ method: "POST", timeout: 8000,
2030
2031
  body: JSON.stringify({ goal: payload.goal, type: payload.type }) });
2031
2032
  const qs = (cq && cq.questions) || [];
2032
2033
  if (qs.length) {
@@ -2034,7 +2035,10 @@ async function createTask() {
2034
2035
  renderClarify(qs, payload.goal, resetSubmit);
2035
2036
  return;
2036
2037
  }
2037
- } catch (e) { /* 澄清失败照常创建 */ }
2038
+ } catch (e) {
2039
+ // 澄清服务不可用或超时不阻塞主流程,明确告诉用户已经自动继续。
2040
+ msg.textContent = t("澄清响应较慢,已直接创建任务…");
2041
+ }
2038
2042
  }
2039
2043
  S.clarifyDone = false;
2040
2044
  if (!payload.workdir) delete payload.workdir; // 留空 → 服务端用「默认保存路径」(编排设置可改)
@@ -2378,6 +2382,7 @@ async function deleteTask(id) {
2378
2382
  if (!await uiConfirm(t("删除该任务及其全部运行记录(含日志与报告)?不可恢复。"), { ok: t("删除"), danger: true })) return;
2379
2383
  let gone = false;
2380
2384
  try {
2385
+ toast(t("正在删除任务…"));
2381
2386
  await api("/api/tasks/" + encodeURIComponent(id) + "/delete", { method: "POST" });
2382
2387
  } catch (e) {
2383
2388
  // 任务已不在(他端删过 / 重复点):不报错晾着,照常把视图清掉
@@ -3315,6 +3320,24 @@ function setEditRetry(taskId, status, taskExists) {
3315
3320
  if (bn) bn.classList.toggle("hidden", !taskExists || failedish);
3316
3321
  }
3317
3322
 
3323
+ /* 详情页归档按钮:非运行中显示;已归档任务显示「取消归档」。
3324
+ * 点击走 archiveTask(与右键菜单同一链路:取消归档会自动恢复侧栏目录显示)。 */
3325
+ function syncArchBtn(task, active) {
3326
+ const b = $("btn-arch");
3327
+ if (!b) return;
3328
+ const show = !!task && !active;
3329
+ b.classList.toggle("hidden", !show);
3330
+ if (!show) return;
3331
+ const archived = !!task.archived;
3332
+ b.textContent = archived ? t("取消归档") : t("归档任务");
3333
+ b.onclick = async () => {
3334
+ try {
3335
+ await archiveTask(task.id, !archived);
3336
+ b.textContent = archived ? t("归档任务") : t("取消归档");
3337
+ } catch (e) { /* archiveTask 内部已 toast */ }
3338
+ };
3339
+ }
3340
+
3318
3341
  /* 重试按钮三态:失败/取消 → 「↻ 继续任务」(断点续跑语义);连载任务完整跑完
3319
3342
  * 但质量未达标(verdict.publishable=false)→ 「↻ 重写未达标章」——后端 retry
3320
3343
  * 会把未过线章从继承清单剔除,只重写重评这几章(store.retry_task 未达标分支);
@@ -3346,6 +3369,7 @@ function renderTaskDetail() {
3346
3369
  if (bc) bc.classList.toggle("hidden",
3347
3370
  !(tk && tk.serial && tk.status !== "running" && tk.status !== "queued"));
3348
3371
  setEditRetry(tk ? tk.id : "", tk ? tk.status : "", !!tk);
3372
+ syncArchBtn(tk, tk && (tk.status === "running" || tk.status === "queued"));
3349
3373
  const isTask = ((S.state || {}).tasks || []).some((t2) => t2.id === key);
3350
3374
  if (isTask) {
3351
3375
  api("/api/tasks/" + encodeURIComponent(key) + "/runs")
@@ -3779,6 +3803,9 @@ async function renderRunDetail() {
3779
3803
  $("btn-share").classList.toggle("hidden", active); // 分享页:结束后可生成自包含 HTML
3780
3804
  $("btn-talk").classList.toggle("hidden", !(run.task_id && !chatEngineIsDirect(run)));
3781
3805
  const rcTask = ((S.state || {}).tasks || []).find((x) => x.id === run.task_id);
3806
+ // 归档按钮:非运行中任务可归档/取消归档(此前只有侧栏右键菜单入口,
3807
+ // 用户反馈「归档按钮不见了」——补显式入口,文案随状态切换)
3808
+ syncArchBtn(rcTask, active);
3782
3809
  setRetryBtn(run, rcTask);
3783
3810
  $("btn-continue").classList.toggle("hidden",
3784
3811
  !(rcTask && rcTask.serial && run.status !== "running" && run.status !== "queued"));
@@ -9287,7 +9314,7 @@ function renderSu() {
9287
9314
  t(" ") + "<a href=\"#\" onclick=\"event.preventDefault();suApply()\">" + t("立即升级") + "</a></b></p>";
9288
9315
  if (SU.notes) {
9289
9316
  html += "<div class=\"hint\"><b>" + t("新版本更新内容") + t(":") + "</b>" +
9290
- "<pre class=\"su-notes\">" + esc(SU.notes) + "</pre></div>";
9317
+ renderRelnotes(SU.notes) + "</div>";
9291
9318
  }
9292
9319
  } else if (SU.mode === "npm" && !SU.note) {
9293
9320
  html += "<p class=\"hint\">" + t("已是最新版。") + "</p>";
@@ -9303,6 +9330,31 @@ function renderSu() {
9303
9330
  renderUpdPill();
9304
9331
  }
9305
9332
 
9333
+ /* 更新说明分类渲染:### 行渲染为小节标题,- 行渲染为条目(对照主流产品的
9334
+ * 更新日志样式:问题修复/新功能分组,一眼看懂)。全部 esc 后拼接。 */
9335
+ function renderRelnotes(txt) {
9336
+ const lines = String(txt || "").replace(/\r/g, "").split("\n");
9337
+ let html = "", inList = false;
9338
+ const closeList = () => { if (inList) { html += "</div>"; inList = false; } };
9339
+ for (const raw of lines) {
9340
+ const line = raw.trim();
9341
+ if (!line) continue;
9342
+ if (/^#{2,4}\s+/.test(line)) {
9343
+ closeList();
9344
+ html += "<p style=\"margin:6px 0 2px\"><b>" + esc(line.replace(/^#{2,4}\s+/, "")) + "</b></p>";
9345
+ } else if (/^[-*]\s+/.test(line)) {
9346
+ if (!inList) { html += "<div style=\"margin:2px 0 2px 4px\">"; inList = true; }
9347
+ html += "<div style=\"display:flex;gap:6px\"><span style=\"opacity:.6\">·</span>" +
9348
+ "<span style=\"flex:1\">" + esc(line.replace(/^[-*]\s+/, "")) + "</span></div>";
9349
+ } else {
9350
+ closeList();
9351
+ html += "<p style=\"margin:2px 0\">" + esc(line) + "</p>";
9352
+ }
9353
+ }
9354
+ closeList();
9355
+ return html || ("<pre class=\"su-notes\">" + esc(txt) + "</pre>");
9356
+ }
9357
+
9306
9358
  /* 顶栏左上角常驻更新胶囊:有新版才出现(同版本被忽略后不再出现),
9307
9359
  * 点击直达「关于与更新」,× 忽略本版本(与 su.seen 记账键同一套语义) */
9308
9360
  function renderUpdPill() {
package/app/ui/i18n.js CHANGED
@@ -584,6 +584,8 @@
584
584
  "勾选可批量删除": "Tick to bulk delete",
585
585
  "取消归档": "Unarchive",
586
586
  "归档": "Archive",
587
+ "归档任务": "Archive Task",
588
+ "归档后任务从侧栏收起,可随时用左下角时钟图标找回并取消归档": "Archiving hides the task from the sidebar; use the clock icon at the bottom-left to find it back and unarchive anytime",
587
589
  "重命名任务": "Rename task",
588
590
  "↻ 继续任务": "↻ Resume task",
589
591
  "↻ 重写未达标章": "↻ Rewrite unqualified chapters",
package/app/ui/index.html CHANGED
@@ -388,6 +388,7 @@
388
388
  <button data-i18n="✎ 编辑重试" id="btn-editretry" class="ghost hidden" data-i18n-title="取回原任务的目标/目录/评审设置,修改后提交即重新开跑" title="取回原任务的目标/目录/评审设置,修改后提交即重新开跑">✎ 编辑重试</button>
389
389
  <button data-i18n="继续连载" id="btn-continue" class="ghost hidden">继续连载</button>
390
390
  <button data-i18n="基于此任务新建" id="btn-newfrom" class="ghost hidden">基于此任务新建</button>
391
+ <button data-i18n="归档任务" id="btn-arch" class="ghost hidden" data-i18n-title="归档后任务从侧栏收起,可随时用左下角时钟图标找回并取消归档" title="归档后任务从侧栏收起,可随时用左下角时钟图标找回并取消归档">归档任务</button>
391
392
  <button data-i18n="分享页" id="btn-share" class="ghost hidden" data-i18n-title="生成自包含分享页(单文件 HTML),可直接发给他人查看任务成果" title="生成自包含分享页(单文件 HTML),可直接发给他人查看任务成果">分享页</button>
392
393
  <button data-i18n="删除记录" id="btn-delete" class="danger hidden">删除记录</button>
393
394
  <button data-i18n="✉ 继续对话" id="btn-talk" class="ghost hidden" data-i18n-title="人工检查有问题?告诉主智能体,由它判断怎么引导执行" title="人工检查有问题?告诉主智能体,由它判断怎么引导执行">✉ 继续对话</button>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codebee",
3
- "version": "0.1.23",
3
+ "version": "0.1.25",
4
4
  "description": "CodeBee · 多智能体编排台 — 统一编排本机 AI 编码 CLI(Codex / Claude Code / QwenCode / OpenCode / Aider…):目标→拆解→路由→执行→验证→跨厂商评审→修复→报告。纯 Python 标准库实现,本地 Web UI。",
5
5
  "license": "MIT",
6
6
  "bin": {