Files

11 KiB
Raw Permalink Blame History

CHANGES — 本 fork 的改动

给接手这个 fork 的人。上游是 deepseek-ai/dsh-superagent-prototype(DeepSeek 团队的研究原型), 基线 = 6337fc8(pristine);其上是本 fork 的 11 个提交(4379973 → cf40686)。

总述

本 fork 在上游研究原型之上做了三件事:

  1. 新增 Gitea Source:面向自建 Gitea 实例的纯拉取轮询——不用 webhook、不需要外网回调, 部署机器无需公网入口。设计决策见 GITEA-DESIGN.md。
  2. Windows 全面移植:上游原型只在 Linux/macOS 上跑通,本 fork 修复了四个卡死部署的 Windows 缺陷(都在 4379973 内,见下文)。
  3. 部署 / 运维层若干改进:面板头部一键切换部署默认模型、Source 活性与轮询停滞上报、 结束工单执行目录的磁盘回收、复用会话的角色模型重新指认等。

提交清单

按时间序;每条的"改了哪里"都对照 git show --stat 核实过。

4379973 Sources: add Gitea; fix Windows shims for shell tool, repo paths and stateDir

最大的一笔,Gitea Source 全家桶 + 四个 Windows 缺陷修复合在同一个提交里。

Gitea Source:新增 src/sources/gitea.ts(Source kind、轮询 round、GiteaConfigSchema、 插件入口)、src/sources/gitea-api.ts(最小 REST 客户端:凭据只从 env[tokenEnv] 读、zod 校验、分页、可注入 fetch)、src/sources/gitea-trigger.ts、src/sources/gitea-channel.ts; src/kv.ts 加 gitea 命名空间(since / retry / 每线程与每流游标);src/deployment.ts 加 GiteaSetupSchema、giteaOnly()、resolveGiteaDeployment();src/app/setup.ts 加 source:gitea 分支与 resolve() 的 gitea-only 路径;src/setup.ts 加 gitea 的 setup problem 码;src/infra/environment.ts 加 Gitea 的 gh 封禁 shim 与 git 凭据 store;bundle 接线 (cordis.patch.yml 插件行默认 disabled、package.json 导出 ./gitea-watch、 tsdown.config.ts 入口);src/client/locales.ts 文案;docs/007 模块与测试表; GITEA-DESIGN.md;tests/gitea.spec.ts。

四个 Windows 缺陷:

  • stateDir:src/deployment.ts 的 absolute() 校验正则 /^\// 拒绝 D:\... 盘符路径 → 扩为接受盘符与 UNC。
  • worker shim / git 凭据:Gitea 的 git 凭据不走 POSIX shell 型 credential helper,改用 git 内置的 store --file=...(src/infra/environment.ts,代码注释:Windows git 行为一致), 写入 gitconfig 的路径反斜杠统一换成正斜杠。
  • 仓库路径:Gitea 的 API 不认 %2F 编码的 owner/repo,resolveGiteaDeployment 直接以 字面 repos/${repository} 请求(src/deployment.ts)。
  • shell 工具:src/app/sessions.ts 给 master 会话的 tools.restrict 白名单硬编码 'bash',Windows 上注册的 shell 工具是 pwsh,症状 = 既有会话 resume 必挂 unknown global tool → 新增 SHELL_TOOL = process.platform === 'win32' ? 'pwsh' : 'bash' 并让白名单与 WORK_TOOLS 都用它。

e8b91ab Infra: write gitea git-credentials line with the deployment's own scheme

动机:凭据行写死 https://,与 http 实例的 credential.<url>.helper 查找不匹配,git 取不到 凭据。改了哪里:src/infra/environment.ts 的 writeGiteaCredentials() 改按部署 URL 自身的 scheme/host 写这一行。

589b5a6 Sources: accept login:password Basic credential for Gitea (API + git store)

