host
8fc4e27241
feat: GitHub App manifest 全量获取:仓库/组织/企业/账号四类最高档
...
接上轮仓库最大权限:用户明确要求无论什么身份,取该身份
授权范围内的所有权限。manifest 现按四类全拉满(74 项权限、
39 个事件):仓库补 codespaces_lifecycle_admin、repository_
creation、metadata 只读;组织 members 升 write 并补
organization_administration 等 15 项;企业补 8 项;账号补
blocking、email_addresses、gists、密钥类等 22 项。
身份边界写进注释:GitHub 只授予安装身份能给的那部分,个人
装不上组织/企业、企业装不上仓库/组织;换 token 不传子集,
token 本就是安装全量;企业安装另需 App 公开/内部
(GITHUB_APP_PUBLIC=1)。诚实边界:企业类键名未用真实
GitHub 建 App 实测,新建时表单会校验,某键被拒删键再建,
线上旧 App 不受影响。
2026-10-30 02:53:46 +08:00
host
668c000394
feat: GitHub App manifest 扩到主机最大权限
...
仓库权限除 metadata 外全部拉到最高档(contents/pull_requests/
issues/actions/checks/workflows/administration 等全部 write,
members 只读),事件补齐 push/check_run/workflow_run 等;
旧权限 contents/pull_requests write + issues read 不再是上限。
风险明示:administration=write 含删库/转移,secrets=write
含管理 secret,配 All repositories 时影响面为全账号仓库。
注意:改代码只改以后新建 App 的 manifest,线上 App
(id 5476837) 仍需在 GitHub 设置里改权限并接受新权限。
2026-10-30 02:53:46 +08:00
openqj
4bbe6a99e3
Merge pull request #164 from openqj/feat-cloud-mcp-more
...
feat(mcp): 云端 MCP 工具从 8 个扩到 12 个
2026-10-30 02:47:36 +08:00
openqj
367b9d8873
Merge pull request #161 from openqj/feat-automation-audit-pg
...
fix(automations): 审计行不再显式插 TEXT id,PG identity 下不再丢审计
2026-10-30 02:47:28 +08:00
openqj
276d433da6
Merge pull request #166 from openqj/feat-console-pagination-tabs
...
console: 任务列表服务端分页 + 控制台分页面签
2026-10-30 02:38:35 +08:00
host
e5b6c45c83
console: 任务列表服务端分页 + 控制台分页面签
...
任务列表分页(服务端 + 前端):
- GET /tasks 新增 limit(1..100,非法回 400)、offset、
order=desc、status/executor/q 服务端过滤;回 total(过滤后
计数)与 status_counts(全项目统计,不受过滤与分页影响,
数据卡片不再把当前页当成全项目);无 limit 时旧行为不变
(全量、正序,协调子任务与旧调用不受影响)。
- 前端每页 20 条、最新在前,上一页/下一页 + 页码;筛选与
搜索改服务端过滤(搜索防抖 300ms),切筛选/切项目/派发
后回第 1 页,10 秒刷新与刷新按钮停在当前页;新测试
test_task_list_pagination.py 5 项。
分页面签:
- 顶栏锚点导航改成 5 个页签:工作台(派发 + 任务列表 +
对话 + 详情)、项目(项目 + 成员)、环境与 Workers、
技能与自动化(技能 + 自动化 + 分诊)、管理与 Key;
数据卡片仍在页签上方常驻。选中任务存在 App 层 store
里,切页不丢,回来仍是同一任务、10 秒刷新续同步;
页签同步到 location.hash(#tab-workbench 等),刷新与
分享链接落在同一页签;窄屏工作台仍保持派发在前的顺序。
- 工作台页签仍是左(任务)右(派发/对话/详情)两栏,
沿用等高内部滚动规则;其它页签单列堆叠。
2026-10-30 02:25:48 +08:00
openqj
6a5a837aac
Merge pull request #165 from openqj/feat-doc-tools-result-cap
...
文档/图片工具进任务镜像 + 结果截断改为提取 text 上限 20000 字
2026-10-30 02:19:46 +08:00
host
c1d25d11b1
feat: 文档/图片工具进任务镜像 + 结果截断从截断 JSON 改为提取 text 上限 20000 字
2026-10-30 02:03:14 +08:00
host
d5a602f7d3
feat(mcp): 云端 MCP 工具从 8 个扩到 12 个
...
#159 只包了读 + 建 + 取消,日常闭环还缺:读产物文件、
读完整结果、重试、合并。新增 get_task_files(path 为
worktree 内相对路径,服务端 _safe_worktree_path 防逃逸,
MCP 层不展开绝对路径)、get_task_result_full(依赖 #162
的 /result-full 端点,未部署前该工具回 404 isError,不炸)、
retry_task、merge_task(写操作,服务端状态机校验,非法
转换 409 原样透传,MCP 层不绕过)。
单测 test_mcp_server 10 项(含新增翻译 1 项)。
2026-10-30 02:00:58 +08:00
host
8afcd3253e
fix(automations): 审计行不再显式插 TEXT id,PG identity 下不再丢审计
...
旧 _audit_row 显式插 uuid 当 audit_log.id:SQLite 下能跑,
生产 PG 的 id 是 BIGINT GENERATED BY DEFAULT AS IDENTITY,
插 TEXT 直接报错、审计行全丢(best-effort 吞掉后无声无息,
#156 留下的已知局限)。修法:INSERT 一律不带 id,让两端
自增/identity 生成;表不存在时先按 PG 口径建、再按 SQLite
口径建、逐个重试——automations 按设计不 import 其它 cloud
模块,所以用先插、失败再按口径重试做方言探测。
单测:test_automation_run_due 4 项(含新增 PG-like 假连接
1 项:只接受不带 id 的 INSERT,旧实现在此应失败)。
2026-10-30 01:55:59 +08:00
openqj
9a11ef27b8
Merge pull request #159 from openqj/feat-cloud-mcp-server
...
feat(cloud): MCP 云端任务入口 + 上游 0.164 对齐配置
2026-10-30 01:55:43 +08:00
openqj
0c458cb2ce
Merge pull request #158 from openqj/feat-repo-access-check
...
feat(repos): 仓库接入预检 + codexsvc deploy key 配给脚本
2026-10-30 01:53:52 +08:00
openqj
aa5bf7da72
Merge pull request #157 from openqj/feat-final-audit-detail
...
fix(worker): 终态审计带上 error,复发卡死可定位
2026-10-30 01:53:39 +08:00
openqj
8d8774edee
Merge pull request #160 from openqj/feat-console-single-chat
...
console: 对话只留一处实时单列;任务列表与 API Key 加滚动上限、三栏等高
2026-10-30 01:52:45 +08:00
host
972203c38f
feat(cloud): MCP 云端任务入口 + 上游 0.164 对齐配置
...
- cloud/mcp_server.py:stdio MCP 服务,把云端任务 REST 翻成
tools/list / tools/call(health、list_projects、list_tasks、
get_task、create_task、cancel_task、get_task_cost、
get_task_trace),底层只走已有 REST,不另开任务逻辑;
鉴权只认调用方自己的 CODEX_CLOUD_API_KEY(缺了启动失败,
绝不打印),服务端权限 403 原样透传;create_task 只传已知
字段,未知字段丢弃;REST 报错时 isError=true。
单测 test_mcp_server 9 项(假 transport,不联网、不碰真 key)。
- 上游对齐 #80 的可合部分:config.example.toml 加
[features] daemon_auto_start = false(防 managed daemon 绕过
版本 pin)+ docs/upstream-164-alignment.md 对齐表;换稳定版
二进制是另一次主机侧部署动作,本批不做、不谎称已升级。
2026-10-30 01:41:34 +08:00
host
41c2b0ab2f
console: 任务列表与 API Key 加滚动上限,左中右栏等高
...
任务列表与 Key 列表此前无高度上限:任务一多就把整栏
(乃至整页)撑到无限高,左中右栏又因 align-items:start
各按内容高度结束,底部参差不齐。
改法(仅宽/中屏,窄屏 <900px 仍是单列页面滚动,不动):
- .issue-list 上限 60vh、内部纵向滚动,搜索/筛选栏在
列表外、滚动时仍可见;.api-key-list 上限 320px、内部
滚动;两处均 overscroll-behavior:contain,不让列表
滚动直接拖动整页。
- 三栏固定为同一高度:calc(100vh - 260px)(减顶栏、
数据卡片与页面边距),下限 480px,超出的部分各栏
自己内部滚动;网格 align-items 改为 stretch。
2026-10-30 01:40:57 +08:00
host
c192c5dec8
console: 对话只保留一处实时单列(ChatGPT 式)
...
根因:ConversationSection 同时渲染 TracePanel(prompt +
全部链路条目)和 ContinuePanel(GET /chat-history,
服务端已把 prompt + 继续 + 后续 + 全部链路种类按时间
合并、并去掉了后续消息回声),简单任务的两份名单
显示同一组用户 + 助手卡片,看起来就是对话重复。
改法:删 TracePanel 名单,只留 ContinuePanel 这一列;
TracePanel 唯一不重复的控件(链路类型筛选、下载完整
链路)移到这一列顶部,筛选只过滤链路消息、用户消息
恒保留;实时性不丢:基础是 10 秒轮询的 chat-history,
SSE 新链路条目按 id 去重合并进来,轮询拿到后不再
重复;无 chat-history 的旧服务端回退路径也改成渲染
全部链路种类(不再只渲染 message),并跳过 fu- 回声。
2026-10-30 01:40:20 +08:00
openqj
9ac0199eba
Merge pull request #156 from openqj/feat-cross-worker-kill
...
feat: 跨 worker 真 kill(kill_requests 意图表 + 收殓器)与自动化触发入闸
2026-10-30 01:40:05 +08:00
host
1ff8906aee
feat(repos): 仓库接入预检 + codexsvc deploy key 配给脚本
...
本机 https 到 GitHub 常被出口策略挡、ssh 才通(2026-10-30
实测),而新项目填 https 私有仓会在 worker 里花几分钟超时
才失败。控制面不存仓库凭证的设计不动,缺的是建项目前的
快速预检与按仓库通用化的配 key 流程:
- cloud.repos.check_repo_access:只跑 git ls-remote HEAD,
不 clone、不写盘、不改库;失败返回 (False, 原因),https
失败时追加改走 git@ 形的提示;CLI python3 -m cloud.repos
check <url>,退出码 0/1,只打印结果与原因。
- deploy/provision_codexsvc_key.sh:主机上以 root 跑,为
codexsvc 生成/复用 ed25519 key(绝不覆盖已有 key),只
打印公钥(私钥绝不打印),--check 时以 codexsvc 身份跑
ls-remote,通了才算配好。
- 内层沙箱边界诚实说明:Docker 任务内层本就是
danger-full-access(见 sandbox.py 注释),外层 Docker/gVisor
才是防线;宿主级 bwrap workspace-write 的 fresh proc 在嵌套
pidns 下是内核 EPERM、/tmp 不隔离——这些是上游 codex 二进制
与内核的边界,本批不谎称在仓库代码里修掉,只把仓库接入
这一档做成可重复流程。
单测:test_project_repo 20 项全过(新增 check 5 项)。
2026-10-30 01:39:46 +08:00
host
f4fb4000e1
fix(worker): 终态审计带上 error,复发卡死可定位
...
2026-10-29 任务 A:认领后 61 秒 interrupted,但终态审计只记
task_id、自动续跑又把 error_text 覆盖掉,事后无法区分取消、
配额、host 返回 interrupted 还是其它失败;容器 --rm 后日志
也没了,根因至今无法从留存证据证明(不是 sweep:阈值 300
秒;不是外部取消:该时段无取消审计;是 worker 自己写回
interrupted,但第一轮的 error 已被第二轮 failed 覆盖)。
本批不谎称找到根因,只补可定位性:run_one 终态审计在
interrupted/failed 时 detail 带 error(截 500 字、去换行),
完成态仍只记 task_id;分段审计 worker_exec_start/error/done
已在现 main,复发时最后一段 + 终态 error 即能定位。
单测 test_final_audit_detail_carries_error:失败派发后
worker_failed 审计 detail 以 'A:' 开头且含 error 文本。
2026-10-30 01:38:01 +08:00
host
3a06205d8b
feat: 跨 worker 真 kill(kill_requests 意图表 + 收殓器)与自动化触发入闸
...
机制 A 移植自旧 PR #101(分支 feat-residual-b,头 895e004),
不合旧 PR:旧基线 6e3eb7b 已 CONFLICTING,本批重做到现 main
6d4f87e(#151 合并后)上。
- kill_requests 意图表:cloud/db.py POSTGRES_SCHEMA + migrations
清单补表;server.ensure_kill_requests_table / request_kill
(同一任务只留一条 pending,写失败返回 False);init_db 的
SQLite 分支补建表(PG 分支由 POSTGRES_SCHEMA 全量建表覆盖)。
- 取消/sweep 写请求 best-effort:_cancel_task 在 commit 后调
request_kill(失败不挡取消);sweep_stale_tasks 在同一事务
内为被扫任务写 system 请求。
- worker 收殓器 _reap_kill_requests:owner 活着(心跳停滞未超
300 秒,COALESCE(last_heartbeat, updated_at))绝不抢杀;只
有 owner 已死且任务仍 interrupted 时,按任务派生容器名
(executor.container_name,codex-<安全字符任务 id>)在本机
真杀,绝不按前缀扫、绝不杀自由传入的名字;本机无容器时
请求照常终结;任务行失踪或已不在 interrupted 时请求直接
终结;单条异常只记日志。run loop 每轮调一次,放在 sweep
块外(旧 PR 只在 sweep 块内,sweep 关掉时请求会积压)。
- 自动化入闸只补两条旁路:worker._coord_sync_children 建子任
务前过 _quota_exceeded(超限跳过建任务、记审计,同一 worker
内同一分工只记一次);automations.run_due_automation
(claim 抢单 -> 配额门 -> 建任务 -> 记产出,超限记
skipped_quota 不进失败重试)。triage/webhook/续跑/后续/
分叉未动。
- 单测:旧 PR 三份单测原样移植(Worker/Server 签名与现 main
兼容,未改用例语义)。
2026-10-30 01:32:35 +08:00
openqj
b306b56517
Merge pull request #155 from openqj/feat-chatgpt-codex-align1
...
ChatGPT Codex 对齐:技能包 + 租户播种 + web_search Docker 联网修法
2026-10-30 01:29:47 +08:00
openqj
3c80d277b0
Merge pull request #154 from openqj/feat-console-detail-cards
...
console: 任务详情改卡片式排版
2026-10-30 01:24:54 +08:00
host
6aa4b45f2c
align: 记白名单后端到端全绿结论
...
- 白名单 6 域名已同步主机并 reload,curl 验 3 个 200、
time.is 仍 403、worldtimeapi 站侧 TLS 失败(timeapi 兜底)。
- 全新项目任务 6a267baf:web_search 6/6、web_fetch 1/4
成功(weather.com.cn),答案报出上海时间与北京晴
5°C、风力 3 级以下,带来源与快照时间,未编造高低温。
- 诚实边界:时间来自系统时钟 + UTC+8 换算,非 timeapi
fetch;天气来自 fetch 成功的一级来源页。
清理已核,用户剩余 0,生产 health fd9fe5f。
2026-10-30 01:16:49 +08:00
host
1dc2f7dc21
egress: 白名单加一级时间/天气域名,供 live-info fetch 核数
...
2026-10-30 端到端再测:web_search 已通,但 web_fetch
4 次全败于 Tinyproxy 403 Filtered——模型要 fetch 的
一级来源域名都不在白名单里,搜索摘要又无可靠数字,
故按技能规则未报数字。加:worldtimeapi.org、timeapi.io
(时间 API)、open-meteo.com(免费天气 API,无 key)、
weather.com.cn(中国气象局英文站)、meteoblue.com、
accuweather.com(搜索结果里的天气一级来源)。
刻意不加 time.is/time.org.cn/time.ms(次级时间站)与
任何新闻/社交域名,白名单仍 fail-closed。
主机 /etc/tinyproxy/tinyproxy-filter 须同步此文件并
reload tinyproxy 才能生效,仓库文件是下次部署不被
revert 的依据。
2026-10-30 01:16:49 +08:00
host
84c79302d7
align: 记 MCP env 根因与端到端再测结论
...
- MCP 子进程不继承 Codex env,docker -e 无用,env 须
写 config;手动加 env 后 web_search 立刻成功,代码
修法 dc9b29e 已落地并经全新项目验证(config 自动
写进 MCP env,web_search 5/6 成功)。
- 端到端仍未报出数字:web_fetch 4 次全败于 Tinyproxy
403 Filtered,一级来源域名不在 egress 白名单里;
下一层是主机白名单变更,另等用户定,非代码。
清理已核,用户剩余 0,生产 health fd9fe5f。
2026-10-30 01:16:49 +08:00
host
71e31b22a0
websearch: MCP env 写进租户 config,不只靠 docker -e
...
2026-10-30 实测:Codex bash 里有 SEARXNG_URL + proxy,
MCP 链却只有 duckduckgo、DNS 瞬间失败——Codex 的 MCP
子进程不继承 Codex 进程 env;给租户 config 加
[mcp_servers.websearch.env] 后同一任务立刻返回真实
SearXNG 结果。修法:worker 在 _docker_task_context
算出网关后、容器启动前,用 ensure_websearch_mcp_env
把 proxy + 搜索 env 写进租户 config(网关此时才已知,
播种时写不死;写失败只记日志不阻塞)。
测试:新增 test_websearch_mcp_env 4 项,相关共 33 项全过。
2026-10-30 01:16:49 +08:00
host
08d56b15ce
websearch: SearXNG 默认只查 bing,360search
...
默认 general 类别在 Docker 任务容器里要 20.0 秒才回
(wikipedia/wikidata/brave/duckduckgo/google 引擎全超时,
只有 bing+360search 回),撞 MCP 默认 20 秒超时;随后
DuckDuckGo 经代理也超时,整条链失败。代理本身无问题
(Tinyproxy 白名单早已放行 searx 与 duckduckgo)。
修法:_provider_searxng 默认 engines=bing,360search,
SEARXNG_ENGINES 可覆盖、空值恢复旧行为;worker 搜索
env 透传补 SEARXNG_ENGINES。容器实测:钉住后 0.26 秒
回 3 条(首条北京天气),auto 链 0.15 秒成功;旧 20.0 秒。
测试:新增 test_websearch_searxng 3 项,MCP/worker 共
21 项全过。生产未部署。
2026-10-30 01:16:49 +08:00
host
79cc59e72e
align: 记真实任务实测:技能在 Docker 任务里被发现并读取
...
2026-10-30 临时 worker 实测(生产未部署):
- 隔离:depends_on 假依赖门 + run_one 单任务,生产
worker 永不认领,临时 worker 只跑指定任务。
- 第一次失败:GitHub clone 卡 684K 6 分钟 + run_one
无心跳线程,300 秒被 sweep 标 interrupted,播种未跑到。
- 第二次成功(test-repo 项目 + 心跳线程):任务
7235de8f completed,租户 skills/ 含 3 个 SKILL.md,
trace 里 agent 真读了容器内 live-info/SKILL.md,
答案按技能规则明说 web_search 不可用、不编造数字。
- 独立未解:Docker 里 web_search 本身 DNS/联网失败,
与 2026-10-28 探针同类,另批再修,不在本批宣称内。
清理已核:临时用户/项目/任务/租户目录/临时代码全删,
生产 health 仍 3696dad、worker_ok。
2026-10-30 01:16:49 +08:00
host
378cddfb1e
align: 修正技能播种路径:codex-home/skills/ 才是用户技能目录
...
2026-10-30 主机实测(临时 codex-home,生产未动)纠正:
先播 .agents/skills/ 时 skills/list 只返回 5 个系统技能,
3 个自有技能一个没出现;改播 skills/ 后返回 8 个,
3 个自有技能以 scope=user 出现。系统技能本身就在
skills/.system/ 下。
- skill_seed DEST_SUBDIR 由 .agents/skills 改为 skills,
模块文档与 worker 注释同步修正。
- 测试期望路径同步改为 skills/。
- 对照表补实测结论与附带发现:Codex 自带系统技能
imagegen,图片生成在 Codex 本体里不是无技能。
验证:skill_seed + chatgpt skills + websearch worker
共 14 项全过。主机探针文件已全部清理,生产未动。
2026-10-30 01:16:49 +08:00
host
cf9d17f035
align: 第二批:把技能包播种进租户 codex-home
...
仿 websearch MCP 播种,默认关:
- cloud/skill_seed.py:cloud/skills/ 的 SKILL.md 拷进租户
codex-home/.agents/skills/(个人级技能路径,见模块
文档的路径依据与诚实边界);幂等,租户改过的文件
绝不覆盖(上报 differs),缺包不阻塞任务。
- cloud/worker.py:新增 --seed-skills,_tenant_dirs 里
调用播种;老租户下一次任务自动合并;播种失败只记
日志、不阻塞任务(技能是可选流程说明)。
- cloud/tests/test_skill_seed_worker.py:播种助手 + worker
开关,仿 test_websearch_worker.py 的结构。
- docs/chatgpt-codex-alignment.md:补第二批说明与实测
待办(真实 Docker 任务 skills/list + $live-info 调用,
通过前不宣称生产任务已能用这些技能)。
验证:skill_seed + chatgpt skills + websearch worker
共 14 项全过。本批不改生产配置、不部署,autoscaler
加 --seed-skills 是部署时另行的主机步骤。
2026-10-30 01:16:49 +08:00
host
8a26d1973c
align: ChatGPT Codex 对齐第一批:技能包 + 对照表
...
对照用户提供的 ChatGPT Codex 工具目录,区分可对齐与
不照搬:核心编程工作流已对齐,ChatGPT 托管专属
(CUA、宠物、Docs/Sites 连接器、图片生成模型)不在
开源宿主编排层范围,不凭空宣称对齐。
第一批只补技能层,不改 worker、不改生产行为:
- cloud/skills/live-info:天气/时区/股票/体育,查一级
来源、带来源和快照时间,绝不编数字。
- cloud/skills/document-tools:LaTeX/Word/PDF/表格/
演示文稿,先核查工具、缺了明说、产出后重读验证。
- cloud/skills/image-workflow:已有图片处理 + 生成工具
已配置时才生成,未配置时明说、绝不顶替。
- docs/chatgpt-codex-alignment.md:逐项对照表与不照搬
的诚实边界,方向为自动化编程任务平台。
- cloud/tests/test_chatgpt_codex_skills.py:校验技能
frontmatter、名字与目录一致、正文非空、无密钥占位。
验证:新测试 2 项全过。播种进租户 codex-home、 worker
改动、CUA/连接器/图片模型均不在本批,另行评审。
2026-10-30 01:16:49 +08:00
host
b60f4facbd
console: 任务详情改卡片式排版
...
只改排版,不改数据与操作:原来一整块 <br> 分隔的
信息行拆成卡片——概览(状态 + 耗时/token/成本三张
指标卡)、基本信息(键值网格)、prompt(单独一张
卡,长 prompt 不再挤在信息行末尾)、操作与结果、
协调子任务/子代理链路/评审队列/审批队列/发消息/
线程(各一张卡)。指标卡在窄的详情列里用
auto-fit 网格自动折成一列,不挤压;nav-detail
锚点保留在外层容器上。
2026-10-30 01:13:32 +08:00
openqj
6d4f87e286
Merge pull request #151 from openqj/feat-trace-truncation
...
trace: 标注被截断的链路消息,避免误读为模型未写完
2026-10-30 01:12:33 +08:00
host
ce85043a24
trace: 标注被截断的链路消息,避免误读为模型未写完
...
2026-10-29 实弹:468 字 final_answer 在链路里只剩前 300 字、
断在 fu 后,控制台照原样当助手回复展示,用户误以为模型
没写完。截断本身是设计(防链路文件写爆),缺的是标记。
- host.py _summarize_trace_item:agentMessage 超 300 字时
条目带 truncated=True,短消息不带,完整回复仍在任务
result_text 里,不在链路条目里。
- 控制台:TraceEntry 加 truncated 字段,mapTrace 与
traceLineText 在被截断的消息后标注“链路摘要已截断至
300 字,完整回复见右侧任务结果”,console.html 为构建产物同步。
- 单测:tests/test_host_trace.py 新增截断标记用例(468 字
截 300 字且带标记、短消息不带标记)。
验证:host 10 项、cloud test_task_trace 14 项全过;
React tsc+vite 构建通过,产物 322151 字节、含截断标注、
含 #150 的 total_tokens/首字/总耗时,无回退。
2026-10-30 01:01:50 +08:00
openqj
fd9fe5f254
Merge pull request #153 from openqj/feat-auth-unknown-role
...
fix(auth): unknown project role denies instead of KeyError 500
2026-10-30 00:55:54 +08:00
openqj
284e821d0c
Merge pull request #152 from openqj/feat-console-task-detail-meta
...
console: 任务详情显示首字、总耗时、token 与自动成本明细
2026-10-30 00:50:08 +08:00
host
c823e32336
fix(auth): unknown project role denies instead of KeyError 500
...
check_permission now returns False for roles not in _ROLE_LEVEL
(e.g. a directly-written 'member' row, which set_member itself
rejects but legacy/direct DB rows can still carry), so the failure
mode is PermissionError/403, never an unhandled 500. Regression test
test_unknown_role_denied_not_500 fails with KeyError on old code.
2026-10-30 00:49:03 +08:00
host
994c4ea5d1
console: 任务详情自动显示成本明细
...
打开详情就自动拉 GET /tasks/{id}/cost(不再只靠
“查成本”按钮出 JSON),详情顶部新一行:美元、总
token(实际/估算、缓存、无价单列)、轮数、fallback
次数;美元小于 1 美分时用 4 位小数,避免小任务
显示成 $0.00 误导成免费;加载中/失败有各自的
弱化文案,成本拉失败不影响详情其它内容;原
“查成本”按钮不动,仍可手动拉原始 JSON。
服务端不用改:成本接口与 _get_task 的 token 聚合
都已在 #150 / 详情 meta 那单里就位。
2026-10-30 00:39:13 +08:00
host
0f7162934b
console: 任务详情也显示首字、总耗时、token
...
列表行与详情共用同一口径:新抽 api/taskMeta.ts(首字/
总耗时/token 计算),TaskListSection 改 import 它(逻辑
原样不动),TaskDetailPanel 在状态行下方加一行:首字
方块 + 耗时 + token,title 里写口径。
详情的数据缺口一并补上:单任务接口 _get_task 此前走
_task_to_dict 默认 total_tokens=None,详情 token 只能
显示占位;现与列表一样用 _task_tokens_map 一次聚合
(单任务只多一条查询),详情直接出真数。
types.ts 里过期的“列表不回 token”注释同步更新。
新测试:单任务 GET /tasks/{id} 聚合回 total_tokens。
2026-10-30 00:39:13 +08:00
openqj
3696dad7c8
Merge pull request #146 from openqj/feat-task-files-tenant
...
fix: task files endpoint resolves tenant docker worktrees
2026-10-30 00:04:37 +08:00
host
4cbdc41e20
fix: task files endpoint resolves tenant docker worktrees
...
GET /tasks/{id}/files previously returned 409 for all docker tasks
on the grounds that tenant docker shares /app/work per project.
Production inspection shows the worker creates a per-task
host-worktrees/<task-id> subdirectory under the tenant work dir
(62 such dirs under the wwww tenant), so per-task reads are
attributable after all: the endpoint now resolves tenant docker
tasks via tenants/<project>/work/host-worktrees/<task-id> (local
worktree as fallback), never serves the shared /app/work mount
itself, and still 409s cloud/cross-host tasks. Docs and the
harness2_tasks boundary notes are updated to match.
2026-10-29 23:16:01 +08:00
openqj
d4a517fc7e
Merge pull request #150 from openqj/feat-console-task-meta
...
console: 任务列表行显示首字、总耗时、token(服务端列表补 total_tokens)
2026-10-29 18:38:36 +08:00
host
9eedee5a3d
server: 任务列表一次聚合回 total_tokens
...
_list_tasks 在取附件的同时用 _task_tokens_map 一次查
cost_records 按 task_id 求和(GROUP BY),一屏只多一条
查询,不按任务逐个调成本接口。无记录计 0、表不存在时
全计 0 且列表不失败;_task_to_dict 新增 total_tokens
参数,默认 None(非列表调用方不把“未算”写成 0)。
前端 TaskListSection 的 token 栏位此前已接好 total_tokens,
补上后列表行直接显示真数,不再显示 token —;前端注释
与占位文案同步更新。
新测试 test_task_list_tokens.py 3 项:HTTP 列表聚合
(actual+estimated 加总、无记录为 0)、缺表不炸、
_task_to_dict 默认 None。
2026-10-29 18:27:53 +08:00
host
65a875ada9
console: 任务列表行显示首字、总耗时、token 栏位
...
任务列表每一行新增三项(筛选、搜索、选中高亮、状态点不动):
- 首字:行前小方块,prompt 第一个非空白字符(按码点取),
无 prompt 时用任务 id 首字符兜底;原 prompt 文案不动。
- 总耗时:只用列表已回时间戳算。终态用 finished_at -
started_at(与服务端 avg_duration_seconds 同口径);running
显示“进行中 + 已用时长”,随列表刷新更新;无 started_at
时用 created_at 兜底(含排队,title 注明口径)。格式:
3分12秒、1小时5分、1天1小时。
- token:栏位已接好,total_tokens 优先,actual +
estimated 分项加总次之;但列表接口 _task_to_dict 目前
不回任何 token 字段,单任务真数只在 GET /tasks/{id}/cost
里,所以当前显示“token —”,不编造、不逐个调 /cost
拖慢列表。服务端在列表里补 total_tokens 后本行自动出真数。
诚实边界:worker 每次认领重写 started_at,多轮续跑任务
的耗时是末次认领时长,不是历次之和;严格累计需服务端
保留首次 started_at 或累加各轮时长。token 的服务端缺口:
需在 _task_to_dict / 列表查询里按 task_id 聚合 cost_records
的 total_tokens,不需要新端点。
构建:npm run build(tsc + vite singlefile)0 退出,
dist/index.html 原样拷到 cloud/console.html,产物含
issue-first、耗时、token —,未动其它确认框。
2026-10-29 18:24:07 +08:00
openqj
e5bf361c6d
Merge pull request #149 from openqj/feat-no-full-confirm
...
console: 新建任务选完全访问不再弹确认框
2026-10-29 18:17:16 +08:00
host
6d9cd24553
console: 新建任务选完全访问不再弹确认框
...
DispatchSection 提交时删掉 full 的 window.confirm:下拉里
选 full 本身就是显式选择,提交直接送 approval,不再二次
确认。计划模式与 full 互斥的拦截不动,其它确认框(取消/
合并/提 PR 等)不动。
构建产物 cloud/console.html 由 npm run build(tsc + vite
singlefile)重新生成,产物里已无“确认提交吗”,仅剩下拉
选项本身的“完全访问”文案。
2026-10-29 18:06:18 +08:00
openqj
baf330f112
Merge pull request #148 from openqj/feat-console-goal-invincible
...
console: 增加 goal 模式无敌版勾选
2026-10-29 18:05:19 +08:00
host
7d400afa37
console: add goal-mode invincible option
...
DispatchSection gains a 'goal 模式无敌版' checkbox next to 'goal 模式':
checking it sends goal_mode=1 plus no_time_limit=1 (server already
accepts the field; the console just never exposed it). Plain goal
checkbox behavior is unchanged; invincible wins when both are
checked. Plan/coordinator mutual exclusion now covers invincible
too (it is a goal variant). TaskDetailPanel shows
'goal 模式无敌版(不限时)' when a task carries no_time_limit.
Help text states the honest boundary: worker/docker total timeouts
are lifted, the 600s single-turn host guard stays. Built with
npm run build (tsc+vite pass); console.html synced verbatim from
dist/index.html.
2026-10-29 17:58:50 +08:00
openqj
9961a251d1
Merge pull request #147 from openqj/feat-prestart-goal-logs
...
worker: 补漏:goal 路径的 docker 分段日志 + 审计任务 id
2026-10-29 17:52:30 +08:00