Skip to content

Tags: AnranS/botmux

Tags

v2.32.0-canary.0

Toggle v2.32.0-canary.0's commit message
canary: workflow runtime v0.1.4-a cancel responsiveness

新功能
- 用户从 IM/Dashboard 取消 workflow run 后,daemon 立刻向所有 in-flight
  subagent worker 发 SIGINT,5 秒优雅 grace,超时 SIGKILL 兜底
- orchestrator 看到 cancelRequested 后短路,不再派发新工作,避免 late
  activitySucceeded 把 run 推到错误终态
- cancel 真等 worker exit 才落 activityCanceled,terminal 事件不再超前于
  worker 实际停止
- cancel 期间 quiesce 和 hardDeadline 自动 disarm,cancel-wins 语义闭环
- WorkerSpawnResult 新增 kind:'cancelled',带 cancelOriginEventId 链接原始
  cancel 事件

兼容性
- WorkerSpawnInput 新增可选 cancelSignal: AbortSignal(向后兼容)
- WorkerSpawnResult 新增 kind:'cancelled' (现有 success/failure 不变)
- 事件 schema 不变,replay 不变

测试
- 181/181 通过(workflow-spawn-cancel 5 + responsiveness 6 +
  finalize-e2e 1 + 现有全套)
- 5 个 codex review 轮回收住 dedup race / B1 worker exit / M1 cancel-wins

需要 dogfood 验真实 Claude/Codex CLI 子进程对 SIGINT 的现场响应。

v2.31.1

Toggle v2.31.1's commit message
v2.31.1 — 群内授权卡片交互反馈修复

修复 v2.31.0 中群内授权卡片「点了没反应」的问题:
- 授权成功后会撤回授权卡片,并在原话题 @ 被授权人,提示其已可使用机器人
- 点「拒绝」时卡片就地更新为「已拒绝」
- 万一卡片超过飞书可撤回时限、撤不掉,也会就地把卡片更新成最终结果,不再无反馈
- 内部:消息撤回接口改为如实返回成功/失败,撤回失败时才走兜底更新

v2.31.0

Toggle v2.31.0's commit message
v2.31.0:群内授权 + CoCo 接入稳定性

新功能
- 群内授权:群主可直接在群里用 /grant、/revoke 给成员开通或收回机器人使用权限,配授权卡片二次确认。内置防重放、拒绝冷却节流,并支持按邮箱反查成员。

修复与改进
- CoCo 消息偶发卡在输入框、表现为「回复上一条」的问题:粘贴改用 bracketed-paste 标记,确保整段内容一次性提交。
- CoCo「没能确认提交」误报:CoCo 新版本写入历史记录的时机变化,导致提交确认逻辑偶发漏判而错误告警;现已兼容,消息其实已送达且会正常回复。
- 完整解析飞书卡片消息:消息、历史、引用场景都能正确还原卡片内容。
- 建群时可绑定 oncall 工作目录。
- tmux 通道更稳健:send-keys 失败不再拖垮 worker,并补充 CLI 退出诊断信息。
- 兼容 Claude Code 自定义 Chat 快捷键。

v2.31.0-canary.7

Toggle v2.31.0-canary.7's commit message
canary: workflow runtime v0.1.3 (approve/reject + i18n + catalog + 并发)

新功能
- Dashboard 直接 approve/reject humanGate,无需回飞书卡片;失败 run 加摘要 + 移动端 UI
- Workflow 页面 zh/en i18n,topbar 语言切换 + localStorage 持久化
- Workflow Catalog: GET /api/workflows/definitions[/:id] 公开读 + cookie 受限 POST .../run;
  详情页展示 def + params schema + JSON,Run 后跳详情;invalid_params 结构化 issues
- runLoop 并发 dispatch:同 tick 内 ready 节点 Promise.allSettled 并行,maxConcurrency
  封顶(默认 4),per-bot tick 内串行;completeNode/Run 串行收尾
- pre-attempt dispatch 抛错直接 no-progress,避免无 attemptId 时重试到 maxTicks

文档/示例
- 内置 parallel-fanout-demo workflow

兼容性
- WorkflowDefinitionSchema.defaults.maxConcurrency 新增可选字段(向后兼容)
- 事件 schema 不变,replay 不变

已知限制(v0.1.4 单独切刀做)
- cancel 在 in-flight 并行期间不主动打断 worker
- 没有可插拔 cancelPolicy / 注入 prompt 软取消

v2.31.0-canary.6

Toggle v2.31.0-canary.6's commit message
canary: params 类型校验/默认值深化 — CLI 拉齐 IM 严格 + --param-json + skill 同步

