## 0.0.520 (2026-11-11) ### 后端 - **钉钉进度卡正文上限从 1500 提到 6000**:状态行、回复和本轮工具列表仍拼在同一个 `body` 里,整段超过 6000 字符才截断,与飞书进度卡正文上限一致。实时进度卡和定时任务结果卡都走这一段。 - **修复钉钉会话的定时任务跑完后结果不推回钉钉**:定时任务收尾此前只把最终回复推回微信和飞书。在钉钉私聊或群里创建的任务会照常执行,回复只留在会话里,钉钉对话看不到。现与飞书对齐:直跑、「立即执行」,以及没有进度卡的失败会话恢复,成功后都把最终回复推回原钉钉会话。机器人配了进度卡模板时发一张「处理完成」卡(不写入执行中的进度卡映射,避免崩溃恢复把这张通知刷成「正在恢复」);没有模板或卡片投放失败时改发 markdown。引用标记在推送前剥离。失败和取消不推。 ### 桌面 Electron - **修复 LOCAL 任务粘贴超长文本后发送报「写入失败」并取消发送**:粘贴 ≥2000 字会转成 `pasted-text-N.txt`,发送时由主进程写入 `~/.mao/attachments/`。写盘本身成功,但 IPC 回的是工具协议 `{ success, path }`,渲染层只认与普通附件拷贝相同的 `{ ok, absolutePath }`,于是把成功当成失败(提示「文件 pasted-text-N.txt 写入失败」),附件全部失败后整单取消。现将该入口的返回改回 `{ ok, absolutePath }` / `{ ok: false, error }`;`dump_user_messages` 委托仍走工具协议,不受影响。同名粘贴仍追加 `-1` 副本,不覆盖已有附件。 ### 管理后台 - **用量分析「用户用量明细」去掉账号、消息、最后登录三列**:表格和 CSV 都不再带这三列。用户名仍在「用户」列(无显示名时回落账号);消息数仍用于上方「用户活跃排行」。 - **用量分析「用户用量明细」操作列两个链接拉开间距**:「调用流水」和「用量详情」原先紧贴成一整段,现中间留 12px,列宽同步加宽以免折行。 - **容器管理列表支持筛选和分页**:可按关键词(用户 / Agent / 容器名,纯数字按用户 ID 或 Agent ID 精确匹配)、运行状态、在册与否、是否有任务筛选,每页 10 / 20 / 50 / 100 条,默认 20 条、第一页。筛选和翻页都在已取回的列表上完成。有筛选时按钮变为「重建筛选结果」,处理的是筛选后的全部容器,而不是只处理当前页。 - **容器管理列表的用户、Agent 列改为名称**:用户列优先显示「显示名称」,否则显示用户名;Agent 列显示 Agent 名称。用户或 Agent 已删除、或名称字段为空时回落 `#ID`。单行重建 / 删除确认,以及「重建全部」的失败明细,同步改用名称。 - **用户详情「用量」Tab 拉开卡片的垂直间距**:总账卡、趋势图、按模型 / 场景 / Agent 三列这几块上下原先贴在一起,现改为 16px;左右间距仍为 12px。窄屏折行时,总账卡行与三列卡片的行距同样为 16px。 - **用户详情「用量」总 Token 卡改用 K / M / B 缩写**:总 Token 及输入、输出、缓存改为与用量分析相同的 `formatTokens`,固定两位小数(如 2,713,315,304 → 2.71B)。 ## 0.0.520 (2026-11-11) ### 管理后台 - **修复在线设备页设备 ID 点不了复制**:设备 ID 列开了表格溢出提示,列宽不够时 ID 和「复制」被收进提示里的纯文本(悬停能看见「复制」,但那不是按钮,点不到;真正的按钮被裁在单元格外面)。现改为 ID 自身省略、悬停只展示完整 ID,「复制」按钮固定留在单元格内;点击 ID 或「复制」都会写入剪贴板。 ## 0.0.519 (2026-11-11) ### 前端(桌面 / Web / 安卓) - **修复部署重启续跑后任务停在半截、看不到最终回复(刷新页面才恢复)**:蓝绿切换时旧执行被新执行顶掉,旧流式气泡被打上「中断」标记;终态重拉历史时它被当成服务端未落库的唯一副本保留,并统一追加在 REST 消息之后。轮次渲染取最后一条 assistant 作为最终回复,于是界面停在部署前那半截内容,真正的最终回复反而被折叠进「已执行 N 个步骤」。现区分「用户中止」(服务端不落库,气泡是唯一副本,必须保留)与「被新执行顶掉」(内容会由续跑重新产出),后者在终态重拉时不再保留;边路任务 / 子代理面板在终态也不再生效「保留本地流式气泡」的判定。 ### 后端 - **修复钉钉进度卡执行中不显示「取消任务」按钮**:按钮可见性原本写成「字符串变量 `status` `isEqual` `running`」,`editorData` 里条件完整、卡片平台也照原样保留,但平台生成的 `widgetInfo`(客户端真正渲染的那份)把条件抹成了空串 `@triple{'' , 'visible', 'gone'}`,条件位恒假,按钮永远是 `gone`。官方样例模板证实:卡片平台只把「boolean 变量 + isTrue/isFalse」渲染成可用的 `@data{...}` 条件。现改为由 `progressCardParams` 下发 `canCancel` / `canRetry` 两个 boolean 变量(`running` → `canCancel=true`,`failed` → `canRetry=true`,其余状态均为 `false`),模板按钮可见性相应改为 `isTrue(canCancel)` / `isTrue(canRetry)`。`status` 变量保留作语义占位。新增回归用例固化四种状态与两个 boolean 的对应关系。 ### mao-cli - 钉钉进度卡模板同步改用 boolean 变量控制按钮显隐(`canCancel` / `canRetry` + `isTrue`),并在说明里写明「字符串 `isEqual` 比较会被平台抹成空条件」这一约束与完整踩坑过程;自检脚本新增对应检查(可见性必须是 `isTrue()`、变量表必须声明该 boolean),已用修复前模板反向验证能报出全部问题。 ## 0.0.518 (2026-11-11) ### mao-cli - **修复钉钉进度卡「取消任务」按钮点了没反应、重试按钮点不动**:两个按钮各有缺陷,且都不在按钮可见性条件上——取消按钮的 `actionId` 是空的 `dynamicString`,点击后不上报 actionId,后端 `parseCardCallback` 取不到值、整个卡片回调分支不会触发,表现为「按钮看得见但点了没反应」;重试按钮的 `status` 是 `disabled`,渲染时置灰且不响应点击,表现为「重试按钮完全点不动」。现已把取消/重试的 `actionId` 补为字面量 `cancel` / `retry`,`status` 统一改为 `normal`。自检脚本新增这两类检查(`actionId` 空值、`status=disabled`),并同步订正模板说明:`widgetInfo` 只是平台导出时生成的渲染快照,导入后客户端渲染以 `editorData` 的组件树与变量条件为准(`useCustomWidgetInfo=false`),手改 XML 不生效。 ### 后端 - **修复定时任务 Spring cron 在「日 + 周」同时受限时按 OR 语义触发**:croner 默认 `legacyMode: true` 是 POSIX 的「日或周任一命中即触发」,与产品接受的 Spring/Quartz 方言(两者都满足才触发)相反。例如 `0 0 12 1 1 1` 本意是「1 月 1 日且为周一」(约四年一次),修复前会把 1 月每个周一都排进档期。现 5 处 Cron 构造统一使用同一组解析选项(`legacyMode: false`,时区不变),预览、下次档期计算、落库校验、补跑与调度器装载口径一致;`0 0 10 ? * MON-FRI` 等单方受限表达式行为不变。 ### agent-cli - **修复无 ripgrep 时 glob/grep 回退的路径匹配语义**:`**/` 现按「零个或多个目录」编译,`src/**/*.ts` 能命中 `src/a.ts`、`**/*.ts` 能命中根目录文件;同时去掉目录遍历里把带目录前缀 pattern 退化成全仓 basename 匹配的兜底,`src/**/*.ts` 不再命中 `docs/b.ts` 等越界文件。匹配前统一把相对路径转成 `/` 分隔,Windows 回退路径不再因反斜杠失配;结果输出仍保留平台路径形态。 ### 前端(桌面 / Web / 安卓) - **修复富文本粘贴转 Markdown 时表格单元格内的竖线撑破列结构**:turndown-plugin-gfm 原样输出 cell 文本,`a|b` 里的 `|` 会被 GFM 当成列分隔符,2 列表格渲染成 3 列、后续行整体串列。现覆盖表格 cell 规则,把单元格文本中的 `|` 转义为 `\|`,表头与表体一致处理。 ## 0.0.517 (2026-11-11) ### 前端(桌面 / Web / 安卓) - **修复暗色主题下「设置 → 服务器」状态卡变成一块白卡片**:该卡片底色误写成未定义令牌 `--aw-bg` 配亮色回退值 `#fbfbfc`,回退值恒生效,于是暗色主题下这块仍是近乎纯白的亮底,配暗色文字既刺眼又读不清(亮色主题下回退值恰好接近底色所以没暴露)。现改为随主题切换的 `--aw-canvas-parchment`(亮 `#f5f5f7` / 暗 `#222226`),在卡片内比卡面深/浅一档,边界清晰。配套新增 `ServerSettingsView.theme.test.ts` 源码守卫:组件引用的 `--aw-*` 令牌必须都已在 `style.css` 定义,避免再用「未定义令牌 + 亮色回退值」制造只在暗色档暴露的回归。 ## 0.0.516 (2026-11-11) ### mao-cli - **修复钉钉进度卡执行中不显示「取消任务」按钮,并删掉冗余的卡片标题**:按钮整个消失(连取消任务都没有)是因为 ButtonBlock 缺了区块级 `visible` 字段——同级 Markdown / DividerBlock 都有、唯独它没有,导致整个按钮区块不渲染,而非单个按钮的条件问题;现已按同级组件同样的结构补齐恒显示配置,单个按钮的显隐仍由各自的 `status` 条件决定。另外卡片顶部那行「正在处理」来自 `Card.cardName`(`${title}`),与正文首行「**状态:正在处理** · 第 1 轮」是同一信息出现两次,且 Grid 里还另有一个纯 `${title}` 的 BaseText;现已把 cardName 置空并移除该 Grid,标题信息只保留正文状态行一处。自检脚本同步补齐这两类检查(`${title}` 残留、ButtonBlock 缺 visible),已用修复前的模板验证能报出全部问题。 ## 0.0.515 (2026-11-11) ### 前端(桌面 / Web / 安卓) - **左右侧栏滚动条与对话区一致隐藏**:任务列表,以及右侧任务、文件、Git 页,内容仍可滚动,滚动条不再占位显示。 ## 0.0.514 (2026-11-11) ### 后端 - **修复 4 处跨平台生产缺陷**(前后端全量测试在 Windows 开发机跑查发现,Linux 部署行为不变):①electron 更新清单缓存排除正则只认 `/` 分隔符——`fastifyStatic` 的 setHeaders 拿到平台本地路径,Windows 部署下 `latest*.yml`/`releases/*.yml` 错误走 7 天强缓存(自动更新可能拿到陈旧清单),改为 `/` 与 `\` 双兼容;②容器运行时闭包 manifest 的文件键从 `path.relative` 改为强制 POSIX 分隔符——buildId 是容器代码漂移检测的事实源,Windows 构建机与 Linux 部署此前会产出不同 manifest;③`toWorkspaceRelative` 的工作区相对路径展示统一为 `/` 分隔(IM 图片保存提示等面向用户与 Agent 的文案,Windows 开发机不再出现反斜杠);④信号脚本探针超时击杀在 Windows(无负 pid 进程组语义)改为直接终止 leader——此前超时后探针进程无法回收、整条链路挂起 5s 超时。 ### agent-cli - **rg 路径归一修正**:Windows 下 rg 输出带 `.\` 前缀,grep/glob 结果路径剥掉该前缀后按平台形态透传(各消费方按平台 join 构造),Linux 输出恒等透传。测试基建:临时目录清理在 Windows 上遇句柄占用(git 子进程残留)降级为告警不淹没断言失败;若干 POSIX-only 语义用例(执行位恢复、0600 文件模式、bash 回退目录、进程组击杀)在 Windows 跳过。 ## 0.0.513 (2026-11-11) ### 前端(桌面 / Web) - **输入效率包:富文本粘贴转 Markdown 与截图轻标注**(方案 docs/plan/2026-11-10-rich-paste-annotate-technical-design.md,提案批次 28):①粘贴分流新增 text/html 分支——Word / 网页 / 飞书文档 / Excel 复制的富文本转为**等义 Markdown 源文本**插入输入框(标题/列表/粗斜体/链接/行内代码/代码块;Excel 区域含合并单元格按左上值展开成规整 GFM 表格、首行作表头),渲染层 MarkdownContent 正常渲染;turndown + turndown-plugin-gfm 动态加载(chunk 门禁加库内部字面量防进首屏包),converter 在 ChatInput setup 预热、粘贴时未就绪 / 超 512KB / 转换空一律回落现状纯文本兜底(无损降级);三条既有分流契约(图片文件化 / ≥2000 字符长文本文件化 / 快捷命令标记)保序不动。②图片轻标注——待发图片缩略卡新增「标注」按钮,全屏 canvas 编辑器(画笔 / 矩形 / 箭头 / 文字 / 马赛克 / 撤销,固定红色单线宽),操作栈重放实现撤销、底图只读零损伤,确认后替换该待发附件为 PNG(原图驻内存保留,可反复重标);图片发送通道(上传/LOCAL)零改动。零后端改动、零迁移;标注按钮在全部执行模式可用(图片发送通道无模式分支)。 ## 0.0.512 (2026-11-11) ### 前端(桌面 / Web) - **工具结果表格化视图:列表类结果一键转表格**(方案 docs/plan/2026-11-10-tool-result-table-view-technical-design.md,提案批次 28):`task_list` / `list_scheduled_tasks` / `list_signal_watchers` / `dump_user_messages` 及自定义 HTTP / MCP 工具返回的「列表形 JSON」结果,卡片结果区出现「表格 / 原文」切换(默认原文,与现状逐字节一致;按钮仅命中时出现)。判定从严:顶层数组或唯一数组字段包裹对象、元素全为扁平键值对象(值仅 string/number/boolean/null)才转表,嵌套值 / 多数组字段 / 空数组 / 超限一律保持原文——不设键名白名单(目标工具数组键 todos/tasks/watchers/files 与任意自定义包裹键同规则命中,误判防护靠唯一性 + 扁平性双闸)。表格复用中心 `TableGrid`(首行表头、数值列右对齐、200 行虚拟滚动),规模上限 201 行 × 30 列 / 1MB 文本;「复制为 CSV」按 RFC 4180 转义,粘贴进 Excel 行列同构;视图偏好按工具名存 localStorage(`aw-tool-result-view.*`,设备本地口径)。零后端改动、零迁移、零新依赖;解析输入为结果全文(后端摘要链不改写结果本体),表格态可呈现超过原文态 4000 字截断显示量的完整数据。 ## 0.0.511 (2026-11-11) ### 后端 - **管理后台新增「用户用量」视图接口**(方案 docs/plan/2026-11-10-admin-user-usage-product-design.md):新增 `GET /v1/admin/users/:id/usage/summary`(周期总账 + 按模型 / 场景 / Agent 分布)与 `GET /v1/admin/users/:id/usage/trends`(按天 / 小时分桶、后端补零),复用桌面端「我的用量」同一套服务方法(`summaryForUser` / `trendsForUser`),零新表零迁移、聚合走既有 `idx_llm_call_user_created` 索引。权限 `analytics:read`(与用量分析同语义,方案 D1);目标用户不存在 / 参数非法返回业务码 `USER_NOT_FOUND` / `PARAM_INVALID`(HTTP 200 Result 口径),自定义区间跨度上限 365 天(对齐桌面回溯口径,方案 D4)。连通性自检行(`connectivity_test`)`user_id` 恒为 NULL,单用户聚合结构上天然不含——与桌面 me/* 口径天然一致,无需排除参数(方案 §6.3)。周期与自定义区间解析沿用 me/* 语义(非法回落 last30、起止倒置交换),`summary/trends` 响应新增解析后的 `window`(起止日历日)供前端深链调用流水直接取用。用量契约(周期枚举 / 聚合行 / 响应壳)下沉 `@mao/contracts`(usage.ts),后端 re-export 保持既有 import 路径。 ### admin - **用户详情抽屉新增「用量」Tab**(方案 §5):位于「会话」之后,权限 `analytics:read` 门控(无权限整 Tab 不渲染);周期下拉(今日 / 昨日 / 本周 / 上周 / 本月 / 上月 / 近 7 天 / 近 30 天 / 自定义,默认近 30 天)+ 四张统计卡(总 Token / 总成本 / 调用次数与成功率 / 平均解码速度)+ 趋势双轴图(Token 左轴、调用次数右轴)+ 按模型 / 场景 / Agent 三块分布表;Tab 懒加载(首次激活才请求,不加重抽屉首开)。深链出口按钮按目标页权限二次门控:「查看调用流水」(`llm-call:read`,带周期日期直达)与「查看会话」(`session:read`)。用量分析页用户明细行新增「用量详情」反链(`/users?detail=&tab=usage`),用户列表解析深链打开抽屉并定位用量 Tab;场景名复用 `llmCallLabels` 汉化表。 ### 前端(桌面 / Web) - **用量类型契约收口**:桌面端手写的用量聚合类型(`UsageTotals` / `UsageModelRow` / `UsageSceneRow` / `UsageAgentRow` / `UsageTrendBucket` / `MyUsageSummary` / `MyUsageTrends` / 周期枚举等,api/index.ts 879-976 行)删除,改从 `@mao/contracts` 消费(`UsageTrendBucket` → `LlmCallTrendRow`、`UsageAgentRow` → `LlmCallAgentAggRow` 改名由编译期兜底);字段零变化、行为零变化。 ## 0.0.510 (2026-11-10) ### 后端 - **管理后台「容器管理」纳入 Docker 未在册残留容器**:此前列表只含当前后端进程在册的容器(注册表纯内存),后端重启 / 崩溃后遗留的 Docker 容器(优雅重启产生的 exited、异常残骸的 running)完全不可见,「重建全部」也覆盖不到,只能靠 `container-gc.sh` 定时静默清理。现列表合并 `docker ps -a`(按 `mao.runtime=user` label 过滤):未在册容器标记 `tracked=false` 一并展示(含 Docker 上报的存在时长);docker 扫描失败时降级为仅在册列表,不影响接口可用。`POST /v1/users/:id/container/recycle` 语义扩展:对未在册残留容器执行 `docker rm -f` 并返回新增的 `removed` 状态(按容器名 + 运行时 label 精确匹配,绝不误删外部容器),下次使用时按最新配置自动重建(挂载数据在宿主机目录,不受影响);整用户聚合回收同时清扫在册容器与该用户的残留容器(聚合优先级 failed > skipped-busy > rebuilt > removed)。孤儿删除与并发 `ensureRunning` 经同键串行锁互斥,锁内复核防止误删刚被纳管的新容器。旧命名 `mao-user-{纯数字}` 孤儿容器仍由 `container-gc.sh` 清理。容器列表 / 回收结果契约类型下沉 `@mao/contracts`。 - **管理后台新增「在线设备」实时查询接口**:新增 `GET /v1/statistics/online-devices`(权限 `analytics:read`),返回当前 WS 在线连接实时快照——总数(连接数 / 去重在线用户数 / 去重设备数)、按客户端类型(桌面客户端 / 安卓 App / 终端 CLI / 浏览器 Web / 页面嵌入)分组计数与按用户的连接列表(设备名 / 平台 / 设备 ID / 连接时长 / 认证到期 / 认证来源)。数据源为 WS 连接注册表纯内存快照(`StreamingWsRegistry.listConnections()`,register 时新增 connectedAt 记录),零新增表零迁移;「在线」= WS 连接存活,断线即离线,无历史留存。去重设备口径:electron / cli 按 `(userId, deviceId)` 去重(同机桌面多窗口与 mao-agent CLI 共用 device.json 算一台),安卓壳逐条计数,browser / embed 无设备标识不计入设备数。响应契约类型下沉 `@mao/contracts`(statistics.ts)。只读快照不触发过期连接的惰性关闭(无 close 副作用)。 ### admin - **容器管理面板支持查看与清理 Docker 残留容器**:未在册容器在状态列显示「未在册」标签(悬停说明来源与处置方式),启动时间列显示 Docker 上报的存在时长,操作列提供「删除」(确认弹窗说明「下次使用时自动重建」语义);「重建全部」覆盖未在册残留容器,确认与结果汇总区分重建 / 删除计数。用户详情抽屉「重建容器」适配新增的 `removed` 结果(残留删除成功不再误报「重建失败」)。列表与回收结果类型改从 `@mao/contracts` 消费,不再本地手写。 - **新增「在线设备」菜单页**:与「用量分析」同级(overview 组,权限 `analytics:read`)。统计卡展示在线连接 / 在线用户 / 去重设备三个数字与五类客户端分组计数;表格按用户列出每条在线连接(客户端类型标签、设备名 / 平台 / 设备 ID 一键复制、连接时长、认证到期、认证来源)。15s 自动轮询 + 手动刷新 + 「更新于」时间戳;页面切走自动停轮询(keepAlive onActivated/onDeactivated),轮询失败静默保留旧数据、靠「更新于」暴露陈旧,避免每 15s 弹红条。客户端类型中文名走 `Record` 穷尽汉化表(联合扩张漏项编译期即失败)。 ## 0.0.510 (2026-11-11) ### 前端(桌面 / Web / 安卓) - **修复暗色主题下「设置 → 服务器」状态卡变成一块白卡片**:该卡片底色误写成未定义令牌 `--aw-bg` 配亮色回退值 `#fbfbfc`,回退值恒生效,于是暗色主题下这块仍是近乎纯白的亮底,配暗色文字既刺眼又读不清(亮色主题下回退值恰好接近底色所以没暴露)。现改为随主题切换的 `--aw-canvas-parchment`(亮 `#f5f5f7` / 暗 `#222226`),在卡片内比卡面深/浅一档,边界清晰。配套新增 `ServerSettingsView.theme.test.ts` 源码守卫:组件引用的 `--aw-*` 令牌必须都已在 `style.css` 定义,避免再用「未定义令牌 + 亮色回退值」制造只在暗色档暴露的回归。 ## 0.0.511 (2026-11-11) ### mao-cli - **修复内置钉钉进度卡模板的两处按钮缺陷**:①「请求成功判定条件」为空——钉钉明确该配置是 Toast 的总开关,不配则平台告警且按钮的成功/失败 Toast 文案都不生效;现按后端回调契约补齐,取消按钮绑 `status == 'cancelled'`、重试按钮绑 `status == 'running'`(后端取消/重试成功时会用 `cardParamMap` 把 `status` 更新为对应值,失败路径只回 `tips`、不改 `status`,判定因此能精确区分成败)。②**重试按钮完全失效**——它的点击事件类型是「打开链接」且链接为空,点击只会打开一个空页面,根本进不了后端的重试分支,「失败态显示重试」形同虚设;现改为「回传请求」。配套新增 `template/check-template.js` 自检脚本,把变量声明、Markdown 绑定、actionId、actionType、可见性与判定条件固化成可执行检查(已用带缺陷的旧模板验证能报出全部 6 处问题),README 的改模板注意点同步补充。 ## 0.0.509 (2026-11-10) ### mao-cli - **mao-cli 技能内置钉钉进度卡模板**:`skills/mao-cli/template/dingtalk-progress-card.json` 是 Mao 钉钉机器人进度卡在钉钉开放平台卡片编辑器的导入文件,排版与飞书进度卡同构(状态行 + 完整回复正文 + 本轮工具列表),终态后只保留结果、隐藏「取消任务」按钮,失败态显示「重试」。此前新增机器人必须自己在卡片平台从零画一套模板,现在可直接导入本文件、保存、发布,再把发布后的模板 ID 填到管理后台「钉钉机器人 → 进度卡模板 ID」。模板用法、变量契约与改模板注意点见 `skills/mao-cli/template/README.md`,已在 `SKILL.md` 知识库路由表与 `reference/dingtalk-bot.md` 交叉登记。 ## 0.0.508 (2026-11-10) ### 后端 - **钉钉进度卡改为「状态行 + 完整正文」,与飞书卡片同构**:此前完成卡只有一行「共 N 轮 · 耗时 X 秒」,Agent 的回复全文看不到——因为 `runtime.ts` 只在 failed/cancelled 时才把正文透传给卡片,running/completed 都丢掉了。现在正文全状态透传,卡片正文按 `**状态:处理完成** · 共 3 轮 · 耗时 44 秒` + 空行 + 回复全文 + `**本轮工具**` 列表拼接,执行中则实时显示流式累积的 assistant 文本与在途工具耗时。配套新增 `card-body.spec.ts` 锁住拼接格式、执行中不带耗时、超长截断等行为。 ## 0.0.507 (2026-11-10) ### 后端 - **修复钉钉任务完成后重复回复**:进度卡终态更新成功后,还会再发一条独立的文本消息,同一条结果出现两遍(卡片一份 + 消息一份)。现与飞书对齐:卡片终态(完成 / 取消 / 失败)更新成功就只由卡片呈现结果,不再另发消息;仅当卡片更新失败(网络抖动、模板问题)才回落发文本,保证用户至少收到一遍。 ## 0.0.506 (2026-11-10) ### 后端 - **修复钉钉进度卡/排队卡始终投放不出去**:钉钉 `createAndDeliverCard` 接口要求场域模型(`imRobotOpenSpaceModel` / `imGroupOpenSpaceModel`)与投放模型(`imRobotOpenDeliverModel` / `imGroupOpenDeliverModel`)**成对**传入,只传前者报 `param.openDeliverModelError`、只传后者在 HTTP 200 里回 `spaces of card is empty`,两者齐备才会真正进入场域投放。此前只传了前者,导致卡片从未创建成功,用户看不到进度卡,只能等 Agent 执行完收到一条纯文本回复。群聊投放此前还缺 `imGroupOpenDeliverModel.robotCode`(钉钉据此定位机器人,缺失报 `chatbot not exist`),现已从机器人配置带入。另外该接口 HTTP 200 不代表投放成功,场域级失败只体现在 `deliverResults` 里,现已解析该字段并抛错,避免"接口通了但用户什么都没收到"被静默放过。 ## 0.0.505 (2026-11-10) ### 后端 - **本地工具执行不再因执行端通道失效长时间卡住**:此前会话绑定设备后,只要 `isConnected` 判定在线,服务端就开等执行端回报,最坏要干等满总超时(默认 900 秒)才返回 `Local tool execution timed out`——桌面端闪断、或 mao-agent 与桌面端共用同一 `deviceId` 时执行连接被抢走(半死连接:socket 活着但执行端没有该会话上下文,收到帧不回报),都会出现这种情况。现在: - 设备定向投递零成功时(该设备当前没有任何可写执行连接),立即回「本地执行端未连接,请确保桌面客户端正在运行」,同时收敛服务端 pending,不再留下无人认领的等待。 - 无审批请求下发后,若执行端在 60 秒内既没回 `tool_approval` 空表态也没回结果,即判通道半死并快速失败,提示用户确认桌面客户端在运行、未被后台挂起后重试。该窗口与总超时定时器同起跑并取更早触发者,只会让结果更早,绝不会把请求拖得比总超时更久。 - `sendToDevice` 在主执行连接不可写(readyState 非 OPEN / 未授权)时,回退到同一 deviceId 的另一条存活连接(同机多窗口 / 多 CLI 进程场景),避免整个设备被误判离线。 ### 前端(桌面 / Web / 安卓) - **侧边栏钉钉分组改用钉钉品牌图标**:钉钉私聊 / 群聊分组此前用通用聊天气泡图标,与飞书、微信的品牌 logo 不一致,看不出这条分组来自哪个 IM。现在换成钉钉官方图形(`#1296DB` 品牌蓝),与既有飞书 / 微信图标同尺寸、同渲染方式;分组判定逻辑不变,仅替换图标资源。 ## 0.0.504 (2026-11-10) ### 后端 - **钉钉 OAuth 登录配置迁入管理后台**:绑定用登录应用的 Client ID / Client Secret / 回调地址此前只能改 `.env` 再重启后端,现在在「系统设置 → 登录认证 → 钉钉 OAuth 登录」维护,保存后即时生效。配置改由 `system_setting` 承载(`dingtalk.oauth.clientId` / `clientSecret` / `redirectUri`,Secret 加密存储、列表返回掩码),绑定短链、授权跳转、回调换 token 全部改为实时读取,不再依赖启动时快照。做法与飞书 OAuth 登录(`auth.feishu.*`)一致:`DINGTALK_OAUTH_*` 环境变量不再生效,升级时首次启动由 SettingsBootstrap 自动导入 DB(管理员在后台保存过的行不被覆盖),导入后即可从 `.env` 删除。`DINGTALK_BOT_ENABLED` 与 `APP_DINGTALK_BOT_SECRET` 仍是环境变量(前者改后需重启,后者是加密主密钥,放进同一张表等于用同一把钥匙锁门和锁钥匙)。 ### 管理后台 - **系统设置新增「钉钉 OAuth 登录」组**:与「飞书 OAuth 登录」并列在登录认证分组下,含 Client ID、Client Secret(密码框 + 已设置提示 + 清空)、回调地址(格式校验),复用集成配置的保存与测试链路。 ## 0.0.503 (2026-11-10) ### 后端 - **Docker 模式的 Shell 脚本哨兵改在属主容器内执行**:此前脚本探针一律由后端进程在宿主机执行,即使用户运行环境已切到 Docker,脚本仍能以后端同一系统用户访问宿主机文件和网络。现在按哨兵属主的有效运行模式分流(用户级覆盖优先,与会话 Shell 相同):Docker 模式在该用户、该 Agent 的运行时容器里执行,可见范围与容器内 Shell 一致;host 模式仍在后端宿主执行。容器起不来、运行时版本尚未对齐或通道断开时,本轮记一次失败并顺延到下个轮询间隔,不计入连续五次自动停用,也不改回宿主机执行。有活跃脚本哨兵时,对应容器会被定期唤醒。 ## 0.0.502 (2026-11-10) ### 前端(桌面 / Web) - **工具卡片的审批与截断改为图标**:状态区不再平铺「AI 已批准 / 低风险放行 / 规则放行 / AI 已拒绝 / 输出已截断」。依次对应头像、魔棒、文档、红色圆圈叉、琥珀色剪刀。悬停或点按仍显示原文;审批图标附带理由。 ## 0.0.501 (2026-11-10) ### 前端(桌面 / Web) - **深色主题压低长文亮度**:对话正文、标题和导航主文字由近白 `#f5f5f7` 改为 `#d0d0d4`(卡片上约 10:1),说明文字再低一档。页面底停在炭黑,控件边框保持深灰。浅色主题不变。 ## 0.0.500 (2026-11-10) ### 后端 - **失败会话批量恢复不再限于 402/403**:`GET /v1/admin/sessions/recover-failed/preview` 改为列出时间窗内全部 `phase=FAILED` 的主会话(额度、权限、工具错误、超时等),错误摘要优先用终态 `executionError`。`POST /v1/admin/sessions/recover-failed/run` 按勾选 id 续跑。历史参数 `scope`(`QUOTA` / `ALL_402_403`)忽略,不再据此跳过。LOCAL、子代理/边路、定时任务待重试、执行中仍会跳过。清单最多 200 条,超出时 `truncated=true`。 ### 管理后台 - **「恢复失败会话」改为勾选后执行**:会话管理页入口不再只扫 402/403。弹窗列出失败会话(可按标题、用户、错误筛选),管理员勾选后发起恢复,单批仍最多 20 个;不再默认全选。本地执行、定时任务待重试、正在执行的行不可勾选。 ### 终端 CLI(mao-cli) - **`mao admin-session recover-failed`**:`preview [--window-hours]` 列出时间窗内失败主会话;`run --session-ids 431,473` 按 ID 发起恢复(单批最多 20,需 `session:write`)。重复 ID 会合并,`--window-hours` 只接受 1–168。 ## 0.0.499 (2026-11-10) ### 后端 - **API Token 支持永久删除**:`DELETE /v1/open/tokens/:id` 仍是吊销(记录保留、立即失效)。新增 `DELETE /v1/open/tokens/:id/permanent`,属主可删掉有效或已吊销的 Token;删除后鉴权变为查无,历史调用流水保留,管理端按原 Token 重发会拒绝。 ### 前端(桌面 / Web) - **开放接口 Token 卡片可删除**:每条 Token(含已吊销)增加删除按钮,确认后永久移除。吊销改为停止图标,与删除区分。 ### 终端 CLI(mao-cli) - **`mao open token purge --id `**:永久删除 API Token。`open token delete` 仍是吊销。 ## 0.0.498 (2026-11-10) ### 终端 CLI(mao-cli) - **信号哨兵 CLI 支持 Shell 脚本探针**:`mao signal-watcher` 此前只有 HTTP 探针参数(`--url` 为硬编码必填),脚本哨兵只能走桌面端表单或 REST 创建。现新增 `--probe-type HTTP|SCRIPT`、`--script-path`、`--timeout-seconds`: - 必填项按类型分流:HTTP 必填 `--url`,SCRIPT 必填 `--script-path`(缺哪个报哪个,不再一律报缺 `--url`)。 - 两侧字段互斥:显式传 `--probe-type` 时非生效侧字段(SCRIPT 下的 `--url`/`--method`/`--headers`/`--body`/`--json-path`,HTTP 下的 `--script-path`/`--timeout-seconds`)在本地丢弃并打 stderr 提示,不静默;未传 `--probe-type` 时全部下发,由后端按库内类型忽略。 - 本地校验与后端同口径:`--script-path` 非空、非绝对路径、不含 `..` 段;`--interval` 对 SCRIPT 下限 5 分钟;`--compare-mode STATUS_CODE` 对 SCRIPT 拒绝;`--timeout-seconds` 5~300 整数。脚本文件的存在性 / ≤256KB / 属主边界仍由服务端校验。 - `update` 可用 `--probe-type` + 对侧字段把已有哨兵切成脚本探针(会重置判定基线);HELP 与 `reference/signal-watcher.md` 同步补充两种 create 形态与脚本侧报错清单。 ### 前端(桌面 / Web) - **哨兵探针类型说明换到选项下方**:新建/编辑哨兵时,探针类型旁的说明不再跟在单选后面挤成一行,改为显示在选项下方。 - **哨兵「选择脚本」按钮与路径输入框齐高**:脚本路径行右侧按钮此前用对话框 24px 按钮,比 32px 输入框矮一截,现与输入框同高、同圆角。 ## 0.0.497 (2026-11-10) ### Embed SDK - **产物改为提交 git,部署不再重复构建**:`/embed/mao-chat.js` 此前由每次 desktop 构建的 `prebuild` 现构 `sdk/embed` 生成,服务器上常留下「构建产物未提交」的脏改动,且线上产物与仓库可能不一致。现 SDK 产物(`desktop/public/embed/mao-chat.js` 与版本锁定副本 `mao-chat.v{version}.js`)**入 git**,改 SDK 源码后在 `sdk/embed` 跑一次 `npm run build` 并提交产物即可;desktop 构建与部署只消费已提交产物。CI `embed-sdk` job 新增产物一致性校验(重新构建并比对 sha256),**改了 SDK 源码却漏提交产物会在 CI 直接挂掉**。本次同时补上 0.3.3 产物。 ## 0.0.496 (2026-11-10) ### Embed SDK - **执行过程渲染重设计,与客户端对话页同构**:浮窗里 Agent 的执行过程(思考/工具调用/中间说明)此前是「思考过程 details + N 个工具调用」两段粗折叠,与桌面端观感差距大。现按桌面端对话页的形态重写: - **轮次折叠**:一轮执行完成后,过程自动折叠为「已执行 N 个步骤,任务耗时 X」胶囊(耗时从用户消息发出到本轮最后一条消息结束;历史回放取 REST 消息时间戳),最终回复在胶囊下方常显,点击展开全过程、再点收起,与桌面端历史轮次一致;无工具的纯问答轮不产生折叠条。 - **思考行**:「思考完成」行 + 图标 + 展开箭头,执行中显示「思考中…」转圈并在头部空白区滚动预览最新思考片段,展开看原文(对齐桌面端 ThinkingBlock)。 - **工具行/组**:工具名全部中文化(与桌面端同一映射口径);单调用渲染一张带图标卡片行,多调用折叠为「2次执行命令」式中文汇总组头,组头带组内执行耗时与转圈。行头显示后端一句话摘要(缺省回退「中文名 · 入参摘要」),右侧为秒表(执行中满 1s 起表)、转圈、成功√/失败×或「结果未记录」。 - **工具卡富视图**(对齐桌面端 ToolCallCard):shell 终端会话块($ 命令 + 输出 + exit 徽标)、edit_file 行级 diff(± 着色、上下文折叠、替换摘要)、read_file/write_file 行号内容、glob/grep 命中列表、web_search 结果卡片、open_web_page 正文;底栏给结果摘要与「查看原始输入输出」开关;无富视图的工具回退输入/输出 JSON 块,超长输出折叠可展开完整;页面截图缩略图点击看大图(沿用灯箱)。 - 数据层配套:WS `tool_call_result` 的 result(富视图数据源)与 summary(行头摘要)分字段保存(此前 summary 覆盖 result 导致富视图解析不到 JSON);工具调用记录起表时刻(订阅重放按 `elapsed_ms` 反推,刷新/重连后秒表不归零);历史消息携带 `createdAt`/`updatedAt` 供折叠条算耗时。SDK 产物版本 0.3.2 → 0.3.3。 ## 0.0.495 (2026-11-10) ### 后端 - **修复一次性定时任务排队结算丢失用户改档**:会话忙入队后、消费完成前,用户把 cron 换成另一个一次性日期,排队结算曾无条件把任务标完结并清空档期——新档期永不触发、任务被误标 finished。现与直跑收尾同口径:改档(队列行 fireTime 不再是当前 cron 的触发点)且任务启用时按最新 cron 重开档期,未改档行为不变。 - **修复流式 tool_call 合并拆分**:部分网关返回的带 id 参数分片不带 index,与无 id 首片的占位调用对不上号时,同一工具调用被拆成两条重复派发(前半参数截断、后半无名),用户命令实际未被完整执行。现 byId/byIndex 都落空且恰有一条占位调用时归并到它。 - **修复出站投递抛出型失败永不终态**:投递过程抛异常(如 webhook 密钥解密持续失败)此前只记日志,行停在 SENDING 被恢复器反复复位重试、无重试上限、不落终态与审计。现与结果型失败同口径:按 1/5/25 分钟退避共 3 次,耗尽后终态 FAILED 并落审计。 - **`message_queue.content` 列宽与消息门禁对齐**(V190 迁移随启动自动执行):TEXT(65535 字节)装不下开放调用允许的 32000 字中文消息(96000 字节),忙会话入队被 MySQL 严格模式拒绝、排队消息丢失。现拓宽为 MEDIUMTEXT,与 message.content 一致;32000 字门禁行为不变。 ### 前端(桌面 / Web) - **修复图片注入行剥离对纯文本消息的尾随空行改写**:气泡/编辑回填/复制口径对不含注入行的内容现保持恒等,非桌面来源消息编辑重发不再被静默裁掉尾随空行;回声去重比对口径不变(仍双侧收敛判等)。 - **修复压缩包点文件与无点文件无法文本预览**:`.gitignore`/`.editorconfig`/`.env`/`Dockerfile`/`Makefile` 此前一律走下载分支,现正确进内存文本预览。 - **修复工具卡片预览截断产生乱码字符**:emoji 等宽字符恰落在截断边界时被从代理对中间切开渲染成 U+FFFD,现按 Unicode 码点完整截断(工具参数预览与后台子代理完成通知摘要)。 ## 0.0.494 (2026-11-10) ### 后端 - **信号哨兵支持 Shell 脚本探针**:哨兵探针类型二选一(HTTP / SCRIPT)。脚本哨兵以 `bash <脚本>` 在后端宿主执行本人项目工作区内的脚本(不要求可执行位、stdin 关闭、独立进程组),stdout 作为判定值进入既有判定管线(HASH / JSON_FIELD),exit code 0=成功、非 0 计一次失败(连续 5 次自动停用兜底不变),超时 5~300 秒(默认 60)、stdout 上限 1MB;脚本路径保存与执行双侧做属主与软链逃逸校验;执行环境为白名单变量(PATH/HOME/TZ/MAO_WATCHER_ID/NAME),不透传后端进程全量 env。调度、退避、自动停用、触发(openRun)、轮询记录、清理链路全部复用;`signal_watcher` 加 `probe_type`/`script_path`/`script_timeout_seconds`、`signal_watcher_check` 加 `exit_code`(V189 迁移随启动自动执行,存量哨兵默认 HTTP 零行为变化)。新增 Agent 内置工具 `list_signal_watchers` / `create_signal_watcher`:会话中可让 Agent 写好脚本(项目工作区)后直接创建哨兵,实现对话闭环。 ### 前端(桌面 / Web) - **信号哨兵表单支持脚本探针**:探针类型切换分流——脚本态展示脚本路径(工作区文件选择器 + 手输)、执行超时,隐藏 URL/方法/请求头/请求体;判定模式对脚本哨兵隐藏状态码选项;轮询间隔下限按类型切换(脚本 5 分钟);列表卡显示探针类型徽标、脚本路径与超时;「立即测试」结果展示脚本退出码与输出样本;轮询记录状态码列对脚本探针显示退出码。 ### 管理后台 - **信号哨兵只读清单与详情展示探针类型**:列表加「类型」列,探测地址列对脚本哨兵显示脚本路径,配置详情展示探针类型与执行超时。 ## 0.0.493 (2026-11-10) ### 前端(桌面 / Web) - **外观个性化:强调色五款与界面字号三档**:个人信息页顶部外观卡在主题色之外新增「强调色」(经典蓝 / 紫 / 绿 / 橙 / 石墨五款预设,应用于按钮、链接与选中态,亮暗主题各自适配)与「界面字号」(小 / 标准 / 大三档,立即生效)两行设置;偏好存本机 localStorage(与主题色同口径,不随登出清除),刷新后保留。 - **默认观感零变化**:不选择新偏好时全部取值与旧版逐字节相同(经典蓝即默认强调色、标准即默认字号);所有个性化均为显式 opt-in,登录页与空态的营销字号不随字号档变化。 ## 0.0.492 (2026-11-09) ### 后端 - **`/opt/mao-data/share` 按 Agent 隔离(形态 C)**:容器内由「整根 rw 挂载」改为两条子路径 rw——`agent-experience//`(本 Agent 团队经验库)与 `agents//`(本 Agent 私有区:投放品/脚本/产物);其他 Agent 目录在容器文件系统层面不复存在(含经验库跨 Agent 零可见,此前为"软链 + 提示词收口"的接受项)。配套调整: - 挂载计划 `assertSafe` 对两条子路径做 purpose 绑定的精确校验(整根 / 其他 Agent / 形似路径一律拒绝); - 容器内沙箱允许根同步收窄为上述两条子路径(与挂载面严格一致,share 根不再放行); - `runtime-agent` 硬依赖 `MAO_CONTAINER_AGENT_ID`(缺失/非法即退出,与 `MAO_CONTAINER_USER_ID` 同口径); - 管理员公共投放区取消:投放改为落到 `agents/<目标AgentId>/`(目录级挂载即时生效,多 Agent 需同一文件时逐个复制); - 存量容器随挂载指纹漂移一次性自动重建;`agent-experience/` 路径本身不变(工作区 `团队经验/` 软链不受影响)。 - **存量数据迁移**:由 `scripts/migrate-share-per-agent.sh` 完成(分发 settings/scripts 至各 Agent 目录、DB 引用更新、旧残留清理;含 DB 前像与分阶段校验)。提示词同步为新文案("本 Agent 的文件放 `agents//`;无跨 Agent 公共共享目录;旧路径已迁移,勿自行重建")。 ## 0.0.491 (2026-11-09) ### Embed SDK - **浮窗入口不再出现「先品牌图标、后换头像」的闪动**:0.0.490 预取后,入口按钮在拿到 Agent 详情前仍会先渲染品牌图标、随后才换成配置头像。现在入口图标分两步处理:①每次成功获取 Agent 详情后,把头像与名称缓存到站点 localStorage(按 Mao 服务地址 + Agent 维度),下次页面加载首屏直接显示上次结果、不等网络;②首次加载(无缓存)期间入口按钮暂不渲染(不出现任何默认图标),解析完成后一次性显示最终图标(配置头像或品牌图标);超时 1.2 秒按无头像兜底、拿到结果后仍会更新。预取失败静默,首次打开浮窗仍会重试。SDK 产物版本 0.3.1 → 0.3.2。 ## 0.0.490 (2026-11-09) ### Embed SDK - **浮窗入口在页面加载时就显示 Agent 头像**:此前入口按钮在首次打开前只显示品牌图标,用户点开浮窗后才加载 Agent 详情、换成管理后台配置的头像。现在 SDK 初始化即预取 Agent 详情(与首次打开共用同一请求,打开后不重复拉取):入口按钮与浮窗标题在页面加载时就使用配置的头像与 Agent 名称;无头像或未配置时仍回退品牌图标与「Mao 助手」。预取失败静默回退(不写浮窗错误横幅),首次打开仍按原流程重试;`launcher.visible: false` 不预取。注意:公司 SSO 模式下预取会在页面加载时触发一次换票(不再等用户点开浮窗),不打开浮窗的页面同样会换票并按既有 TTL 续期;WS 连接仍为懒连接。SDK 产物版本 0.3.0 → 0.3.1。 ## 0.0.489 (2026-11-09) ### 后端 - **公司 SSO 宿主 Origin 支持 HTTP、localhost 与 IP**:宿主 Origin 白名单的精确项由「仅 HTTPS」放宽为 HTTP/HTTPS 均可,支持 localhost、IPv4/IPv6 与非默认端口(如 `http://localhost:2222`);换票 CORS 预检与 POST 校验共用同一规则同步放行。子域模式仍仅限 `https://*.example.com`,校验域名白名单、checkUrl 与换票入口 HTTPS(`requireHttps`)要求不变。 ### 管理后台 - **公司 SSO 宿主 Origin 表单支持 HTTP、localhost 与 IP**:校验与后端保持一致,输入提示补充 `http://localhost:2222`、`http://127.0.0.1:8080` 等示例与默认端口说明;子域模式仍仅 HTTPS,HTTP 来源仅建议本地开发或内网联调使用。 ## 0.0.488 (2026-11-09) ### 后端 - **非白名单图片格式(TIFF 等)强制转码后再进 prompt**:用户上传的图片若实际是 TIFF/BMP 等非 webp/png/jpeg/gif 格式(例如文件名伪装成 `.jpg` 的 TIFF 截图),此前图片准备链路只按尺寸/体积决定是否重编码——尺寸合规的 TIFF 会被原样转成 `data:image/tiff;base64,…` 发给模型,上游(如 kuaishou 渠道)不认该格式直接 400 `unsupported image`;且失败会话历史里这张图每轮都会重发,用户重发新图也无法自救。现在 `PromptImageResizer` 统一走图片格式白名单(png/jpeg/gif/webp),白名单外的格式即使尺寸/体积合规也强制转码为 PNG(压不小则 JPEG),三条协议(OpenAI 兼容 / Anthropic / Responses)与远程图片缓存路径同时生效。 ## 0.0.487 (2026-11-09) ### 终端 CLI(mao-agent) - **常驻本地执行端 `mao-agent local --serve`**:不加入任何会话,凭本机设备身份替全部 LOCAL 会话执行工具。桌面客户端退出后,安卓 / 浏览器上已绑定该设备的本地任务仍能跑。`--workspace` 是信任根(默认当前目录,须已信任,不会静默信任)。需审批时默认等桌面 / 安卓 / Web 任一端投票,超时(默认 300 秒,`--approval-timeout-ms`)后拒绝;附着形态 `mao-agent --local --on-approval=remote` 使用同一个超时。`--yolo` 可全自动。与桌面客户端同时在线时,谁最后连接谁执行:桌面端后启动会夺回,关闭桌面端后执行权回到仍在线的 daemon。信任根外的技能 / MCP 同步不回包,避免失败回包把同机桌面端的成功判负;仅 daemon 在线且工作区在根外时,技能同步会在约 60 秒后失败,MCP 同步超时后该轮工具不可用。无人值守建议加 `--yolo` 或把会话权限设为 `FULL`。守护进程等于把本机 shell 开放给自己账号的会话,只在可信机器上运行。 ### 后端 - **执行端类型随 `device_status` 下发**:在线帧带当前执行连接的 `clientType`(`electron` / `cli`)。设备仍在线、只是执行连接从桌面换成 mao-agent(或反过来)时会再推一帧,同类型互顶不推。会话详情和列表增加可选 `executorClientType`,刷新后不用等下一次上下线。无新表、无迁移。 ### 前端(桌面 / Web / 安卓) - **本地任务横幅区分谁在执行**:在别的设备上看,在线且执行连接是桌面客户端时显示「桌面客户端在执行」,是 mao-agent 时显示「mao-agent 在执行」。字段还没有时仍是「该任务在 {设备名} 上执行」。当前这台机器就是绑定设备时横幅不出现。离线文案和发送拦截不变。 - **后端重启 / 蓝绿部署后不再出现重复且一直转圈的工具调用**:会话恢复执行时,末尾那条被中断的工具调用此前会在界面上一式两份(同一条命令两个条目),旧的那份持续转圈直到任务结束或刷新页面才消失。现在后端换新执行重跑时就地终结旧气泡里未终结的调用(已执行完的轮次与已产出的文字原样保留),恢复后的调用是唯一在跑的条目,结果正常落到它身上。 ### 终端 CLI(mao-cli) - 手册补充「常驻本地执行端」:适用场景、命令、信任根、审批口径、与桌面端共存和无人值守注意事项。 ## 0.0.486 (2026-11-09) ### 管理后台 - **移除用量分析「运行轨迹」Tab**:最慢的轮、最贵的轮、工具失败率三个榜不再展示。旧链接 `?tab=run-trace` 会打开总览。桌面端任务里按会话查看的运行轨迹仍在。 ### 后端 - **移除 `GET /v1/admin/analytics/run-trace`**:该聚合只给上述 Tab 使用,一并删除。 - **飞书多文件消息(一次发送多个文件)落地支持**:飞书把「一次发多个文件」编码成 `post` 富文本消息、文件挂在 content 顶层 `files` 数组(`{"content":[[]],"files":[{"file_key":"file_v3_…","file_name":"x.pptx","is_folder":false}]}`),此前入站链路完全不识别该形态——正文提取为空、消息退化为 `[post msg=om_xxx]` 占位(Agent 看不到文件名和内容),`feishu_download_file` 兜底也报「未找到包含文件/图片的群聊消息」。现在与单文件消息对齐: - 入站解析识别 `files` 数组,生成 `[文件:名字 msg=om_xxx file_key=file_v3_xxx]` 逐文件占位(带 file_key 供精确下载);文件夹项(`is_folder=true`)不可下载、保留 `[文件夹:名字]` 占位(不再退化为 `[post msg=…]`); - 只有文件、没有正文的 post 与单文件消息同语义:入站即下载落盘、只写入会话不单独触发任务(带正文的 post 正常触发并注入文件路径); - 私聊直传、群聊预下载(日志行回填 `@{路径}@`)均支持多文件,同一消息内重名文件自动避让; - `feishu_download_file` 新增可选 `file_key` 参数:多文件消息按占位符逐一下载,不传则下载该消息全部文件(返回 `paths` 数组,单个失败不影响其余文件);含图+文件的混合 post 中该工具只负责文件资源,图片仍由入站直传 / 群预下载覆盖; - 带内嵌文件的多文件 post 与图片/文件同类,不并入纯文本防抖合并窗口,到达即单独触发。 ### 终端 CLI(mao-cli) - **移除 `mao analytics run-trace`**:与管理后台该 Tab 同一份数据,Tab 下线后命令不再提供。 ### Embed SDK - **浮窗入口按钮放大为原来的 75%**:0.0.424 曾缩到 56px 的 50%(28px),实际偏小;现调整为 75%——桌面 42px、窄屏(≤480px)39px。品牌图标 / Agent 头像满铺按钮随之同比缩放,内侧描边环、未读红点、运行环与拖动避让同步适配,点击打开对话的行为不变。 - **页面工具改为读 / 写分离,`page.enabled` 只控制写/操作类**:读类工具(`page_inspect` / `page_observe` / `page_screenshot` / `page_wait`)不受开关控制、始终提供——宿主零配置,Agent 默认就能查看当前页面(元素快照与遮罩截图);写/操作类(`page_scroll` / `page_focus` / `page_fill` / `page_select` / `page_check` / `page_uncheck` / `page_click` / `page_keyboard` / `page_actions`)缺省关闭,显式 `page: { enabled: true }` 才开启,不再有「一行 `init` 就默认拿到操作宿主页面能力」的隐式授权。后端按连接级声明过滤写类工具,SDK 侧写请求双保险直接返回 `page_operation_disabled`;写能力关闭时截图强制遮罩敏感区域(不弹确认卡)、浮窗不显示授权下拉 / 确认卡片 / 动作日志、注入模型的提示词换用只读变体(明确告知只能查看、不能代操作)。读能力需要页面快照,SDK 因此始终创建页面引擎(patch 宿主 `history.pushState` 并挂导航监听,非破坏性)——这是「读始终提供」的固有成本,暂无「连读也全关」的开关。管理后台自家宿主已显式 `page: { enabled: true }`,浮窗助手读写能力不变;**外部存量宿主**若依赖原缺省开启,补 `page: { enabled: true }` 即可恢复。 ## 0.0.485 (2026-11-09) ### 管理后台 - **会话管理「活跃时间」新增「最近 1 天」「最近 3 天」**:筛选下拉原有「最近 7 天」起步,查当天或近几天的活跃会话只能手选自定义区间;新增两档后点选即查,口径与既有预设一致(含今天,按北京时间日历日切分,`--range 1d/3d` 同效)。默认档仍是最近 7 天,地址栏 `range` 参数同步支持两档。 ## 0.0.484 (2026-11-09) ### 后端 - **非流式 LLM 调用补记 token 用量与成本**:连通性测试、飞书群聊溢出摘要等走非流式客户端的调用,此前落库 `usage: null`,入/出 Token 与成本恒为 0。现在三个协议(OpenAI 兼容 / Anthropic Messages / Responses)的非流式响应都会归一出 `usage`(Anthropic 含缓存读/写分项),`llm_call` 记录真实 token 与按真实 token 计的成本;飞书群聊溢出摘要(`feishu_summarize`)同时补上调用归属人——本次触发的发言者(缺省回退会话归属人),管理后台「调用流水」的「用户」列不再为空。 ## 0.0.483 (2026-11-09) ### 后端 - **本地任务执行端离线提示中文化 + 在线态实时推送**: - 执行端未连接的拒绝文案统一为中文「本地执行端未连接,请确保桌面客户端正在运行」:覆盖发送 / 编辑重发 / 重试 / 边路任务创建 / 定时与开放接口执行(WS 错误帧),以及工具执行失败回执(本地端中途断线时的工具卡片)——此前这些路径是英文,弹窗与工具卡片会直接露出英文句子。 - 新增 `device_status` 用户级广播:桌面客户端退出(设备最后一条执行连接断开)时向该用户的其它连接推送离线,桌面/mao-agent 连入时推送上线;同设备多窗口覆盖、连接交接不重复广播。`targetDeviceOnline` 原本只是会话详情的请求时快照,其他端(安卓/浏览器)此前只能靠刷新纠正。 ### 前端(桌面 / Web / 安卓) - **本地任务横幅实时跟随执行端在线态**:桌面客户端退出后,「该任务在 xxx 上执行」细条数秒内由绿转橙(「执行端 xxx 不在线,发送前请在该设备上打开 Mao」),桌面重新打开后自动转回在线态,不再只有刷新页面才纠正;边路任务面板的执行端提示同样实时。横幅转橙后浏览器/安卓端继续发送会被既有中文拦截挡住。 - **发送失败不再卡「正在保存…」60 秒**:本地端未连接等「消息尚未落库即被服务端拒绝」的场景,此前只回错误帧、不发保存确认,输入框一直转「正在保存…」直到 60 秒超时,且实际未发出的消息会挂在列表里像已发出。现在拒绝即解锁输入框(原文保留可重试)、回滚该条乐观消息,错误横幅中文展示;任务被占用、预算超限等同类落库前拒绝同样受益。 ## 0.0.482 (2026-11-09) ### 后端 - **飞书进度卡片:首次思考占位带耗时刷新**:「正在思考…」满 1 秒后附耗时(`正在思考…(1 分 30 秒)`),思考期间按「在途工具耗时」同一间隔(默认 3 秒,`FEISHU_CARD_TOOL_TICK_MS` 可调)重推卡片——首次 LLM 调用长时间无产出时,用户能看到时间在走,不再只有一行静止文案。口径与工具耗时一致:亚秒不显示;首个非空白增量(首 token)/工具开始/轮次收尾即停思考计时。后续轮仍不重刷占位(0.0.481 语义不变)。 ## 0.0.481 (2026-11-09) ### 后端 - **飞书进度卡片:「正在思考…」仅在首次思考显示,后续轮次不再重刷**:0.0.476 起每轮开始都会把卡片重刷成「正在思考…」,已执行到第 36 轮的任务正文与工具被抹掉、看起来像进度重置。现改为仅首个轮次推送该占位,后续轮保持已展示的进展(轮次与工具更新仍由工具开始 / 轮次结束推进);失败卡重试与崩溃恢复续跑同理。钉钉共用同一监听器,行为同步。 ## 0.0.480 (2026-11-09) ### 前端(桌面 / Web) - **信号哨兵请求头凭据提示不再被输入框截断**:`{{MAO_TOKEN}}` / `{{ECP_TOKEN}}` 占位符说明从值输入框的 placeholder 挪到请求头编辑区下方单独一行(可完整折行显示),值输入框 placeholder 改为简短的「Header 值」(编辑态仍显示「留空不修改」)。 ## 0.0.479 (2026-11-08) ### 前端(桌面 / Web) - **聊天消息长代码块默认折叠**:超过 30 行的代码块默认只显示首屏约 8 行并带渐隐遮罩,块头新增行数徽标(如「500 行」)与「展开全部 / 收起」按钮,长代码不再把对话撑出十几屏;展开状态在会话内记住(切换主题、流式结束、翻页重渲后不折回),刷新页面后恢复默认折叠。折叠是视觉裁剪,代码完整渲染,复制、划选不受影响。 - **代码块换行开关**:折叠块块头新增「换行」按钮,切换长行折行 / 横向滚动;偏好全局记忆(localStorage),刷新后沿用,会话内全部代码块(含短块长行)一致生效。 - 分享页随消息正文同步生效;文件预览、运行轨迹、技能页、OpenApi 文档等其它宿主的代码块展示不变。Mermaid 图不折叠;超过 64KB 的 mermaid 源码按普通代码块折叠(既有行为)。 ## 0.0.478 (2026-11-08) ### 前端(桌面 / Web) - **中心页签效率补完**(技术方案 `docs/plan/2026-11-08-center-tab-efficiency-technical-design.md`): - **中键关闭页签**:鼠标中键点击页签即关闭(主会话页签除外,`×` 按钮上的中键同样生效),并抑制浏览器中键自动滚动指示器。 - **页签拖拽排序**:非主会话页签可拖拽重排,悬停页签显示左右插入指示线(按中点判定),拖到 Tab 栏空白处即「移到最后」;主会话页签恒在首位、不可拖拽,其上无插入线且落点为禁止光标。顺序为会话生命周期内行为,刷新后按既有重建口径,不持久化。与 0.0.476 工作区文件拖入 Tab 栏的落点互不干扰(文件拖拽行为不变)。 - **右键菜单新增「关闭右侧文件」**:关闭被右键页签右侧的全部文件类页签;右侧的执行中边路任务 / 子代理页签不受影响(与「关闭其他文件」同口径),副作用(关闭标记、激活回退)完整保留。 - **键盘循环切换页签**:`Ctrl/Cmd+Alt+←/→` 在中心页签(含主会话)间循环切换、端点回绕;输入框 / 编辑器聚焦时不触发,长按不连跳。Web 端部分平台(Linux GNOME 工作区切换、macOS Chrome 切换标签页等)该组合键可能被系统或浏览器占用拦截,Electron 桌面端不受影响。 ## 0.0.477 (2026-11-08) ### 前端(桌面 / Web) - **顶栏隐藏命令面板功能图标**:顶栏 ✨ 图标不再展示(功能打磨中,暂不面向用户开放),命令面板本体与 `Ctrl/Cmd+Shift+P` 快捷键、`?` 速查表均不受影响。 ### 后端 - **飞书进度卡片:在途工具显示执行中耗时**(技术方案 `docs/plan/2026-11-08-feishu-card-tool-elapsed-technical-design.md`):「本轮工具」列表对执行中的工具行追加耗时(`shell:`npm test`(执行中 · 1 分 30 秒)`),有工具在跑期间每 3 秒重推一次卡片,长耗时工具执行期间不再完全静止。口径与桌面端 0.0.463–465 对齐:亚秒(< 1s)不显示、已完成工具摘要行不带耗时、并行工具各自计时、终态卡不带执行中耗时;工具结束 / 轮次结束 / 终态即停刷新(模型思考阶段卡片照旧静止)。新增环境变量 `FEISHU_CARD_TOOL_TICK_MS`(默认 3000,0 关闭周期刷新),可降频规避 im.v1.message.patch 限额,无需发版。钉钉共用同一监听器,进度卡同样带耗时刷新(钉钉群用户可见的行为同源变化)。 ## 0.0.476 (2026-11-08) ### 后端 - **飞书进度卡片:首次思考不再停留在「任务已接收,正在准备执行。」**:此前卡片只在首个工具调用开始或轮次结束才 PATCH,AgentLoop 发起每轮 LLM 请求(`onRoundStart`)时只记轮次、不刷新卡片——首次调用常要几十秒才产出内容,这段时间卡片一直停在首卡文案,用户容易误以为任务卡住。现改为每轮开始即刷新卡片:尚无正文时显示「正在思考…」,状态行同步显示「第 N 轮」;失败卡重试与崩溃恢复续跑同样生效(轮次按已完成的助手轮接续)。钉钉共用同一监听器,轮次刷新同样更及时(其进度卡模板本就不展示执行中正文)。 ### 前端(桌面 / Web) - **新增全局命令面板**(`Ctrl/Cmd+Shift+P`,或点顶栏 ✨ 图标唤起):28 条内置命令输入即滤、↑↓ 循环选择、Enter 执行、Esc 关闭且焦点还原——覆盖搜索会话(与 Ctrl/Cmd+K 同源)、新建会话、终端 / 左右面板 / 收件箱 / 我的指令开关、会话列表刷新、退出登录、15 个设置页直达与快捷键速查表;浏览器(非 Electron)下「服务器」「桌面」两条置灰,终端命令跟随既有可用性判定。共享 UI 生效(Web / Electron / 安卓壳同入口)。 - **新增快捷键速查表**:主界面按 `?` 弹出全部 7 条快捷键(输入框 / 编辑器聚焦时不触发);命令面板内「快捷键速查表」命令亦可打开。 - **主题切换主界面直达**:命令面板内执行「主题:亮色 / 暗色 / 跟随系统」即时生效(当前模式带 ✓ 标记),与个人资料页三态选择器同一单例、天然同步,无需再进资料页切换。 - **工作区文件跨面板拖拽**:文件管理器 / 文件树的文件可直接拖进聊天输入框,成为可点击的 `@` 文件引用(多选逐条插入、顺序与选择一致,目录忽略;插入随草稿持久化,切会话不丢);拖到中心 Tab 栏直接打开预览页签(重复拖同文件只激活既有页签,不重复开;从工作区总览打开的其他工作区文件管理页签拖出时,按其所属工作区打开预览,不会错开当前会话工作区的同名文件)。拖拽光标在聊天输入框 / Tab 栏显示 copy、面板内部移动仍为 move;OS 本地文件拖入上传、面板内部移动 / 归组行为均不变。 ## 0.0.475 (2026-11-08) ### 后端 - **修复 2026-11-07 逻辑审查全部问题(BUG 6 条 + 候选 5 条)**(报告 `docs/code-review/2026-11-07-logic-bug-review-01.md`,存在性证明用例已全部转正为回归测试): - **grep_search rg 分支把 `-` 开头的 pattern 当命令行 flag**:合法 flag(如 `-n`)被吃成选项后静默返回「0 命中成功」、非法 flag(如 `--foo`)把合法搜索误报成工具故障——pattern 改以 `-e` 显式绑定(agent-cli 本地同型缺陷同步修复)。 - **容器 read_bytes 把 0 字节文件判成读取失败**:判空从 `!base64` 改为 `== null`——空串是空文件的合法编码,docker 模式下读取/发送/编辑空文件的会话恢复正常(host 模式本就正常)。 - **哨兵复制(copyFrom)在请求头键未下发时静默丢弃源哨兵全部请求头**:改为整体继承源行解密值(与 body 的 undefined=继承语义对齐;显式 null 仍为清空)——官方 CLI 文档示例(`--copy-from` 不带 `--headers`)复制的哨兵不再无凭据、401 错误页不再被当正常基线。 - **重试入口不消费 pendingCancels**:FAILED 会话点「重试」后、提交前窗口点「停止」被静默吞掉、任务照跑——注册 cancelFlag 前按入口时间消费取消标记,命中即按取消收敛(不提交执行、记录不卡 RUNNING)。 - **容器 agent 重连后 connectionDead 永不清除、健康容器被强制重建**:一次通道抖动(已自动重连)后下次工具调用会把健康容器 stop+rm+run,shell/PTY/后台任务全丢——hello 重连成功即清标记;旧连接替换先从连接表摘除,不再把正常替换误报为连接失效。 - **工具结果摘要失败/超时语义失真**:wait_subagents 等满超时不再谎报「后台子代理已完成 (0 个结果)」;ask_user_questions 仅「等待超时/会话取消」标「超时或取消」、参数非法等即时失败改标「(错误)」(超时结果补结构化 `timed_out` 标记)。 - **候选 5 条**:容器内 MCP stdio connect/listTools 加 60s 超时与失败清理(不再每轮执行泄漏子进程);一次性任务换 cron 不再绕过「有未结算工作禁止重开档期」不变量(重试运行中判据补 hasRunningRun、旧档期收尾按新 cron 重排,新计划不再被抹掉);deleteSession 运行中拒删判据移入事务内复查(消除 check-then-act 窗口);POST 探针有 body 时按 utf8 字节数代填 Content-Length(要求定长的目标不再 411、不再建假基线);失败退避统一 Node 时钟(不再混用 MySQL NOW(),DB 时区差异不再让退避整体漂移)。 ### 前端(桌面 / Web) - **边路会话发送收尾不再无条件清空输入框**(2026-11-07 审查候选):上传/连接/等待 user_message_saved(上限 60s)窗口内继续打字,收尾时不再被静默清空且不可恢复——与主会话同口径的「输入未改才清空」守卫(`clearInputIfUnedited`),附 8 例回归测试。 ### CLI(mao-agent) - **修复 2026-11-07 逻辑审查全部问题(BUG 1 条 + 候选 3 条)**: - `/resume` 切入运行中会话(含启动续接路径)后,等待期间排队的输入在续接结束时自动消费——不再静默滞留、也不再在下一条消息提交时乱序先行发出。 - 本地 grep 同型修复:pattern 以 `-e` 绑定,`-` 开头的搜索词不再静默 0 命中/误报失败。 - 打印 / JSON 模式失败时输出 error 帧原文:text 模式 stderr 打「执行失败:…」、json 终态对象带 `error` 字段,脚本消费方不再只见 `status=FAILED` 无原因。 - 审批「已提交」态 30s 兜底收尾:回声因服务端重启/断线永不到达时模态可关闭,不再吞掉全部按键(含 Ctrl+C)。 - MCP HTTP `tools/call` 加超时并给出友好超时文案(病态 trickle 响应不再让调用永不返回)。 ## 0.0.474 (2026-11-08) ### 后端 - **修复 Docker 模式会话内 CLI 全部断链(0.0.473 回归)**:0.0.473 把技能视图按 (user, agent) 物化到 `skill-views/{u}/{a}/{skill}`、容器挂载收窄为 `{u}/{a}` 后,`deps/{u}/npm` 里更早安装的 npm 全局 CLI 软链仍相对指向历史路径 `skill-views/{u}/{skill}`,而容器内该路径不存在——`dama-cli` / `access-cli` / `xxl-job` / `bigdata-cli` / `lark-cli` / `sls` / `apollo-cli` 等全部 `command -v` 失败,脚本报 `FileNotFoundError`(宿主机旧副本残留掩盖了该问题,仅在容器内复现)。现由 `runtime-agent` 在容器启动时于用户视图根为当前 Agent 的每个技能补 `{skillName} -> {a}/{skillName}` 相对软链(仅补缺失、不覆盖既有条目、幂等、失败仅告警),恢复历史软链解析;存量容器在下一次按代码漂移自动重建后生效。 ## 0.0.473 (2026-11-07) ### 后端 - **Docker 容器隔离维度从「人」升级为「人 + Agent」**(方案 docs/plan/2026-11-07-user-agent-container-isolation-technical-design.md,决策与调研见 docs/research/2026-11-07-container-isolation-user-agent-dimension.md):同一用户的不同 Agent 各自独占一个容器(`mao-user-{userId}-agent-{agentId}`),其他 Agent 的技能视图在容器内从此不可见——此前 `skillViews/{userId}` 整根挂载可读该用户全部 Agent 关联过的技能视图。skill 视图按 (user, agent) 物化为恒定路径(`{skillViewsDir}/{userId}/{agentId}/`),skillNames 增删/技能源更新只改目录内容、零容器重建;share 目录维持整根 rw 共享(含团队经验库与管理员投放的共享文件,不做按 Agent 收窄,经验库跨 Agent 收口仍靠工作区软链 + 提示词);Unix socket 通道、PTY 终端、预热、admin 容器管理全部按复合键隔离。同用户多 Agent 并存互不挤占单容器资源上限;重建的爆炸半径从「该用户全部会话」缩小到「单个 Agent 的会话」。 - **会话内切换 Agent 的容器侧行为**(已拍板接受中断):切换不打断当前轮(agentId 按轮快照),下一轮路由到新容器(PATCH 成功即预热、无冷启动等待);旧持久 shell 的 session_id 失效并报「请重新创建 shell 会话」,已 attach 终端随旧容器存活到关闭或回收,async 后台任务在旧容器成孤儿。群聊(飞书/钉钉)路由与技能同步本就按发言者运行身份,与复合键天然一致;bot 热切换 Agent 与会话内切换同口径。 - **用户级共享数据维持不变**(已拍板):deps/HOME/tmp/workspace/用户个人技能与 share 目录(整根)继续共享挂载;host 模式、LOCAL 模式、桌面端零变化;无 DB 迁移。 - **升级自动收敛**:上线后存量容器首次使用时按新挂载指纹自动重建一次(既有机制);`container-gc.sh` 新增旧命名孤儿容器(`mao-user-{纯数字}`,升级后必为孤儿)与三级 socket 目录的清理规则。 ### admin - **容器管理面板按 (用户, Agent) 展示**:列表新增「Agent ID」列,单行「重建」按钮精确回收该 (用户, Agent) 容器;`POST /v1/users/:id/container/recycle` 支持 body `agentId`(缺省保持整用户回收语义)。 ## 0.0.472 (2026-11-07) ### 前端(桌面 / Web) - **修复边路任务执行中刷新页面后,正在执行的工具调用不回显**:此前刷新后只显示已完成的历史工具,正在执行的 shell 调用要等结果出来才凭空冒出。根因是主会话修复「刷新后在途工具回显」时只做了两段配套——后端订阅重放在途调用(边路会话同样生效)+ 前端拉 REST 历史时保留重放写入的流式气泡——而边路 Tab 拉历史时没传保留标记,重放先写入的「执行中」气泡被随后到达的 REST 历史整表覆盖吞掉。现边路面板与主会话 / 子代理面板同口径:历史覆盖时保留本地正在流式的内容(判定在响应到达后做,重放帧若在请求期间写入也能被认出),气泡继续承接后续结果事件并随之收尾;服务端只在会话活跃时才重放在途调用,不会保留出无人收尾的幻影转圈。 ## 0.0.471 (2026-11-07) ### 前端(桌面 / Web) - **键盘、焦点与命中区可达性**(方案 docs/plan/2026-11-07-keyboard-focus-hit-area-technical-design.md):①发完消息焦点回归输入框——点「发送」按钮后光标掉到 body、连发需重新点输入框,现在 `handleSend` 在 emit 后统一归还焦点(主聊天/边路/队列全部发送路径单点覆盖,输入框执行中 disabled 时仍不抢焦点);②「已执行 N 个步骤」折叠块键盘可达——由纯点击 div 改为 `