Commit Graph
243 Commits
Author SHA1 Message Date
host 036323e620 feat(console): CHV executor option in dispatch/env selectors + experimental note in detail/list
- DispatchSection: add cloud-hypervisor option (labelled experimental,
  default off); default stays docker; hint states a KVM-host CHV worker
  must claim the task (otherwise it stays queued; attachments are
  rejected by the backend at creation) and that the frontend only passes
  the executor value through, never bypassing the backend allowlist.
- EnvSection: same option, because the backend env-create allowlist
  (local/docker/cloud-hypervisor) does allow it; note states env
  allowlist excludes cloud.
- TaskListSection: add cloud-hypervisor to the executor filter so CHV
  tasks are findable; list rows already showed executor.
- TaskDetailPanel: pure display note for cloud-hypervisor tasks
  (experimental, default off, no VM controls); detail already showed
  executor from the task API.
- README: document the CHV console entry, experimental marking, and
  verbatim backend-error display.
- Rebuilt cloud/console.html from src (tsc + vite single-file build);
  no backend change: executor is already returned by _task_to_dict.
2026-10-31 02:25:21 +00:00
host 445376743d feat: CHV 审核修复 P2(范围恢复为全做)
P2-1:preflight reuse/CPU/内存校验块小提取为
_preflight_config_checks(纯移动,深耦合处如实停)。
P2-2:build_vm_command 降级为私有 _build_vm_command;
Docker goal 内联解析顶部加正典分叉说明 + 同步检查清单。
P2-3:gaps grep 文本断言改成真实 Worker._run_attempt
行为断言。P2-4:README/build.sh 口径对齐(章节顺序、
BUILDINFO 名字列表、Node.js 不装写实)。P2-5:stop_vm
删除失败记审计。P2-6:CPU/内存校验统一进 preflight。
测试:原 84 + 新增 33 = 117 项,mock,无真 VM。
2026-10-31 02:01:03 +00:00
host 9771ed9e8c feat: CHV 审核修复(P0+P1,堆叠于 #230)
P0:seed 磁盘 CIDATA ISO 挂进 VmConfig 第二块只读盘;
restore provisioned 下复用钉死 known_hosts、缺失 fail-fast
绝不 keyscan;preflight 拦截 CHV_DISK_MODE=reuse(显式
实验二次确认 + 审计放行);SSH 目标选客机 IP 方案(显式
host > net 静态 ip > 显式转发宣称回环,三者皆无 fail-fast)。
P1:网关 extra_env 经 SSH env 前缀注入、worker 守卫收窄到
Local/CHV;取消/清理/看门狗接 CHV 通用路径;WarmPool
acquire 内 resume;容量门持久化计数;磁盘配额总量+余量
与已存在磁盘校验重拷;API 按 Content-Length 验完整性;
快照 file:// 验落盘再 shutdown;execute 死端口归类
vm_not_running。
P2 全部排除未做(用户范围收窄令,留待以后一轨)。
测试:原 84 + 新增 29 = 113 项,mock,无真 VM。
2026-10-31 01:54:13 +00:00
host 22b83f118a feat: CHV gap fill — worker breakpoint wiring, pool reconcile, per-VM host keys, egress validation, guest build script
Stack: #216 -> #221 -> this. Worker breakpoint branch now calls any
executor providing goal_resume_breakpoint_task (Local keeps its
original path, gateway tasks still loud-fail); WarmPool
reconcile_orphans is called on CHV worker startup and close with
audit-on-failure; per-VM SSH host keys are provisioned before VMM
start via cloud-init NoCloud seed (keyscan kept only as weak
fallback, CHV_HOST_KEY_MODE=provisioned|keyscan); CHV_NET_JSON is
validated in preflight and explicit direct egress is audited;
chv-guest/build.sh is now real steps with --dry-run and fails fast
without /dev/kvm. Tests: new test_chv_gaps.py (18), cloud full
1514 OK (skipped=4). No real VM verification: no KVM host.
2026-10-31 01:30:52 +00:00
host fde7bf4c3e feat: CHV 执行器优化(拆模块/去重复/SSH 钉死/池持久化/中途死亡分类)
- 拆模块:CHV 从 cloud/sandbox.py 巨类拆到 cloud/chv/(executor/
  pool/config/api_client/ssh_transport/disk/errors),sandbox 只留
  兼容 re-export,旧导入路径与新路径是同一对象
- 去重复:goal 解析、host 顶层参数、runner 超时抽成共享 helper,
  Local 与 CHV 在矩阵输入下结论全等(Docker goal-resume 变体
  有意保留内联版,见 PR 描述)
- 安全:SSH host key 按 VM 钉死(state_dir/<vm>/known_hosts,
  ssh-keyscan 首次捕获 TOFU),废除 no + /dev/null;CHV_SSH_USER
  空串与 CHV_SSH_PORT 越界直接拒绝,不静默 fallback
- execute 语义:只读已运行 VM,未运行报 vm_not_running,不为
  status 起 VM
- 预热池:registry 落盘、重启载入只当孤儿、reconcile 清理、
  损坏 quarantine;条目仍一次性,绝不复用脏 VM
- 长任务:VM 中途死亡判 interrupted(断点可续跑);中途心跳
  经评估不做(无客内进度信号可采)
- #215 未合并:只列复用清单,不复制模块

测试:原 42 项 + 新 24 项全过;相关旧套件与 cloud 全量 1496 项
全过(skipped=4)。验证仍是 mock + 干跑 + 单元测试,未做真机、
压测、安全审计;堆叠于 #216 之上,base 为 feat-cloud-hypervisor。
2026-10-30 19:45:33 +00:00
host c371bbdf1e feat: Cloud Hypervisor 执行器生产级 v1(cloud-hypervisor)
单任务单 VM:API 唤醒(preflight→vmm.ping→vm.create→vm.boot→SSH 就绪)、
暂停/快照/休眠等价/关闭/回收、预热快照池、每任务磁盘 copy、容量与磁盘配额门、
受控 egress fail-closed、VM 事件审计与分类失败;worker/server/autoscaler 接线
(executor=cloud-hypervisor,任务内 LLM 不可自选);默认关闭,不进生产路由。
未做真实 VM 验证:生产主机与本 VM 均无 /dev/kvm、无嵌套虚拟化,验证为 mock +
干跑命令 + 单元测试;真 VM、快照恢复、压测、安全审计见
docs/chv-production-readiness.md。CI 账单故障仍是硬门禁,本提交只到 PR OPEN。
2026-10-30 18:54:16 +00:00
openqj aebc6238a6 Merge pull request #201 from openqj/feat-platform-auto-resume
feat: auto-resume platform-interrupted non-goal tasks
2026-10-30 15:51:43 +08:00
host 4428a721a6 feat: auto-resume platform-interrupted non-goal tasks
Deploy restarts kill running tasks: the worker marks them
interrupted (worker_shutdown on graceful exit, sweep on stale
reclaim), and auto_resume_interrupted used to accept goal tasks
only, so every non-goal task killed by a deploy stayed
interrupted forever unless a human retried it (the 2026-10-30
demo task died this way).

Now worker_shutdown/sweep interruptions are re-queued for
non-goal tasks too: the platform killed the task, so the
platform re-queues it. The re-queue is a fresh run, not a
breakpoint resume: goal_resume_pending is forced to 0 and any
stale resume_message is cleared, so the new run cannot be
hijacked by the goal-resume path or an old continue message;
files in the same worktree persist. All existing guards stay:
user pause, coordinator orphans, quota (still goal-only),
backoff, the 3-strike stall guard (non-goal tasks have no
checkpoints, so each platform re-queue counts as no-progress),
and the auto_resume_max cap. Other non-goal reasons (NULL,
quota, user cancel) still do not auto-resume.
2026-10-30 15:39:55 +08:00
host 2d644f901b feat(console): automation panel edit and richer list
- AutomationPanel rows now show title, prompt content (160-char preview with expand/collapse), repo_url, last/next run, run_once badge and cancelled time.

- Active automations get an inline edit form (name/prompt/interval/repo) that PATCHes only changed fields via the existing automation_update endpoint; backend semantics unchanged (no last_run_at reset, cancelled stays terminal).

- Rebuilt cloud/console.html with tsc + vite (build green); automation python tests 18/18 OK.
2026-10-30 15:31:21 +08:00
openqj e2ce04ce4f Merge pull request #197 from openqj/feat-stream-waiting
feat: browser stream waits through round gaps instead of disconnecting
2026-10-30 15:29:17 +08:00
host 962bb50a1c feat: browser stream waits through round gaps instead of disconnecting
Stale bridge state used to end the stream on the first stale read,
so every round gap and every worker restart killed the watch (the
2026-10-30 demo watch died this way when a 15:03 deploy restarted
the worker). Now a stale state switches to a waiting heartbeat
every 5s while the task is still alive (running/queued/paused/
interrupted), and frames resume when the next round's MCP starts
polling. The stream ends only on a terminal task state, a missing
task row, or 10 minutes of continuous staleness. The panel shows
a waiting status and keeps the last frame. Also force-close the
SSE connection on stream end: HTTP/1.1 keep-alive otherwise left
terminal streams hanging with no EOF.
2026-10-30 15:14:37 +08:00
host b977a9dee8 feat: sync shared-home MCP scripts on control-plane startup
租户 config 的 mcp_servers.* 指向共享 home 路径,但宿主共享
home 里原先没有 MCP 脚本,宿主 app-server 启动 MCP 即文件
不存在、握手断掉,面板 mcp-servers-list 三服务器 toolsError
全是 handshake failed;14:43 的手工拷入能修一次,但下次
MCP 脚本改动后面板又会跑旧版。

本批只在服务端 main() 启动时同步一次:清单唯一定义在
cloud/shared_home_mcp.py(7 文件:playwright_mcp/browser/
remote、websearch_mcp/websearch、imagegen_mcp/imagegen,含
同目录兄弟模块),解析优先用 host-config-host.json 的
codex_home,兜底用 tenants_root 父目录/codex-home;缺失
拷入、不同刷新(原子替换)、相同不动;源缺失/目标不可写
只记 warning,绝不阻塞启动。create_server() 不做同步,
避免单测写向生产共享路径。

被否决的落点:worker _tenant_dirs(只在下个任务派发时跑,
面板要等下一个任务才更新,且不修共享路径本身);deploy
host_deploy.sh(会在 shell 里复制第二份清单,且重启不
部署时不刷新);面板请求时同步(把读请求变成写请求,
失败会把面板读数变成 502 风险)。
2026-10-30 07:08:51 +00:00
openqj 671b4bedef Merge pull request #194 from openqj/feat-project-tree
feat: project directory tree + first-round snapshot
2026-10-30 15:00:11 +08:00
openqj 4f035f0449 Merge pull request #186 from openqj/feat-console-llm-status
前端:任务详情 LLM 进度与失败原因标识
2026-10-30 14:46:24 +08:00
host ce7fb3afd6 feat: project directory tree + first-round snapshot
- cloud/tree.py: structured worktree tree (dirs first, ignore
  .git/node_modules, symlinks not followed, entry/depth
  truncation flags, text render for injection)
- GET /tasks/{id}/tree with /files auth + worktree resolution,
  max_depth 1..5, max_entries 1..500, escape 400, missing 404,
  cloud/cross-host 409
- MCP get_task_tree translating to the new endpoint
- worker first-round injection of a repo-checkout top-level
  snapshot (2 layers, 120 entries) after repo resolution,
  labelled as checkout snapshot not worktree; skipped for
  coordinator/resume/fork, silent when no host source
- docs/project-tree.md; tests for tree, endpoint, injection,
  MCP translation
2026-10-30 14:46:11 +08:00
openqj 85f280e5e7 Merge pull request #193 from openqj/feat-software-engineering-github
feat: software-engineering skill GitHub guarantees
2026-10-30 14:40:30 +08:00
host 70ad8d7d09 feat: 任务详情 LLM 进度与失败原因标识(列表失败原因摘要) 2026-10-30 14:38:23 +08:00
openqj 5c1069334a feat: software-engineering skill GitHub guarantees
- G0/G0.5: repo freeze items (new vs existing, owner/repo, default branch,
  visibility); new-repo creation and first commit are G1 prerequisites.
- One branch per thread (feat/swe/<phase>-<role>-<short>), never push main
  directly, never force-push main; sync main before PR, coordinator
  resolves conflicts, never silently.
- Delivery requires a PR with scope, contract version, test evidence,
  known issues and linked todos/PRD items; no PR number means not done.
- Merge gate: Checks green, directory ownership pass, frozen contract
  version, coordinator approval, no unresolved review comments.
  Branch protection (require PR, require Checks, block direct push) is a
  GitHub repo setting; if unset, coordinator records it as risk and
  enables it, never pretends it is protected. GET /tasks/{id}/pr/checks
  is read-only diagnostics, never reruns or approves.
- Merge commit by default; merge record holds PR number, merge commit
  hash, CI run link and executor; delete remote branch after merge.
- Per-client release tags (e.g. v0.1.0) from merged PRs; rollback is
  revert or redeploy previous tag, never force-push rollback.
- Security: tokens/keys never in code, commits or command lines;
  token only into subprocess env (cloud/pr.py GIT_TOKEN pattern);
  .gitignore covers secrets and local config.
- Main text and appendix (coordinator, client, acceptance) updated in
  sync; appendix travels inside SKILL.md for seeding.
2026-10-30 06:33:25 +00:00
host 56b8f98b47 perf: Chromium 启动 flag 微调 + screencast 画质 q60->q50
Flag:加 --no-first-run、--no-default-browser-check、
--disable-default-apps、--disable-extensions、
--disable-background-networking、--disable-sync、
--disable-translate,只跳过首跑/装配活,不改渲染与工具
行为。实测(runsc 容器,launch + new_page,各 3 次交替):
旧中位数 0.889s、新 0.819s——只差 70ms 且在逐次噪声
(0.70-0.99s)里,几百毫秒的预期不成立;零成本顺手留着。
画质:screencast 与 eager 抓帧 q60 -> q50,分辨率
1280x800 不动,点击坐标系不受影响。实测同页文本+渐变:
62068 -> 56428 字节(-9%),不是经验法则的 30%;觉得糊
一句话改回 60。
2026-10-30 14:27:04 +08:00
openqj 878f8de7da Merge pull request #190 from openqj/feat-remote-perf2
perf: 小优化组 + 恢复浏览器页签
2026-10-30 14:17:03 +08:00
host cbf5e65a7a perf: 小优化组 + 恢复浏览器页签
1. MCP 空闲睡眠 50ms -> 10ms:#187 后单轮 drain 约 0.3ms,
   100 次/s 空闲迭代约 3% 单核,请求与远控输入拾取延迟
   从平均 25ms 降到 5ms。
2. stream 轮询 50ms -> 20ms。
3. stream payload 加 url/title;面板 stream 处理合并 url/
   title,5 秒 state 轮询只在未观看时跑(观看时 stream 已
   全量覆盖,轮询纯冗余;不观看时保留轮询,避免会话开始
   后页眉 stale)。
4. 恢复浏览器页签:#176(ccb5a86)改写 TaskDetailPanel
   页签时顺带删了 BrowserPanel 的挂载,导致线上控制台
   自 #176 起就没有浏览器页签(面板文件一直在,只是不
   被 import,构建产物因此不变)。本次把 import、页签
   与 Card 原样挂回;构建产物含“开始观看”标记可证。