亮点
- 共享 coerceWorkflowParams 模块 (src/workflows/params.ts): 单一来源,IM
  /workflow run 和 CLI botmux workflow run 走同一条严格校验链。
- CLI 拉齐 IM 严格度: 之前 CLI 只 check required, type 全不校验,默认值不
  materialize, 未知 param 静默通过。canary.6 起所有 param 入参一致行为:
  未知 param reject、type 严格(string/number/boolean/object/array)、optional
  默认值 materialize、错误聚合一次给全 issue。
- --param-json key=<json>: CLI 新入口,thread object/array(或想保留 JSON
  类型的标量)直接传 JSON 字面值,例如 --param-json tags='["x","y"]' 或
  --param-json config='{"mode":"safe"}'。--param 标量、--param-json
  结构化、两个都接 --flag value 和 --flag=value 两种 syntax。
- workflow-create skill 文档同步: Schema 速查补全 params 五字段
  (type/required/default/description/format),明确 CLI/IM 启动差异+
  object/array 限制,补 5 条错误样例(未知参数/缺少必填参数/必须是 number/
  必须是 boolean/object array 用 --param-json),LLM 不会再编错指令。
  builtin-skills 锁断言 +8 条,防文档漂移。

测试
- 16 case 共享模块单测 (test/workflow-params.test.ts): 字符串 channel
  七条 + RawParamInput 混 channel 七条 + 错误聚合 + 默认值 verbatim。
- 4 case CLI integration (test/workflow-cli.test.ts): 未知 param reject,
  type=number 严格,--param-json object/array,坏 JSON 报错。
- builtin-skills 5 case + 8 锁断言: workflow-create skill 关键词全覆盖。
- IM 端 13 case 零回归。