动机:当时所用实例的 token 校验链损坏,需要以账号密码 Basic 顶替。改了哪里: src/sources/gitea-api.ts 新增 giteaAuthorization()——凭据含 : 走 HTTP Basic,否则按 token <x>;src/infra/environment.ts 的 writeGiteaCredentials() 同一规则(Basic 时 store 只存冒号后的密码段)。API 与 git 两路一致。历史注记:上游 Gitea 1.26 收紧 Basic 后本部署 已改回细粒度 token,此提交保留为兜底能力(见"部署实战要点")。

a662188 Panel: switch the deployment default model from the header

动机:面板只能显示 DSH 默认模型不能改,换 Executor / Assessor 模型要手工编辑 profile。 改了哪里:新增 src/app/default-model.ts 的 switchDefaultModel()——走 sessionController.selectModel(与 DSH 模型选择器同一路径,写 profile 的 agent-default-model),按 catalog 校验、值未变报 unchanged、后台保存靠轮询确认; src/app/http.ts 加 PUT default-model 路由;src/client/default-model.tsx 头部控件; tests/default-model.spec.ts。只影响新会话(既有会话见 dee76b1 / acacbb2)。

b348d69 Overview: report liveness and a Source whose poll loop stopped

动机:轮询循环死了的服务照常响应每个请求,面板看不出来。改了哪里: src/app/views/overview.ts 新增 liveness(startedAt / uptimeMs / lastPollAt / pollAgeMs / polling),Source 连续 3 个自己的轮询周期没有新动静(且不低于 180 s)报 stalled problem; src/app/http.ts、src/app/runtime.ts 传入进程 startedAt;src/client/overview.tsx 展示。

3bee231 Execution: reclaim the directories of Ended Tickets after a retention

动机:每张工单留下 clone 与产物,长期吃磁盘。改了哪里:新增 src/app/reclaim.ts—— Reclaimer 每小时扫一次执行根,删超过保留期的 ended 工单目录;src/policy.ts 加 executor.reclaimAfterDays(默认 14,0 = 关闭,0–365);面板 overview / execution 显示回收 摘要。防误删四道闸:过了保留期、路径必须在执行根内、目录 basename 必须等于 execution.name、该目录不在任何 open 工单的目录集中。

d527ad8 Sessions: account a restored Session to its Workspace

动机:数据迁移后面板看不到 worker 会话——ensure() 只在新建会话时登记 Workspace,从盘上 恢复的会话永远不在 Workspace 记录里。改了哪里:src/app/sessions.ts 改为对每次 ensure 都 幂等 workspaceRegistry.create(cwd),未记账的既有会话补 attachSession(失败只 warn,不拦 启动)。

dee76b1 + acacbb2 Roles: re-point reused Sessions when a role model drifts

动机(dee76b1):角色模型只给新建会话播种,旧会话被唤醒后永远用旧路由——症状是改了 executor.model 之后老工单仍用 DeepSeek,新开任务才生效。改了哪里:src/app/role-models.ts 新增 alignRoleModel(),dispatch 时比对既有会话的持久 selection / header 与配置的角色模型, 漂移则 append model/selection 事件;src/app/sessions.ts 对非新建会话调用它。

关键修正(acacbb2):只 append 事件不刷内存缓存,真机复跑下一半秒的装配仍用旧模型—— prompt 装配读的是 Session Controller 的内存 selection。改为优先调用 sessionController 实例内部的 agents.selectForNextRequest()(append + 刷 Agent 缓存,且不动全局默认),该 内部面不存在时回退公开 selectModel()(会顺带保存默认,换正确性)。 tests/role-models.spec.ts 钉住快路径与回退路径两条。

17be661 Default model: let the picker choose a reasoning effort

动机:头部快捷菜单只有 provider/model,catalog 声明的思考强度只能去 Eval / Execution 表单 里手打。改了哪里:src/client/default-model.tsx 为目录里带 efforts 的行展开二级菜单(模型 默认 + 各档位);src/app/default-model.ts 校验 effort 属于目录、只改强度也算真切换、转发 带 brand 的 id;docs/006、docs/007 同步。

