codebee 0.1.96 → 0.1.98

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,19 @@ README 元数据带回,供老版本在「发现新版本」时展示新版更
6
6
 
7
7
  ## 未发布
8
8
 
9
+ ## v0.1.98(2026-10-09)
10
+
11
+ - **连载起草误拒修复(沙箱闸策略感知)**:0.1.97 起任务创建强制落默认执行策略,沙箱闸把非 codex 外部 CLI(claude-code/opencode/kimi-code 等)一律拒跑——89—96 批连载起草整批被拒死、连载停摆。现改为策略感知:默认策略(工作目录白名单+允许网络+无禁用)与外部 CLI 天然权限一致,放行;仅当任务带收窄策略(禁网/禁工具/环境变量白名单/目录白名单不含工作目录)时仍拒绝(fail-closed)。codex 分支语义原样保留
12
+ - **蜂巢「3D 场景」重做为真 3D 蜜蜂办公室(WebGL)**:此前的 3D 只是把平面卡片整体斜切(CSS 透视),现换成零依赖 WebGL2 引擎渲染的蜜蜂办公室——每个流水线阶段是一排工位,每个步骤是一只坐在桌前对着显示器的低多边形蜜蜂:运行中的屏幕亮蓝脉动+蜜蜂打字颤翅、完成绿屏、失败红屏+趴桌、排队黑屏打盹;蜂王戴皇冠坐讲台、始终面向当前在干活的工位,巡逻蜂平时绕场巡查、有格子跑起来就飞去悬停督工。左键拖动旋转/滚轮缩放/右键升降/双击空白复位,空闲 8 秒缓慢自转(尊重系统减弱动效设置);悬停工位出气泡卡(角色/模型/实时输出/思考行),点按直接开日志抽屉;换肤与明暗主题自动跟随;WebGL 不可用或上下文丢失自动回落 2D 列表并记忆视图偏好
13
+ - **uv 缺失自动补装**:管理页 uv 系安装命令遇到 uv 缺失,从「人话指引」升级为自动补装(Windows 先 winget 后 pip、Mac 先 brew 后官方脚本,全部免 sudo 非交互),补装成功直接接管安装;uv 全家桶命令挂国内镜像兜底
14
+ - **uv 系安装链 Mac 三防**:PATH 快照落点兜底(~/.local/bin 等)+ uv 缺失人话短路 + winget 头识别放宽
15
+
16
+ ## v0.1.97(2026-10-09)
17
+
18
+ - **知识注入扩展到全部任务类型**:引擎经验库与知识库此前只在连载链命中,现按任务类型全量覆盖(代码/文档/翻译/调研等全部受益)
19
+ - 命中计数不重复累加:同条目同轮只记一次;被预算丢弃的条目不记 hits——修复「从未被读到的内容反而升权、挤占预算」的反馈回路缺陷
20
+ - 注入结果与旧版字节一致(回归保障);66 班全类型矩阵回归测试 84 项
21
+
9
22
  ## v0.1.96(2026-10-08)
10
23
 
11
24
  - **3D 交互式蜂巢工作台视图**:任务流程以三维场景呈现,节点/连线/状态立体可视化,支持旋转缩放拖拽交互
package/README.md CHANGED
@@ -25,9 +25,11 @@ Trae Agent、OpenClaw……),提供
25
25
  ---
26
26
 
27
27
  <!-- relnotes:start -->
28
- ### 最新版更新内容(v0.1.96)
28
+ ### 最新版更新内容(v0.1.98)
29
29
 
30
- - 新增 3D 交互式蜂巢工作台视图:任务流程三维可视化(旋转/缩放/拖拽交互)
30
+ - 修复连载/常规任务被沙箱闸误拒:非 codex 外部 CLI 默认策略放行,仅收窄策略仍拒绝(89—96 批连载起草误拒实案)
31
+ - 蜂巢 3D 场景重做为真 3D 蜜蜂办公室(WebGL):运行打字颤翅、失败趴桌、蜂王督工,悬停看实时输出
32
+ - uv 缺失自动补装(winget/pip/brew/curl 免 sudo),uv 系安装链 Mac PATH 兜底
31
33
  <!-- relnotes:end -->
32
34
 
33
35
 
@@ -19,16 +19,34 @@ MAX_FILE_CHARS = 8000
19
19
  MAX_PROMPT_CHARS = 24000
20
20
 
21
21
 
22
- def _roots(workdir):
22
+ def _roots(workdir, boundary=None):
23
23
  try:
24
24
  current = Path(workdir).expanduser().resolve()
25
25
  except (TypeError, OSError, ValueError):
26
26
  return []
27
27
  if not current.is_dir():
28
28
  return []