console.html 由 npm run build:console 重打(342484 字节)。
console-redesign/ 为构建脚本审阅产物,不进仓库。
2026-10-30 14:09:02 +08:00
host 885bf38790 feat: add software-engineering skill v0.2
Add cloud/skills/software-engineering/SKILL.md (686 lines, v0.2, appendix with 9 role templates travels inside SKILL.md because skill_seed only copies SKILL.md, not templates/). Update skill pack tests: EXPECTED set and real-pack list now include software-engineering, plus an explicit seed test asserting it lands at skills/software-engineering/SKILL.md, contains the appendix, and tenant edits are never overwritten. One-line wording tweak in the architect template avoids the existing secret-scan false positive on the substring sk- inside agent-task-contract.md; deployed file sha256 bd0436399ac05c6131b9281dad00973e50d13540e4c56ad21f21e2b5209bae8e (40759 bytes, 686 lines).
2026-10-30 06:00:31 +00:00
host fafc0734c7 perf: screencast 隔帧改每帧,跟手优先
Page.startScreencast everyNthFrame 2 -> 1,画质 q60、尺寸
1280x800 不动。静态页不产生额外成本(帧只在重绘时来,
且 #187 起桥只写变化的帧字节);收益全部落在真正需要跟
手的时候:滚动、拖拽、动画期间帧率翻倍。测试断言同步。
2026-10-30 13:50:18 +08:00
host 910168126d perf: 桥变化才写、stdin 优先、stream 50ms 轮询
1. 桥写放大:旧代码每 ~50ms 轮询都无条件重写 state 和帧
   文件(约 40 次原子 temp+replace/s 走 runsc gofer,
   泵持久返回同一帧、updated_at 每轮都变,字节其实不变)。
   现帧字节不变不写;state 只在 url/title/started/holder/
   streaming 变化时写,或 0.5s 心跳一次(判死阈值 30s,
   绰绰有余);静态页写量从 ~40次/s 降到 ~2次/s。
2. MCP 主循环 stdin 优先:旧循环先 drain 再读 stdin,
   每次工具调用都先付一轮文件 IO。现 pending 请求先处理,
   空闲轮询 drain,忙时 200ms 保底 drain 一次防饿死。
3. stream 轮询 200ms → 50ms,画面延迟下限随之下降。
附回归测试:无变化轮询不重写、帧变化立即写、holder
变化绕过节流立即写。
2026-10-30 13:36:24 +08:00
host 2d840a6c37 fix: navigate 后立即推一帧,静态页开流不再等重绘
screencast 帧只在重绘时来,页面可能在 startScreencast 之前
就已画好——静态页于是开流后一直无画面,直到下一次重绘。
navigate 后用 CDP captureScreenshot 抓一张当前视口塞进帧
队列,泵在下一轮就把桥帧文件写出来;泵跳过空 session 的
ack(eager 帧没有可确认的 screencast 帧)。失败静默,
screencast 本身仍照常流动。
2026-10-30 13:14:38 +08:00
host ccb5a8638d feat: 任务详情 LLM 请求数(cost_records 存 completions) 2026-10-30 12:58:41 +08:00
openqj 2ff8975f43 Merge pull request #183 from openqj/feat-browser-filebridge
fix: 浏览器远控传输层改文件桥(Unix socket 在 runsc 下宿主不可见)
2026-10-30 07:35:46 +08:00
host 6bcdeb8da1 fix: 浏览器远控传输层改文件桥(Unix socket 在 runsc 下宿主不可见)
根因(2026-10-30 活体实证):#181 的 .browser-remote.sock 假设
宿主能连容器内 socket,但生产 Docker 任务走 runsc/gVisor,
其 gofer 挂载下容器内建的 socket 只在容器内可见,宿主目录
里只有普通文件(browser-live.png 一直能透传)。后果:server
代理对真实任务一律 503,会话根本没活过。

修法:传输层改四个普通文件(worktree 内,原子写 + 追加日志):
- .browser-remote-state.json:MCP 每轮重写,mtime 即存活信号,
  server 判 30 秒无心跳为会话死亡(503);
- .browser-remote-frame.jpg:最新 screencast 帧(base64 文本);
- .browser-remote-input.jsonl:server 追加,MCP 按偏移量消费
  完整行,执行时再判 holder,半行等下一轮;
- .browser-remote-control.json:{holder, seq},MCP 首轮即应用,
  接管可先于浏览器启动。
- holder 竞态:control 写下后 state 文件约 50ms 才刷新,server
  的 input/stream 改判 effective_holder(控制文件 mtime 新者胜),
  否则接管后立刻点会误 409。
- 线程契约与控制权模型不变;MCP 主循环仍是唯一触页线程。
- 播种刷新(#181)让老租户自动拿到新版脚本。

测试:socket 测试改文件桥测试(桥轮询/偏移量/半行/陈旧态/
effective_holder + server 代理全链),全量 1357 项通过(skipped 4)。
2026-10-30 07:28:32 +08:00
host e81ba8d2bf feat: 会话内 LLM 自判 goal / 自动化标记工具,不靠关键词
agent 在回合输出里写 goal-convert 块,worker 在轮次边界
排成 /goal 自后续消息、走已有 followup 转换路径把本会话
转成 goal;写 automation-create 块,worker 在轮次边界
创建自动化定义(权限 create_task、配额整轮门、创建人跟
父任务走、name 缺失自动生成、首次时刻已过去单块拒绝、
bind heartbeat 可绑回本会话)。

automations 新增 first_run_at / run_once:首次时刻只管
首次、之后按间隔算;只跑一次跑过后 is_due / due / claim
三处都不再到期(SQL 到期条件与 Python 口径共用同一
_DUE_SQL);API 创建与更新同步接受这两个字段。

刻意不向 LLM 自动注入工具指南:避免 prompt 臃肿,格式
只写进 docs/marker-tools.md 与 README,需要时由用户在
会话里手动告诉 agent;服务端不按关键词再猜意图。

单测 cloud/tests/test_session_goal_automation.py 12 项,
相关回归 218 项全过。
2026-10-30 07:15:05 +08:00
host f1aab5415c feat: 不用斜杠,单发 goal 也触发 /goal 目标
触发词从仅 /goal 放宽到 /goal 或裸 goal(大小写不敏感,
单数 only,goals/mygoal 不算):goal 收xxx、goal,目标是
收xxx、发goal 收xxx 均同款触发,新建与主线转换入口共用
同一解析。讨论句式仍不触发:goal 的用法、goal 是什么、
讨论goal的用法、/goal的用法 均返回 None。
单测补 4 项:裸 goal 触发、裸 goal 讨论不触发、followup
裸 goal 转换、新建裸 goal。
2026-10-30 07:15:05 +08:00
host f3bd65c171 feat: 新建任务的 prompt 里写 /goal 也自动变 goal
上一提交只覆盖了已有主线的转换,新建任务的 prompt 里写
/goal 时仍会当成普通一轮任务跑。本提交补上 POST /tasks
入口:prompt 经 cloud/goal_command.py 解析后,目标即新任
务的 prompt 与 goal,goal_mode 强制为 1(命令优先于 body
里的 goal_mode=0),plan/验收命令冲突仍按新建规则 400,
空目标 400 不建任务;讨论里提到 /goal 不触发。
单测补 5 项:/goal 直写、整句、空目标、plan/验收冲突、
讨论 prompt 不变。
2026-10-30 07:15:05 +08:00
host 3096e04345 feat: 主线 /goal 命令自动建 goal
发给主线的一句话(含字面 /goal)即可自动建 goal,不用先
知道主线是进行中还是已终态,也不用勾选项:
- cloud/goal_command.py:server 与 worker 共用的纯文本解析,
  只认命令形状(/goal 开头、分隔符/目标标记、开启类动词),
  讨论里提到 /goal 不误触发;空目标返回空串供调用方 400。
- server followup/thread/message/continue 三入口同款:queued
  原地转 goal,已终态复活并转 goal,running 排队后由 worker
  在轮次边界转 goal;已是 goal 409、plan 400、merged 409。
- worker 排空:/goal 不当普通轮次跑,CAS 把 running 主线
  改回 queued 并写 goal/resume_message,下次认领走 goal-resume
  在同一 thread 上开新目标循环;取消/回收时 CAS 失败则把
  followup 放回 pending,绝不把取消过的任务改回 queued。
- 单测 14 项:解析、三态转换、拒绝口径、普通消息不受影响、
  continue/thread 同款、worker 轮次边界转换 + 下次 goal 跑通。
2026-10-30 07:15:05 +08:00
host 7589876cff feat: 控制台浏览器远控面板
- TaskDetailPanel 新增“浏览器”页签,内嵌 BrowserPanel。
- 开始观看:fetch + ReadableStream 读 SSE(EventSource 发不出
  X-API-Key),最新帧以 data URI 显示;状态每 5 秒轮询。
- 接管/交还:POST /browser/control;接管后点画面按 1280x800
  换算坐标 POST /browser/input,键盘直达页面。
- 产物:cloud/console.html 由 vite 单文件构建重打(341451 字节,
  含 browser/state 与“浏览器远控”标记)。
2026-10-30 07:01:48 +08:00
host 6f39ab3945 feat: 浏览器二期后端:远控服务 + ref 快照 + server 代理
- playwright_remote.py(新):MCP 进程内 Unix socket HTTP 服务,
  监听 worktree/.browser-remote.sock;GET /state、GET /stream
  (SSE 画面流)、POST /input、POST /control(接管/交还)。
  线程契约(实测):Playwright 同步调用只能在创建页面的线程,
  所以 HTTP 线程只读属性/读最新帧/入队,MCP 主循环用
  select 轮询(50ms) draining 输入并 pump screencast 帧
  (无 ack 则 CDP 首帧后停流)。
- 画面流走 CDP screencast 帧(学 chrome-devtools-mcp),不用
  定时截图;ffmpeg 录像暂不做。
- snapshot_refs/click_ref(学 playwright-mcp 的 ref 机制)+
  mouse_move/key_press/type_text;agent 工具在 holder=user 时
  直接报错,等用户交还。
- server.py:/tasks/{id}/browser/{state,stream,input,control}
  代理到 worktree socket,复用任务鉴权与 worktree 解析;
  会话不存在时 503(轮次结束即消失是设计)。
- 播种器:MCP 脚本是系统文件,版本变化时刷新老租户旧脚本
  (script_refreshed 打日志),否则远控只对新项目生效;
  新增 playwright_remote.py 进播种清单。
- 队列遮蔽修复:cloud/queue.py 会遮蔽 stdlib queue,改用
  SimpleQueue(deque+锁),仓库模式与 flat-copy 两路都通。
- 测试:新 20 项(remote 服务、server 代理、ref/输入/
  screencast fake),全量 1354 项通过(skipped 4)。
2026-10-30 06:44:24 +08:00
host 814fe8f7c2 feat: 浏览器一期:坐标点击 + live 截图
- browser_click_at(x, y):视口坐标点击(1280x800、左上角
  原点),越界与非数字拒绝;live 视图里用户在截图上的
  点击落点就走这个工具。
- browser_live_shot:固定文件 browser-live.png + 状态
  sidecar browser-live.json(URL/标题/时间戳),watcher
  轮询一个稳定路径即可;技能要求每次动作后都调一次,
  保持画面最新。
- MCP 新增 browser_click_at / browser_live_shot 两个工具;
  技能补 live 视图一节;测试 9 项(含 fake mouse、越界、
  live 文件与状态读回)。
2026-10-30 06:19:55 +08:00
openqj cb6de0e3aa Merge pull request #178 from openqj/feat-playwright-mcp
feat: 浏览器自动化 MCP(Playwright)
2026-10-30 05:39:27 +08:00
host cd3952590b test: 技能播种清单期望集加 browser-automation 2026-10-30 05:30:58 +08:00
openqj 58cbb198cf Merge pull request #177 from openqj/feat-project-todos
项目待办 + LLM 标记工具:todos 接口、控制台待办页、todo/task-list/cost/files 标记与首轮注入
2026-10-30 05:22:54 +08:00
host f67867694f test: 技能清单期望集加 browser-automation 2026-10-30 05:22:25 +08:00
host c9a483282d feat: 浏览器自动化 MCP(Playwright)+ browser-automation 技能
- playwright_browser.Browser:单页 Chromium,navigate /
  snapshot(正文 8000 字截断标记)/ click / fill / evaluate /
  screenshot(工作区内)/ close;启动参数 --no-sandbox +
  --disable-dev-shm-usage(runsc + 1003 用户实测必需),
  代理显式传给 launch(Chromium 在 Linux 下不稳定地读 env
  代理),浏览器路径 PLAYWRIGHT_BROWSERS_PATH=/opt/ms-playwright。
- playwright_mcp:stdio MCP,7 个 browser_* 工具,同一进程
  单 Browser 实例;测试用 fake browser / fake factory。
- worker:--playwright-mcp flag,_tenant_dirs 播种两个脚本 +
  [mcp_servers.playwright],_prepare_tenant 写 env(代理 +
  浏览器路径,MCP 子进程不继承 Codex 进程 env,镜像 ENV
  在此必须重写,缺了会报 Executable doesn't exist)。
- 技能 browser-automation:JS 页、翻页、表单、截图时用,
  静态页优先 web_fetch / web_search;截图须 PIL 读回验证。
- 镜像(层构建,非本 PR):FROM latest + fonts-noto-cjk +
  playwright + chromium(npmmirror)+ install-deps,3.77GB;
  runsc + 1003 + docker-codex 条件下 JS 执行、example.com
  标题、截图均已实测通过。
2026-10-30 05:14:09 +08:00
host 9d6430a4d0 成本配额与文件只读标记:task-cost/quota-status/task-files 2026-10-30 05:11:06 +08:00
host 2fd73c1121 任务列表 task-list 标记 + 首轮项目上下文注入 2026-10-30 05:11:06 +08:00
host 73288f08db 待办:todo-list/create/update 标记工具 + 首轮未完成待办注入 2026-10-30 05:11:06 +08:00
host b3b3b35042 待办:项目待办模型 + /projects/{id}/todos 接口 + 控制台待办页 2026-10-30 05:11:06 +08:00
host 60283d55fc feat: 经验复用 MCP 暴露——项目记忆列/建/废弃(注入与提取已存在,不重复造) 2026-10-30 05:01:44 +08:00
openqj c10fda4e4a Merge pull request #174 from openqj/feat-repo-access-multi
feat: 仓库接入通用化(批量预检 + 多仓 ssh 别名)
2026-10-30 05:01:13 +08:00
openqj 6d49b72a9c Merge pull request #173 from openqj/feat-docker-sandbox-strict
feat: Docker 沙箱 /tmp tmpfs 隔离 + 可选根只读
2026-10-30 05:01:09 +08:00
openqj 8d7651b0b7 Merge pull request #172 from openqj/feat-metrics-extended
feat: /metrics 可观测性扩展
2026-10-30 05:00:53 +08:00
host 50ba8d9297 feat: 仓库接入通用化——批量预检 + 多仓 ssh 别名配给 2026-10-30 04:18:09 +08:00
host 49fc27eef1 feat: Docker 沙箱 /tmp tmpfs 隔离 + 可选根只读(内层 bwrap 本体不在本仓修复范围) 2026-10-30 04:17:09 +08:00