cf40686 Sources: carry the Gitea kanban convention in the Source's own instructions

动机:看板约定是部署侧约定,不该写进用户仓库的 AGENTS.md。改了哪里:src/sources/gitea.ts 注册环境变量 DSH_SUPERAGENT_GITEA_KANBAN,约定文本写进它自己的 description,经既有的环境 说明机制注入 worker 提示词。约定内容:Issue 挂在项目看板上,列名与标签同名,现共 9 列 = 文档性维护、已完成、进行中、下一顺位、排队、等外部资源、暂缓、观察、开放问题(首列原名 Uncategorized,已改名);该 Gitea 版本没有 Projects API,改标签或移卡后跑外部同步脚本 card-sync.mjs,只碰这个看板、不直接操作数据库。

测试基线

上游原型在 Windows 本机跑 pnpm test 有约 38 个固有失败(tmux、lark-cli、POSIX shims、 deployment 相关、docs 测试的 path.sep 枚举、NTFS 语义等)。本 fork 的门禁口径 = 零回归: 失败集合必须始终 ⊆ 基线,即 pnpm typecheck 全绿且失败集合不新增条目。新增测试文件: tests/gitea.spec.ts(21 例)、tests/role-models.spec.ts(14 例)、 tests/default-model.spec.ts(14 例)、tests/reclaim.spec.ts(5 例)。

Gitea 部署实战要点(运维备忘)

  • 1.25 / 1.26 / 1.27 均无 Projects REST API,Projects API 首发于 1.28。判断以在跑的二进制 为准——main 分支的 swagger 是预览文档,≠ 已发布能力。看板同步只能靠外部脚本(见 cf40686)。
  • 1.26 起密码 Basic 在 API 写路由被拒(报 token is required),只读路由仍可用;必须用 细粒度 token。scope 按最小需要给,本部署用的例子:write:issue + write:notification + read:user + write:repository。
  • 一个凭据两用:同一个 token 既做 API 认证头(token <x>)也做 git 的 HTTPS 密码——本 fork 的 gitea-api.ts 与 environment.ts 凭据 store 是同一规则,轮换时一处换新两处都要动。
  • 实例若 token 校验链坏掉,可临时回退 login:password Basic(589b5a6);升级 1.26 后写 路径必须回到 token。
  • Windows git 兼容性:MSYS bash 自带的 ucrt64 构建 git 2.56 与该 Gitea 实例的 http/2 协议交互挂起(clone 卡死);Git for Windows 2.39 正常。worker 用的是系统 PATH 里的 git, 不受 MSYS 那份影响,但手工在 MSYS 环境里跑长 clone 时注意。
  • 插件不自动升级:装时锁版本。升级纪律=一次升一个、升前看 changelog、升后跑门禁+验 overview;带本地热补丁的插件(如 workbuddy-to-dsh 桥脚本)升级会盖掉补丁,升完要重打补丁 并核对两侧桥脚本哈希一致(不一致时 buildDiff 判 stale,桥互杀重启);重度依赖在跑的插件 没有明确收益不升。详见 INSTALL.md「插件升级纪律」。

已知限制

  • 无 webhook,纯轮询(默认 60 s,可配 60–3600 s);响应速度换部署侧零入站端口。
  • bot 不自动 merge PR,人工合并是设计(Gitea 侧 auto-merge 在 MVP 裁剪线之外,见 GITEA-DESIGN.md)。
  • Gitea API 无 is_bot 字段,非 agent、不在名单里的 actor 一律按 human 处理;自动化账号要 手工维护进 Policy 的 bots 名单。
  • 结束的工单可被 human 唤醒,所以执行目录回收留有保留期(默认 14 天,见 3bee231)。