29
+ # Trust instructions only through the nearest repository root. Outside a
30
+ # repository, the selected workdir itself is the boundary; never walk into
31
+ # an unrelated parent directory (or drive root).
32
+ try:
33
+ if boundary:
34
+ stop = Path(boundary).expanduser().resolve()
35
+ else:
36
+ stop = current
37
+ for candidate in (current, *current.parents):
38
+ if (candidate / ".git").exists():
39
+ stop = candidate
40
+ break
41
+ except (TypeError, OSError, ValueError):
42
+ stop = current
43
+ if current != stop and stop not in current.parents:
44
+ stop = current
29
45
  roots = []
30
46
  while True:
31
47
  roots.append(current)
48
+ if current == stop:
49
+ break
32
50
  parent = current.parent
33
51
  if parent == current:
34
52
  break
@@ -50,7 +68,7 @@ def _read(path):
50
68
  return ""
51
69
 
52
70
 
53
- def discover(workdir, *, max_files=MAX_FILES, max_chars=MAX_PROMPT_CHARS):
71
+ def discover(workdir, *, boundary=None, max_files=MAX_FILES, max_chars=MAX_PROMPT_CHARS):
54
72
  """Return nearest-first AGENTS.md guidance and stable metadata."""
55
73
  try:
56
74
  file_limit = max(1, min(MAX_FILES, int(max_files)))
@@ -60,7 +78,7 @@ def discover(workdir, *, max_files=MAX_FILES, max_chars=MAX_PROMPT_CHARS):
60
78
  records = []
61
79
  chunks = []
62
80
  used = 0
63
- for root in _roots(workdir):
81
+ for root in _roots(workdir, boundary=boundary):
64
82
  if len(records) >= file_limit:
65
83
  break
66
84
  path = root / "AGENTS.md"
package/app/core/board.py CHANGED
@@ -13,8 +13,8 @@ _CACHE = {"ts": 0.0, "data": None}
13
13
  _TTL = 8.0
14
14
 
15
15
  _TAIL_MAX = 150 # 跑马灯尾行截断
16
- _TAIL_LINES = 6 # 实时流窗口行数
17
- _TAIL_LINE_CHARS = 56 # 实时流单行截断(卡内 11px 等宽不换行的安全宽度)
16
+ _TAIL_LINES = 14 # 实时流窗口行数(单任务卡的终端约 20 行,留余量)
17
+ _TAIL_LINE_CHARS = 110 # 实时流单行截断;卡内 pre-wrap,超宽会折行而不是切掉
18
18
  _RECENT_LIMIT = 10 # 最近完成/失败条数
19
19
  _RUN_WINDOW = 300 # 今日计数扫描的运行窗口(id 字典序=时间序)
20
20
 
@@ -29,6 +29,43 @@ def payload():
29
29
  return data
30
30
 
31
31
 
32
+ def run_detail(run_id):
33
+ """单条运行的步骤链,供大屏下钻抽屉;不进 8 秒缓存(点开即要最新)。
34
+
35
+ 只给步骤概要,日志正文不在这里搬——前端选中某一步时走现成的
36
+ /api/runs/<id>/log?step=<log>&pretty=1,那份已有目录穿越防护和 tail 夹取。
37
+ """
38
+ from . import store
39
+
40
+ run = store.get_run(str(run_id or ""))
41
+ if not run:
42
+ return None
43
+ steps = []
44
+ for s in (run.get("steps") or []):
45
+ steps.append({
46
+ "n": s.get("n"), "role": s.get("role") or "",
47
+ "agent": s.get("agent") or "",
48
+ "agent_label": s.get("agent_label") or s.get("agent") or "",
49
+ "status": s.get("status") or "",
50
+ "started_at": s.get("started_at") or "", "ended_at": s.get("ended_at") or "",
51
+ "duration_s": s.get("duration_s"),
52
+ "summary": (s.get("summary") or "")[:120],
53
+ "log": s.get("log") or "",
54
+ "tokens": s.get("tokens") or 0,
55
+ "cost_usd": round(float(s.get("cost_usd") or 0.0), 4),
56
+ "exit_code": s.get("exit_code"),
57
+ "error": (s.get("error") or "")[:160],
58
+ })
59
+ return {
60
+ "run_id": run.get("id"), "task_id": run.get("task_id") or "",
61
+ "title": run.get("title") or "", "status": run.get("status") or "",
62
+ "started_at": run.get("started_at") or run.get("created_at") or "",
63
+ "ended_at": run.get("ended_at") or "",
64
+ "error": (run.get("error") or "")[:200],
65
+ "steps": steps,
66
+ }
67
+
68
+
32
69
  def _tail(step):
33
70
  """步骤实时流(正文优先,其次思考)的最后一行,给大屏跑马灯。"""
34
71
  for key in ("stream", "thinking"):