升级影响
- npm i botmux@canary 即可装到 v2.31.0-canary.6。
- 老 CLI 用户的 \`--param key=value\` 流程不变;新增 \`--param-json\` 入口
  完全 additive。
- 严格校验是 CLI 行为收紧: 之前 \`--param days=abc\` 当 type=number 能跑
  现在 fail-fast 报 "参数 days 必须是 number"。IM 端这条一直是这么做的,
  CLI 现在对齐。
- 共享模块抽出后 IM workflow-slash-command.ts re-export coerceWorkflowParams
  保持原签名,IM 端调用方零侵入。

dogfood 重点
- 跑现有 weather-trip-plan 等 workflow,验证 --param key=value 行为不变
- 试 \`--param-json\` 传 object/array 参数
- 故意写错 param name / type 看错误提示是否清晰
- workflow-create skill 重新生成一个 workflow,看 LLM 是否按新文档教 --param-json

v2.31.0-canary.5

Toggle v2.31.0-canary.5's commit message
canary: step detail v2 收口 + promptRef + dashboard auth refactor + rou…

…te smoke

亮点
- promptRef 三刀(4b80db8 schema + efc1e5a runtime spill + a44ac62 卡片
  与 dashboard): ≥1 KiB 的 humanGate prompt 自动落 blob,事件内只携带
  OutputRef-shaped promptRef + ≤800B 短 promptPreview。飞书审批卡片
  始终用 preview + "完整内容见 Web 详情" 引导,绝不读 blob。dashboard
  Node I/O 新增 Wait prompt 块按 64 KiB ladder 读完整文本。互斥
  invariant 在 parseEvent / safeParseEvent / EventLog.append 三路都
  拦得住坏 draft;历史 2-3 KiB inline prompt 兼容性保留(schema 不加 max,
  1024 阈值是 producer 策略不是 wire format 约束)。
- 86fc623 step detail v2 收口: renderAttemptDetail 一直只显 errorCode,
  现在补上 errorMessage 一行 pre-wrap 渲染,operator 能直接看到
  "humanGate.prompt too large 4950 bytes" 这种诊断;加 ops-projection
  单测锁住 previewAttemptLog 是 tail 语义(70 KiB filler + 头/尾
  sentinel,以后误改回 head-window 即挂)。
- 759f3e6 dashboard auth refactor: 抽 decideDashboardAuth 纯函数挂在
  src/dashboard/auth.ts,把 canary.3 加的 public-read 决策(workflow GET
  / 静态 shell 免 cookie,其它 401)从 dashboard.ts 内联 24 行抽出来,
  附 15 个矩阵单测覆盖 public 三条 / protected 七条 / ?t= cookie set
  五条 + 边界。
- c36b64d HTTP route smoke (codex): 真 createServer + handleWorkflowApi
  e2e,覆盖 GET workflows runs/snapshot 无 cookie 200, POST cancel 无
  cookie 401 且不 proxy, GET sessions 无 cookie 401, /__health 200,
  / 200, /assets/missing 404 (boundary 不挡), /?t=correct 302+Set-Cookie,
  /?t=wrong 在 public 路径 200 不 mint 错 cookie / 在 protected 路径
  401, cookie 携带 correct token 访问 protected 200。

升级影响
- npm i botmux@canary 即可装到 v2.31.0-canary.5。
- 老 daemon 进程对 promptRef 字段走 strip mode silent degrade(读不到
  promptRef → AttemptState.wait.prompt 落空,卡片显空),建议整批升级。
- decideDashboardAuth 是纯重构、行为零变化,dashboard cookie / public-read
  / set-cookie redirect 跟 canary.4 完全一致,30/30 e2e + 单测验证过。

dogfood 重点(codex 划)
- weather-trip-plan 大 humanGate prompt 自动 spill,卡片只显 preview,
  dashboard 能看完整 Wait prompt
- dashboard public-read / cancel write-protect 没被 refactor 影响
- Node I/O 的展开、滚动、errorMessage、terminal log tail 都稳定

v2.31.0-canary.4

Toggle v2.31.0-canary.4's commit message
canary: humanGate 大 prompt 自动 spill 到 promptRef + promptPreview

亮点
- waitCreated.payload 字段级 blob spill:> 1KiB 的 humanGate prompt 自动
  落 <runDir>/blobs/<hash> blob 文件,事件内只携带 OutputRef-shaped promptRef
  + 短 promptPreview。weather-trip-plan 等大 markdown 工作流不再被 4KiB
  EventLog inline cap 卡死。
- 历史 / 小 prompt 100% 兼容:schema 上 prompt 仍是 z.string().optional()
  不加 max,1024B 阈值只是 producer 策略;老版本 2-3KiB inline prompt 不
  受影响。
- 互斥 invariant:prompt 和 promptRef 同存 / promptRef 缺 promptPreview
  都会在 parseEvent / safeParseEvent / EventLog.append 三条路径上抛
  ZodError,producer 写坏 draft 也能被拦下。
- 飞书审批卡边界明确:卡片永远只用 promptPreview,不读 blob 文件——
  否则 EventLog 4KiB 问题只是搬到飞书消息体积 / payload 上限。promptRef
  存在时卡片自动加 "完整内容见 Web 详情" 引导。
- dashboard Node I/O 新增 Wait prompt 块,有 promptRef 时按 64KiB
  BlobPreview ladder 读完整文本,跟 input / output / log 同构。
- replay 严格不读 blob:promptRef / promptPreview 字段原样落到
  AttemptState.wait,消费端(card-builder / dashboard)按需读。

测试 165/165 绿,跨 events 模式 / append 路径 / replay / runtime / 卡片 /
dashboard ops-projection 六文件。

升级影响
- npm i botmux@canary 即可装到。老 daemon 进程读新 events 时 strip mode
  自动丢 promptRef 字段(silent degrade,不 crash),建议整批升级再验证大
  prompt workflow。

v2.31.0-canary.3

Toggle v2.31.0-canary.3's commit message
canary: workflow runtime 字符串模板 + OOM 根因修复 + dashboard public-read

亮点
- $ref 之外补一套字符串内 ${...} 内嵌(仅标量),允许在 prompt 里直接
  拼 params.city / fetchWeather.output.summary,不再被迫加上游 planRequest
  wrapper 字段。
- workflow worker OOM 根因定位并修复:cwd 上的 ~ 没展开导致 fork ENOENT,
  错误路径无 settle guard 反复 reject 把 event loop 塞满。fork cwd 统一
  expandWorkflowWorkingDir + 单次 settle guard + spawn-mem 面包屑(事后
  可在 attempt log 看到逐段耗时和 worker pid)。
- humanGate 大 prompt 不再让 EventLog.append 硬抛:dispatchGate 估算
  waitCreated payload 大小,超阈值直接 activityFailed(InputBindingFailed,
  userFault) 并提示用 summary 字段。
- 跨 daemon bot 解析回退共享 bots.json:多 daemon 各自只装载自己那只
  bot,workflow subagent 指向兄弟 bot 时不再 "bot not found"。
- dashboard /api/workflows/* GET 和 SPA shell 放开免 token,写操作仍校验
  cookie;run 详情页新增 Node I/O 面板,每个 attempt 把 input /
  resolvedInput / output / 终端 log 折叠成可读 BlobPreview。
- 顺手修审批卡片里 workflowRunDetailUrl 的 /#workflow/<id> → /#/workflows/<id>,
  老链接点开是空白页。
- daemon-0 默认 5s 打 [memdiag] 内存快照,--max-old-space-size 提到 8GB;
  worker.ts 在 BOTMUX_WORKFLOW=1 时跳过 web 终端 + 截图 + 分析器,
  PTY 转写到内存里只在见到 </WORKFLOW_OUTPUT> 时 emit final_output。
- workflow-create SKILL.md 同步双语法 + weather-city 范例 C,下次新建
  workflow 时 LLM 会直接用 ${...},不再发明 planRequest wrapper。

dogfood
weather-trip-plan 三节点(coco fetch / aiden plan / feishu-send + humanGate)
端到端跑通:summary/plan 拆分 + ${...} 注入 params.city + humanGate 卡片
点通后发完整 markdown 到群。

v2.31.0-canary.2

Toggle v2.31.0-canary.2's commit message
v2.31.0-canary.2 — Workflow Runtime(dogfood 修复轮)

基于 v2.31.0-canary.1,按真实 dogfood 反馈修两个 workflow 设计阶段的常见坑:

dogfood 撞到:LLM 老实按 `botmux bots list` 输出的 `name` 字段填 subagent.bot,
但 name 来自 Lark `listChatBotMembers.displayName`(admin 可改),而 runtime
`resolveBotSnapshot` 严格匹配 `config.name / botName / larkAppId`。跨 daemon
时 botName 拿不到、`config.name` 经常 unset,唯一可靠的全局 ID 是 larkAppId。

- `botmux bots list` 两条输出路径都加 `larkAppId` 字段 + `workflowBot` alias
  (本地配置 bot = larkAppId;外部 introduce bot = null),让 LLM 明确知道
  workflow.subagent.bot 应填哪个值
- `createRun()` 找不到 subagent bot 时错误信息升级:明确"用 botmux bots list、
  填 larkAppId 不是 display name",并附上 available larkAppIds 让 LLM
  self-correct
- `botmux-workflow-create` skill 硬规则 2 改成强制填 larkAppId,三个范例的
  bot 字段从具名(如 "claude-loopy")换成占位符 "cli_xxxxxxxxxxxxxxxx"
- 常见错误新增 sharp negative example: "subagent.bot 填了 displayName
  (如 claude-loopy 或 aiden-oncall(d2)) 而不是 larkAppId:跨 daemon 必 fail"

dogfood 撞到:LLM 把文件写到自己 cwd 的 `./workflows/`,daemon 进程 cwd 不
一致就找不到。runtime search path 是 \$CWD/workflows/ + \$HOME/.botmux/workflows/,
后者作为全局位置最稳。

- SKILL.md 硬规则 3 改为绝对路径:\$HOME/.botmux/workflows/<id>.workflow.json
- Step 4 / Step 5 全程换成绝对路径口径
- 常见错误新增:写到 ./workflows/ 而不是 \$HOME/.botmux/workflows/,daemon 找不到

- 38 测试文件 / 499 用例全绿(含新的 bots-list-output / workflow-run-init 测试)
- targeted: 21/21(builtin-skills + bots-list-output + workflow-run-init + workflow-cli)

  npm i -g botmux@canary
  botmux restart  # 或 pm2 restart all

  npm i -g botmux@latest

v2.31.0-canary.1

Toggle v2.31.0-canary.1's commit message
v2.31.0-canary.1 — Workflow Runtime(事件驱动流程编排)

引入 botmux 流程编排能力。事件驱动 workflow runtime,支持三类节点 + DAG 依赖 + 数据流 + 重试/超时/审批 + 故障恢复 + 四入口 cancel。

- 流程定义:`workflows/*.workflow.json`,三种节点类型(subagent / hostExecutor / humanGate)
- 启动:`botmux workflow run <id>` 或 IM `/workflow run <id>`
- 数据流:`$ref: "<nodeId>.output.<path>"` 引上游节点输出 + `$ref: "params.<path>"` 引启动入参(支持嵌套)
- 审批:飞书卡片 Approve / Reject / 取消 Run,humanGate.approvers 白名单 enforce
- Cancel chain 四入口 + e2e 全部锁定:CLI / IM slash / IM card / Dashboard
- Dashboard Workflows 标签页:Run List(5s 刷新) + Run Detail(2s 刷新,timeline + dangling + cancel)
- 故障恢复:daemon 重启自动 cold-attach owned runs,dangling effect 通过 provider reconciler 收敛,worker crash 标 WorkerCrashed retryable
- 新内置 skill botmux-workflow-create:根据自然语言描述生成 workflow.json,6 步流程(复述拆分 → bots list → 设计稿 → 写文件 → validate → 启动)
- 新 CLI 子命令:botmux workflow validate / ls / tail / show
- 37 测试文件 / 495 用例全绿

  npm i -g botmux@canary
  botmux restart  # or pm2 restart all

不会污染 latest(默认 npm i 仍拿 stable)。

  npm i -g botmux@latest