openqj
b3f4597d3f
Merge pull request #192 from openqj/feat-chromium-flags-quality
...
perf: Chromium 启动 flag 微调 + screencast 画质 q60→q50
2026-10-30 14:34:56 +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
openqj
c472078568
Merge pull request #189 from openqj/feat-software-engineering-skill
...
software-engineering skill v0.2: multi-client orchestration
2026-10-30 14:16:12 +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
openqj
5e562d8413
Merge pull request #188 from openqj/feat-screencast-full-fps
...
perf: screencast 隔帧改每帧,跟手优先
2026-10-30 13:58:35 +08:00
host
fafc0734c7
perf: screencast 隔帧改每帧,跟手优先
...
Page.startScreencast everyNthFrame 2 -> 1,画质 q60、尺寸
1280x800 不动。静态页不产生额外成本(帧只在重绘时来,
且 #187 起桥只写变化的帧字节);收益全部落在真正需要跟
手的时候:滚动、拖拽、动画期间帧率翻倍。测试断言同步。
2026-10-30 13:50:18 +08:00
openqj
305e3b20bc
Merge pull request #187 from openqj/feat-bridge-perf
...
perf: 桥变化才写、stdin 优先、stream 50ms 轮询
2026-10-30 13:43:34 +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
openqj
e9370d7291
Merge pull request #185 from openqj/feat-browser-stream-first-frame
...
fix: navigate 后立即推一帧,静态页开流不再等重绘
2026-10-30 13:22:48 +08:00
host
2d840a6c37
fix: navigate 后立即推一帧,静态页开流不再等重绘
...
screencast 帧只在重绘时来,页面可能在 startScreencast 之前
就已画好——静态页于是开流后一直无画面,直到下一次重绘。
navigate 后用 CDP captureScreenshot 抓一张当前视口塞进帧
队列,泵在下一轮就把桥帧文件写出来;泵跳过空 session 的
ack(eager 帧没有可确认的 screencast 帧)。失败静默,
screencast 本身仍照常流动。
2026-10-30 13:14:38 +08:00
openqj
b844624c96
Merge pull request #176 from openqj/feat-console-task-request-count
...
feat: 任务详情 LLM 请求数(cost_records 存 completions)
2026-10-30 13:05:30 +08:00
host
ccb5a8638d
feat: 任务详情 LLM 请求数(cost_records 存 completions)
2026-10-30 12:58:41 +08:00
openqj
ad4384a08e
Merge pull request #184 from openqj/feat-mcp-stdin-starve-main
...
fix: MCP 主循环 stdin 批量行饥饿
2026-10-30 12:55:31 +08:00
host
f85de63120
fix: MCP 主循环 stdin 批量行饥饿
...
select + buffered readline 会丢批量到达的行:一行 readline
可能把多行一起读进用户态 buffer,之后 select 再也看不到
空 fd,buffer 里的行永远不被读。客户端在 initialize 后
习惯把 notification + 下一请求连写,MCP 于是只答 initialize
就卡死(生产 2ff8975 活体验证两跑复现,faulthandler 证实
主线程停在 select)。改用非阻塞 fd + 自有 buffer 的行泵,
每行按到达顺序必达;附带回归测试(批量行全达 + EOF 残行)。
2026-10-30 12:47:23 +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
openqj
0c1cfcee31
Merge pull request #179 from openqj/feat-goal-convert-port
...
goal-convert / automation-create 移植:/goal 转换链 + 会话内标记工具
2026-10-30 07:28:45 +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
openqj
3a5c5db9fb
Merge pull request #182 from openqj/feat-browser-panel
...
feat: 控制台浏览器远控面板
2026-10-30 07:11:25 +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
openqj
80b32f25b3
Merge pull request #181 from openqj/feat-browser-phase2
...
feat: 浏览器二期后端:远控服务 + ref 快照 + server 代理
2026-10-30 06:51:20 +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
openqj
7bea8df512
Merge pull request #180 from openqj/feat-browser-phase1
...
feat: 浏览器一期:坐标点击 + live 截图
2026-10-30 06:27:46 +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
openqj
872b23a296
Merge pull request #175 from openqj/feat-project-memory-reuse
...
feat: 经验复用 MCP 暴露(项目记忆列/建/废弃)
2026-10-30 05:13:26 +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
openqj
903098de09
Merge pull request #171 from openqj/feat-cloud-mcp-more2
...
feat: 云端 MCP 工具 12→20
2026-10-30 05:00:50 +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
host
c168304418
feat: /metrics 扩队列深度/worker 聚合/分模型成本/未定价占比/近24h失败
2026-10-30 04:15:54 +08:00
host
b71cff5ee2
feat: 云端 MCP 工具 12→20(pause/goal-resume/followup/agents/workers/metrics/members/models)
2026-10-30 04:15:16 +08:00
openqj
0787496427
Merge pull request #170 from openqj/feat-image-edit-mcp
...
feat: 图片改图 MCP 工具 image_edit
2026-10-30 04:12:46 +08:00