dsh-plugin-teamflow 0.1.8 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -1
- package/README.en.md +14 -3
- package/README.md +6 -3
- package/lib/client.js +922 -259
- package/lib/descriptors.mjs +9 -0
- package/lib/host.mjs +2724 -563
- package/lib/store.mjs +55 -6
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,33 @@
|
|
|
2
2
|
|
|
3
3
|
> 本插件首次公开发布版本为 **v0.1.0**;发布前的内部迭代(v0.3~v0.13)记录于 `AGENTS.md` §5,对外统一归到 v0.1.0。
|
|
4
4
|
|
|
5
|
-
## [0.1.
|
|
5
|
+
## [0.1.9] - 2026-09-16
|
|
6
|
+
|
|
7
|
+
### 新增
|
|
8
|
+
- **host 侧响应与产物语言跟随界面语言(中英双语,P2)**:英文用户此前看到的工具返回、完成汇报、流水线日志与产物正文(PRD/QA-REPORT/ACCEPTANCE)仍是中文,产品呈现割裂。语言源链=**客户端推送**(浏览器当前语言/系统探测,经既有 Remote 面 `teamflow/setLocale`)> **宿主用户显式选择** > **`en` 默认**;run 起跑时解析一次并落 run 级快照(`journal.locale`)——**同 run 语言一致、断点续跑沿用、切语言只影响之后新起的 run**;headless(无客户端)走兜底链不报错。覆盖面:11 个 prompt 工厂 + AGENTS.md/memory 模板 + 产物语言指令 + 工具返回/分支决策/完成汇报/日志/诊断/state 注入块/triage 理由。**判据层只增不改**:验收结论行 zh 四档逐字保留并新增 en 四档(`✅ Pass / ⚠️ Conditional pass / ❌ Fail / 📝 Not applicable`;解析器同时兼收 `Not passed` 等价写法)、缺陷表新增 en 表头、triage 关键词新增英文项(中文项一字不动,实测 19 个中文样本档位 0 漂移)、L2 语料只增 6 条 en 样例。仓库 `docs/` 与代码注释**不做双语**(注释统一中文)。独立验收 46/46:11 工厂 + 2 模板 en 产出 **CJK 0 处**、zh 侧逐字不回归、语言链异常不冒泡
|
|
9
|
+
- **ADR-0009:不做插件级用户记忆层(否决记录)**(`docs/adr/0009-user-layer-memory.md`)——曾设计插件自建跨产品线用户层(`_user/{memory.md,index.json}` + 流水线启动时注入索引 + acceptance write-back),**经复核否决**。理由:① **场所错位**——用户偏好是多轮对话的产物,流水线是「一需求一链路」批处理,不存在该场所;② **输入不足**——流水线任一时刻只有当前产品线上下文,「跨产品可复用」的普适性只能靠猜;③ **替代路径已够且已实现**——跨产品用户约定写宿主原生的 `$DSH_HOME/AGENTS.md`(`dsh-agent-instructions` 已无条件注入,插件零代码),插件硬规矩直接进 prompt/模板(`TOKEN_HYGIENE` / `LOG-LAYOUT-SCOPED` / `DOC-BOUNDARY-POLICY` 等);④ **突破 ADR-0002 写域边界**。**零运行时改动**,仅留决策记录与再评估触发信号。同步 ADR 索引:README / README.en / CONTRIBUTING / AGENTS 四处(AGENTS 原为 `0001~0007`,漏了 0008,一并补齐)
|
|
10
|
+
- **工作区 key 迁移演练脚本(只读)**:`scripts/migrate-workspace-key-dryrun.mjs`——扫描 `$DSH_HOME/teamflow/<key>/`,从 `runs/*.json` 的 `workspacePath` 反推来源路径,用与 `store.ts` 同源的 `slugPath` 重算期望 key,产出「逐目录判定(OK/DRIFT/LEGACY/EMPTY/FALLBACK)+ 按路径分组的合并计划 + 同名文件内容冲突检测」。**不写任何数据**(`--out <file>` 只写报表)。用于给「`workspaceScopeOf` 的 UUID 分支不可达 → key 绑路径字符串」这个已知风险定价:本机实测 11 个目录 → 自洽 4、**漂移 0**、旧格式 1、空壳 6,故该风险尚未造成数据分裂,迁移优先级按风险而非损失排(详见 `docs/TODO.md`)
|
|
11
|
+
|
|
12
|
+
### 修复
|
|
13
|
+
- **缺陷卡点开看不出「缺陷是什么」**:QA 报告里写好的复现步骤/期望行为/实际行为/关联验收项四列此前**被整列丢弃**(解析只留编号/严重级/模块,建卡时四个字段硬编码空串,下发面也没有这几个字段)→ backlog 里点开一张缺陷卡,只看到「QA 缺陷:R3-1」+ 关联 run 的原始需求。现:解析新增富行(四列 + 原始表头映射),缺陷卡存全并幂等刷新、标题自解释(`R3-1 · 日志/注入面`)、下发面补齐字段,工作台两处详情抽屉都新增「缺陷详情」块;**并让 QA 打回修复时的缺陷清单也带上完整描述**(dev 直接看到复现/期望/实际)。附带:QA 表格单元格内的字面量 `|` 现在要求转义 `\|`(不转义会切开单元格、后续列错位)
|
|
14
|
+
- **英文界面下「人看得见的三处」仍是中文(首次英文 run 实测发现)**:① **阶段子代理的回复语言**此前无人约束(只约束了产物文件的语言)→ 文件是英文、工作台里「阶段性产物」却是中文(子代理跟着中文上下文回复);现由 `productCtx`(11 个阶段共用前缀)统一声明 `[Reply language]`,一处覆盖全部阶段。② **给模型的工具返回/会话注入**没点名回复语言 → 主会话模型仍用中文答复用户;现显式写入「用当前语言回复用户」。③ **团队名/描述**来自用户数据 `teams.json`(只有中文)→ 英文界面下拉里是中文;现支持可选 `nameEn`/`descriptionEn`(**不改写存量文件**,内置团队按 id 回落英文),并由宿主按当前语言本地化后下发。顺带:run 日志里的阶段名改走已有的 `phaseLabel`(原先直出 `teams.json` 的中文 label)
|
|
15
|
+
- **QA 缺陷解析误登记(一条流水线因此被误停线)**:旧 `parseDefects` 按**列位置**认缺陷(任一含 `|` 的行 + 第 2 格 ∈ P0-P3),于是 QA 报告里的「round-2 缺陷**复验对照**」表(第 3 格是结论「已关闭」)被登记成一个新的 P2 缺陷 → 每轮复验都重生一个阻断缺陷 → **第 3 轮必然超限停线并跳过产品验收**(自我实现的停线,与交付质量无关)。现改为**按表头认表**:只有表头显式声明严重级列(`严重级(P0/P1/P2/P3)` / `Severity (P0/P1/P2/P3)`)的表格才解析,列位置由表头决定,无严重级表头的表格整表跳过。回归门禁:L2 语料新增真实停线形态 + `test/verdict.test.js` 5 条断言(conformance 18/18 → 19/19)
|
|
16
|
+
- **未验收的 run 不再邀请合回 main**:完成汇报的合回指引旧条件只有「状态 completed 且无 error」——QA 超限时流程提前结束、验收被跳过,status 仍是 completed,汇报照样写「验收已通过,请询问用户是否合回」,会诱导用户在未验收时合回。现要求「已完成 + **无人工介入** + **验收阶段真的 done**」,并在需人工介入且验收未跑时显式提示「本轮未完成产品验收…不要据此合回 main」
|
|
17
|
+
- **en 文案残留的全角标点**:护栏中止摘要的连接符(`runner.ts`)改走词典(en 出半角冒号);en 验收档位行的全角 `/` 改半角 ` / `(zh 侧逐字不变);`store.ts` 运行日志**文件头**随 run 语言;`RETRY_SUFFIX` 补 `attempt N`(词典 `dev.taskRetry` 的实际产出,无 `taskKey` 的兜底路径上任务标题归一不再漏剥离)
|
|
18
|
+
- **收口提交静默失效 4 天:run 跑完却没有 commit(2026-09-11 → 09-15 全部如此)**:英文 lite run 验收时发现产物**全是 staged 但没有 commit**(`git log` 空、`.git` 无 reflog / 无 `COMMIT_EDITMSG`,而 12 个 blob 与索引的写入时间正是 run 收尾那一刻),而 journal 里 `commitDone`/`commitSkip`/`commitFail` **三条一条都没有**——故障完全不可见。根因:上一版「收口提交面」的两处写法互相拆台——`ensureLogGitignore()` 先把 `logs/teamflow/` 写进 `.gitignore`,紧随其后的 `tfAddArgs()` 又用**负 pathspec** `:(exclude)logs/teamflow` **点名**这个「显式点名且被忽略」的路径,git 直接报错**退出 1**(`The following paths are ignored by one of your .gitignore files`;索引其实已写好 → 现场就是「文件 staged 但没有 commit」);而 `add === null ? null : git commit(...)` 用 add 的结果**短路**了提交,`if (cm !== null) … else if (add !== null) …` 又让三条日志一条都不触发。`:(exclude)logs/teamflow/**`、`:(exclude,glob)`、`:(exclude,literal)`、`-c advice.addIgnoredFile=false` 四种变体实测同样 exit 1。**修复(①+③)**:① `tfAddArgs()` 收敛为 `git add -A -- .`(忽略交给刚写好的 `.gitignore`,它才是整树 add 的唯一依赖),并新增 `sanity.tfUnstageArgs()`(`git rm -r --cached --ignore-unmatch -- logs/teamflow`,只动索引不删文件)作为**索引兜底**紧随 add 执行——真摘出东西会记 `log.logsUnstaged` warn(那是 `.gitignore` 防线失效的信号);③ 提交不再被 add 结果短路:永远尝试提交,由提交结果分派 `commitDone`/`commitSkip`/`commitFail`(「无事可做」先用 `git status --porcelain` 空判定,`GIT_NOTHING_TO_COMMIT` 兜措辞),`gitCmd` 之外新增 **`gitRun`**(`{ok, out, error}`,失败原因进日志)——**失败可以处置,但不能不可见**。回归门禁:新增 **`test/commit-path.test.js`(真 git 集成)**——负 pathspec exit 1 的防回退锁、写规则→整树 add→索引兜底→commit 真跑通(断言提交树里没有 `logs/teamflow`)、兜底真摘出东西、失败分类;`test/gitignore.test.js` 与 smoke 断言同步改到新机制(smoke 新增「零回退」断点)。**部署后需重启 `dsh --profile web`**;此前失效期间产生的未提交 run(assetd 09-11、slugkit-en、durparse-en)需人工 `git add -A -- . && git commit`(插件不再回头补提交)
|
|
19
|
+
|
|
20
|
+
### 改进
|
|
21
|
+
- **QA 轮次收敛埋点(D 方案先测量再立法)**:52 个历史 run 的实测显示「真正需要第 3 轮修复」**从未发生**(打回 7/52、触达上限 1/52,且唯一那次是幻影),而「同一缺陷原样复现就早停」这条判据**按缺陷 id 判不出来**——QA 每轮重新编号(r9 三轮分别 `QA-*` / `R2-*` / `R3-*`)。所以不急着动状态机,先把数据攒起来:QA 循环每轮把阻断集合的**稳定身份**与增/减/停滞计数写进 `journal.qaRounds`(`{round, seq, blocking, p3, defects:[{id,sev,module,fp}], withCheck, withCriterion, qaCalls, fixCalls, gate, newFps, repeats, resolved, outcome}`,留最近 12 轮)。**身份优先级**:缺陷行自带的**检测命令**(B 方案起 QA 必填,机器写给机器看,最稳)> 模块+实际行为文本 > 缺陷 id(最不稳)。配套**只读读侧** `node scripts/qa-rounds-report.mjs`:逐 run 轮次表 + 聚合(收敛 vs 停滞次数、检测命令可用率 = B 落地率、门禁落地率 = A 落地率、单轮成本),让「要不要把 `QA_REWORK_LIMIT` 换成收敛判据」这个问题有数据可答。**埋点只记录、不改变任何行为**(纯函数 `util.defectFingerprint`/`compareDefectRounds`/`qaRoundEntry`,可单测)
|
|
22
|
+
- **QA 打回超限时不再「验收整段跳过」(E 方案:已知问题只读验收)**:旧行为是 QA 复验超限 → 跳过产品验收 → 人工只拿到一个 needs-human 旗标,**任务夹里连 `ACCEPTANCE.md` 都没有**(实锤 tf-mu2ioilr-95l4th:那份验收记录是维护者事后手写的)。现在改成:超限时仍以 **「已知问题」只读模式**跑一次验收,产出交付级视图(逐条 AC 核对表 + **未闭环阻断缺陷清单**,含各自的检测命令)。**硬约束(信息而非判定)**:结论一律**强制为需人工裁定**——prompt 明写"结论只能是 ⚠️/❌,且本 run 不会被提交或合回",host 侧照旧 `humanIntervention=true`、`mergeEligible` 保持 false(`accepted` 永不放行),验收失败也**不改变 run 结局**(只记 warn,保持 completed + needs-human)。汇报里新增 `report.knownIssuesNoMerge`:显式说「结论被强制为需人工裁定,不要据此合回 main」——否则 `acceptanceDone` 变真会让旧的「验收未跑、不要合回」警告消失(这正是这条改动最容易踩的坑)。定价依据(52 个真实 run):验收阶段 **p50 10 / p90 21 calls ≈ 一个 run 的 6%**,而「需人工介入且验收未跑」历史发生 1 次——便宜且不是假设。回归:L1 新增 `ACCEPTANCE-KNOWN-ISSUES`/`ACCEPTANCE-NORMAL-NO-KNOWN-ISSUES`(后者保证常规验收 prompt 零回归),smoke 新增 5 条;`log.accSkipped`(旧的「跳过验收」文案)随之删除
|
|
23
|
+
- **QA 打回闭环:治「修复不完整」而不是「少发现缺陷」(A/C/B 三件套)**:先纠正一个前提——维护者问「打回→修→打回→修 有没有解」,实测 r9 那次的停线**是幻影**(报告第 3 节的「round-2 缺陷复验对照」表被旧位置判定读成新 P2 缺陷;用修好后的解析器现场重放该真实报告 → **0 阻断**),真实轨迹是 **6 → 1 → 0 在收敛**,唯一那轮真实返工的病因是**修复不完整 / 扫描面不完整**(round-1 只改了看得见的实例,同类 4 处留在 `prompts/index.ts`)。故落地三件套:**A. 类别门禁**——`qaFixPrompt` 要求每个 P0–P2 修复落**永久可执行门禁**(verify 套件断言,或随检查一起提交的 grep/脚本断言:修复前失败、修复后通过)+ 证据块给 `gate:` 与 `class sweep:`(类别命中数 before→after);policy 级,缺失由新增的 `FIX_GATE_PATTERN` 记 warn 留痕(host 证明不了门禁真存在,不做硬失败,避免形式主义)。**B. 缺陷的「可执行定义」**——QA 缺陷表新增 `检测命令` + `通过判据` 两列(P0–P2 必填):`检测命令` 是**现在就能失败**的那条命令、`通过判据` 是修好后的期望输出;修复方据此验收、复验方据此回归、**误报用它当场证伪**(r9 的 R2-2a QA 误报在 round-3 就是靠一条命令自证的)。同步:富行解析新增两字段(`parseDefects` 瘦身投影形状不变、旧报告零回归)、缺陷卡持久化两列、`itemDetail` 下发、两处详情抽屉渲染;新增 L2 语料 `qa-report-check-columns.md`(conformance 19/19 → **20/20**)。**顺带修一个真 bug**:表格行原先无条件 `split('|')`——QA 按契约转义的 `\|` 照样被切开(R3-2 的「实际」串进「关联验收项」的实锤根因),而检测命令列几乎必然含 `|`;现改为**按未转义管道符切分并还原 `\|`**。**C. 复验复用**——复验轮经 `state.__runCtx.qaReverify` 显式声明(`QAREVERIFY`,不改 11 个工厂签名):**先原样重跑上一轮探针**(就在 `logs/teamflow/<runId>/scripts/`,正是日志收口决定归档留存的那一类)**再补上一轮没覆盖的面并说明漏在哪**,必须重跑缺陷行自带的检测命令、**不得重造已有基线**(r9 实测后一轮重做了一整份 HEAD 副本 = 50 文件/1 MB)。回归:L1 新增 `FIX-CLASS-GATE`/`QA-DEFECT-EXECUTABLE-DEFINITION`/`QA-REVERIFY-REUSE`/`QA-FIRST-PASS-NO-REVERIFY-NOISE` + `test/verdict.test.js` 新增 6 条断言(含转义管道符与错列门禁)。**未动流程语义**(轮次上限、QA 独立探针要求保持原样——质量第一约束,见 `docs/TODO.md`)
|
|
24
|
+
- **运行日志的根离开用户项目 + 只留有用的(`logs/teamflow` 不再长期躺在你的仓库里)**:此前命令日志直接落在项目内**没有任何清理逻辑**(实测 `products/tetris` 累计 1042 文件/17.3 MB、本插件仓 136 文件/3.0 MB),文件树遍历类工具(eslint/prettier/IDE 索引/agent 全局 grep/无 `.npmignore` 的 npm publish)都会看到它。为什么不干脆一步写进 `$DSH_HOME`:**子代理受 DSH 文件沙箱约束**——`workspace-write` 只允许写会话工作区 + 平台临时区,写 `$DSH_HOME` 直接 `FS_SANDBOX_DENIED`(实测:子代理写 `C:\Users\<u>\.dsh\...` 三步全拒,同构命令写工作区内 exit 0;`$env:TEMP` 又是**每会话**子目录、不可依赖),而 host 进程不受该约束。故改为**两段式**:子代理在工作区暂存(`logs/teamflow/<runId>/`)→ **run 终态由 host 过滤归档到 `$DSH_HOME/teamflow/<workspace>/logs/<runId>/` 并删除项目内副本**(host 自身事件日志 `run.log` 直接落归档位)。**归档只留有用的**:维护者一句「logs 里的文件基本都是没用的吧」促使实测——一次真实 run 130 文件/3.03 MB 里 **93% 是可重跑的命令输出或 git 里一模一样的源码快照**(41% `regression-*.log`+`*.out`、35% `probe/head/**` 快照、17% prompt JSON dump),唯一不可重跑且真被用过的 7% 就是检查脚本。因此归档面收敛为**白名单**:code 扩展名(`.mjs/.cjs/.js/.sh/.ps1/.py/.md`)+ `captures.json` 保留,命令输出(`*.log`/`*.out`/`*.txt`)与快照**一律丢弃**(命令输出在运行期仍有价值——把几百行输出挡在上下文之外;但**不是审计资产**,durable claim 是回复里的 `[Verification evidence]` 块)。配套:① **自愈清扫**——run 起跑按同一白名单处理上次崩溃/被 kill 残留的暂存目录与历史散落的 `<runId>.log`/笔记(`<runId>.log` 直接丢弃:内容与 journal 同源);② **保留 K 次**——每个工作区只留最近 `LOG_ARCHIVE_KEEP=20` 次 run,按 mtime 淘汰;③ 正在运行的 run(暂存目录与归档)一律跳过;④ 归档失败只 warn,暂存留待下次自愈,**run 收尾绝不被日志管理打断**。prompt 侧新增 `[Log lifecycle · policy]`(三处 `[Log discipline]` + `TOKEN_HYGIENE` + 资源表 + AGENTS/memory 模板同源),明确「项目内只是暂存、只留脚本与笔记、dump 不留存、不得提交/自行清理/当项目产物」。收口提交面的两道防线(pathspec 排除 + `.gitignore` 幂等补写)保留,覆盖「run 进行中用户自己提交」的窗口。**存量已按新白名单就地瘦身**:本插件仓归档 136 文件/3.03 MB → **43 文件/278 KB**(丢弃 93 个可重跑输出/快照,2.7 MB)。
|
|
25
|
+
- **生成量纪律:不再制造输出 dump(改由宿主截尾 + spill 承担)**:维护者追问「**为啥会产生这么多文件?是我们流水线带来的,还是 DSH 本身也会有?**」——实测两边都有,但性质不同:**DSH 原生**会把过大的工具结果截成 tail 并把全文 **spill 到会话临时区**(`dsh-spill-*`/`dsh-subprocess-*`,不进你的仓库,`dsh-spill-local` 有启动 TTL 清扫;本机 temp 里 149 个 `dsh-*` 目录共 8.4 MB,主要是 Node 编译缓存);**我们的流水线额外要求**每个执行体把命令输出与临时脚本**落到项目内**。真正制造数量的是**执行体数量**:r9 一次 full run 起了 **10 个子代理**(PRD 1 + 技术 1 + 开发 5 = T1–T5 三个并发 + 两轮 QA 打回修复 + QA 首轮 + 两轮复验;**718 次调用 / 59 分钟,其中 61% 花在打回闭环**),每个都按旧 prompt 把整套件输出 dump 成 `regression-*.log`(一次 443 KB、同一套件重复两遍)与 23 个 per-command `.out`。故**删掉旧约定、改为不落盘**:`TOKEN_HYGIENE` 新增 `[No dump manufacturing]`(**禁止**把命令/套件输出重定向进文件;长输出由宿主截尾并把全文 spill 到你被报告的路径,需要细节时读那里),`logs/teamflow/<runId>/` 只放**要留存**的三类——一次性检查脚本 `scripts/`、不可重跑的命令载荷 `captures.json`、结论 `.md`;并要求**同一用途不得新增编号变体**(`-run2`/`dbg-repro2`/`dbg-scan3` 一律就地覆盖)、**改动前基线只物化一次**(`probe/head/` 共享,实测一次 run 因后一阶段重做而留下两整份 50 文件/1 MB)。少掉的正是「41% 的 `.out` + `regression-*.log`(1.2 MB)」与「35% 的源码快照」这两类。回归:L1 契约改写为 `LOG-NO-DUMP-MANUFACTURE`/`LOG-KEEP-ONLY-DURABLE`/`LOG-DISCIPLINE-NO-REDIRECT`(含**防回退**断点:旧写法 `APPENDED on re-run`、`regression-dev.log` 等出现即失败);执行体数量的收敛留 `docs/TODO.md`(需人决策,先定判据)。回归:新增 `test/runlogs.test.js`(60 断言:路径契约/白名单矩阵/过滤归档/合并语义/自愈清扫/活跃 run 豁免/K 次淘汰/永不抛)+ `test/journal.test.js` 与 smoke 断言改到新落点 + L1 契约 `LOG-LIFECYCLE-ARCHIVED`/`LOG-LIFECYCLE-FILTERED`
|
|
26
|
+
- **客户端界面中英双语(P1:客户端展示层,走宿主 locale 服务)**:工作台文案跟随宿主语言(设置 → 通用 → 语言)**实时切换、无需重启**,机制全部复用宿主能力——`ctx.locale.register(NS, {zh,en})` 注册词典 + `ctx.locale.bind(NS)` 取翻译函数 + slot 注册项声明 `locale: NS`(宿主切语言时重渲染每个 outlet;`sidebar.panellist` / `conversation.view` 的名称用 thunk `() => t(...)`,宿主读时求值)。落地:新增 `client/locales.ts`(247 条 key,zh/en 逐条同形)+ `scripts/i18n-client-codemod.mjs`(一次性改写脚本,186 处字面量 → `t('key')`,保留映射留痕);`client/shared.tsx` 词表**函数化**(`runStatusText`/`kindTitle`/`roleChip`/`stText`,删掉切语言后会变陈旧的模块级常量表)+ `localeTag()` 取代硬编码 `toLocaleTimeString('zh-CN')`;`apply()` 把翻译函数注入纯函数层(词表/格式化/折叠件拿不到组件 prop,只能走模块注入)。**门禁**:smoke 新增「词典 zh/en key 集合逐条一致(en 是兜底语言,漏 key 会让用户看到 raw key)+ 客户端除 console 诊断与存量 phaseKeyOf 映射外零中文字面量 + 5 处 slot 声明 locale + 名称 thunk」。**范围边界(刻意未做)**:host 生成的完成汇报/工具返回/流水线日志、以及流水线产物文档(PRD/QA-REPORT/ACCEPTANCE…)仍是中文——产物语言与「验收结论」字面量是 host 解析契约(`util.parseAcceptanceVerdict` + 冻结语料只增不改),属 P3,见 `docs/TODO.md`
|
|
27
|
+
|
|
28
|
+
### 已知待办
|
|
29
|
+
- 沿用 [0.1.8] 的待办项,并新增本轮产物,见 `docs/TODO.md`
|
|
30
|
+
|
|
31
|
+
## [0.1.8] - 2026-09-12
|
|
6
32
|
|
|
7
33
|
### 新增
|
|
8
34
|
- **全局团队工作台(`sidebar.panellist` + `main`)**:工作台从「某个会话里的一个 tab」升级为应用级主面板——左侧边栏多一个图标(inline SVG,跟随选中态),点开中央主区即整块换成 TeamFlow:左栏是**产品线**列表(`$DSH_HOME/teamflow/<key>` 扫描,含 run 计数/活跃数/最近需求与验收结论/磁盘路径),右栏是该产品线的 **run 列表 + backlog 分组**(需求/任务/缺陷,含按角色 token)。**不依附会话**:面板在 root scope(无 `useSession`/`useProjection`),所以数据面新增按**产品线 key** 寻址的 remote 方法(`products` / `productView` / `productRunDetail` / `productStageDetail` / `productItemDetail`),与会话内工作台同源装配(同一批 journal 与 state.json,非新数据模型)
|
package/README.en.md
CHANGED
|
@@ -47,8 +47,9 @@ requirement → PRD (based on existing patterns / product memory, archived to pr
|
|
|
47
47
|
- **Resume from checkpoint**: every stage checkpoint persists to `$DSH_HOME/teamflow/runs/<runId>.json` (LangGraph checkpointer semantics); after a process crash / restart it is auto-marked `interrupted`, and `teamflow_resume` / the panel's "↻ resume from checkpoint" continues from the first unfinished stage (skipping completed stages, reusing full stage outputs).
|
|
48
48
|
- **Backlog persistence (workspace-isolated since v0.1.0)** under `$DSH_HOME/teamflow/<workspace>/backlog/` as `requirements.json` / `tasks.json` / `bugs.json`, surviving restarts; backlog is isolated per "workspace (project)" — one workspace is one product line, and different workspaces each see their own Team Workspace.
|
|
49
49
|
- **Single-task model **: one requirement = one rotating task card (no longer split by role); the task card records `devAssign` / `qaAssign` / acceptor, with state rotation: todo → developing → to-test → testing → to-accept → accepted | bounced | needs-human; the delivered frontend page also shows each role's **real token usage** spent on that task.
|
|
50
|
-
- **Artifact consolidation **: pipeline docs (PRD / design / architecture / tech spec / QA / memory / history) all consolidate into `docs/teamflow/`, command run logs into `logs/teamflow/<runId
|
|
51
|
-
- **
|
|
50
|
+
- **Artifact consolidation **: pipeline docs (PRD / design / architecture / tech spec / QA / memory / history) all consolidate into `docs/teamflow/`, command run logs are staged into `logs/teamflow/<runId>/` while the run is live, so the host `docs/<role>/` and project root are no longer polluted by TeamFlow.
|
|
51
|
+
- **The log root lives in `$DSH_HOME`, not in your project (v0.1.9)**: sub-agents are confined by the DSH file sandbox (`workspace-write` can only write the session workspace), so they stage inside the project first; **as soon as the run ends the host archives what is worth keeping to `$DSH_HOME/teamflow/<workspace>/logs/<runId>/` and deletes the in-project copy** (the host's own event log `run.log` is written straight to the archive). **No output dumps are manufactured**: sub-agents are told *not* to redirect command/suite output into files — long output is already truncated to its tail by the host, which spills the full text to a temp path it reports (native DSH behaviour). What survives is therefore only your **checkers** (`scripts/`), **non-derivable payloads** (`captures.json`) and conclusion notes (`.md`); everything else (`*.log`/`*.out`/`*.txt`, source snapshots) is **dropped at archive time**. Measured on a real run, 93% of the bytes were rerunnable output or an exact copy of something already in git. A crashed/killed run leaves no residue (the next run in the same workspace applies the same rule — self-healing), and **each workspace keeps only the latest 20 runs**.
|
|
52
|
+
- **Delivery surface vs. noise**: only **code + the `docs/teamflow/` task folder** go into the closing commit (one commit per run); `logs/teamflow/` is the plugin's own run log (including sub-agent scratch verification scripts) and is **not a deliverable** — before committing, the host appends that rule to the workspace `.gitignore` (idempotent, visible in the same commit) and, right after the whole-tree `git add`, **unstages the directory again** (`git rm -r --cached --ignore-unmatch` — index only, your files stay put), so **your project needs no pre-configured .gitignore** (these two guards cover the window where you commit yourself while a run is live). If a repo already committed that noise, run `git rm -r --cached logs/teamflow` there to untrack it (local files are kept).
|
|
52
53
|
- **State machine + event log**: requirement (initiated → in-progress → to-accept → accepted), task (todo → developing → to-test → testing → to-accept → done | bounced | needs-human), defect (to-claim → in-progress → fixed-to-verify → closed).
|
|
53
54
|
- **Bounce-back threshold**: 2 consecutive Agent failures in a single stage auto-retry; still failing → `needs-human`, requiring human intervention.
|
|
54
55
|
- **Concurrency pool**: dev tasks run in parallel by `maxConcurrency` (default 3, max 8).
|
|
@@ -63,6 +64,8 @@ requirement → PRD (based on existing patterns / product memory, archived to pr
|
|
|
63
64
|
- Human-intervention center (needs-human items aggregated + one-click terminal state)
|
|
64
65
|
- History run switching + product switching
|
|
65
66
|
|
|
67
|
+
- **Bilingual UI — Chinese / English (v0.1.9, P1 client surface)**: the workbench follows the host language (Settings → General → Language) and **switches live, no restart** — it rides the host `ctx.locale` service (the plugin registers dictionaries and declares `locale` on its slot entries, so every outlet re-renders on a switch) rather than a bespoke i18n layer. Status/phase/role/token-metering vocabularies and time formatting all go through one lookup table; all 247 keys are paired zh↔en, guarded by `test/smoke.js` (the two key sets must match, and no Chinese copy may remain in the client outside `console` diagnostics). **Scope boundary**: the **client display layer only**. Host-generated completion reports, tool results, pipeline logs and artifact documents (PRD/QA-REPORT/ACCEPTANCE…) remain Chinese — artifact language and the acceptance-verdict line are a host parsing contract, tracked as P3 (see `docs/TODO.md`).
|
|
68
|
+
|
|
66
69
|
## AGENTS.md minimal-invasion principle (important)
|
|
67
70
|
|
|
68
71
|
AGENTS.md is unconditionally injected into every session by the harness; it is **team assets**. TeamFlow follows separation of concerns:
|
|
@@ -114,6 +117,14 @@ dsh-plugin-teamflow/
|
|
|
114
117
|
- Node.js ≥ 22.18;
|
|
115
118
|
- Relies on host-provided `@deepseek-ai/dsh-*` and `react` (peerDependencies, injected by the host — no separate install needed).
|
|
116
119
|
|
|
120
|
+
### Version anchor (dsh host compatibility)
|
|
121
|
+
|
|
122
|
+
This plugin is developed and verified against **dsh v0.1.5-rc.2 (2026-09-10, tag `dsh-v0.1.5-rc.2`)**; on npm the `@deepseek-ai/dsh` package has `next`=0.1.5-rc.2 and `latest`=0.1.5-rc.1 (`latest` lags behind `next` — do not use `latest` to judge the release line). `peerDependencies` stay at `*` (host-injected, deliberately loose), and `package.json` declares the compatibility window **`engines.dsh: ">=0.1.5-rc.2 <0.2.0"`** plus **`dsh.manifestVersion: 1`** — dsh does not read or validate either field today (they exist as types only), so they are declarative author metadata.
|
|
123
|
+
|
|
124
|
+
Compatibility check of 2026-09-10 (dsh 0.1.5-rc.2): plugin panel slots (the old `conversation` root slot → the `conversation` key under `main`), session format V3 + Session lifecycle (`SessionHandle`, async `agentLoop.create()`, session locks), removal of `ctx.agent` and typed Inbox, adjusted default tools for SDK/Headless/ACP, subprocess handles without pid — **the plugin is compatible with all of them** (it uses none of the changed interfaces; the `conversation.view` / `conversation.input.right` declarations are unchanged and no slot was removed). One follow-up item:
|
|
125
|
+
|
|
126
|
+
- **The synchronous session event readers are deprecated** (`session.eventAt()` / `snapshotEvents()` / `ownEvents()`; since 2026-09-09 the host allows existing calls but forbids new ones, aiming to stop keeping the full event sequence resident in memory): **token metering now prefers the official Session projection** (`ctx.sessionProjections.stateOf(session,'tokenUsage')` for the four buckets + `'sessionStats'.steps` for the call count), with event scanning degraded to a fallback for hosts without projections; **the guard reminder channel moved to the official `Agent.inject()` and the stall check to the official `subagentTiming` projection's `active.through`** (long silent tools are still exempted by the agent-activity guard). Only **repeat detection** still reads events (it needs streaming text; the official replacement — subscribing to `'session/event'` post-commit delivery — requires an equivalent predicate first, see `docs/TODO.md`).
|
|
127
|
+
|
|
117
128
|
## Install (for users)
|
|
118
129
|
|
|
119
130
|
```bash
|
|
@@ -161,7 +172,7 @@ node --check lib/host.mjs lib/client.js lib/store.mjs lib/descriptors.mjs
|
|
|
161
172
|
npm run bundle # build client (tsdown → lib/client.js, __ModuleLoader__.load registers)
|
|
162
173
|
```
|
|
163
174
|
|
|
164
|
-
**For plugin developers** (the local dev loop of THIS plugin): see [`AGENTS.md`](./AGENTS.md) and [`docs/adr/`](./docs/adr) in the repo — deployment sync (`node deploy.mjs` → restart `dsh --profile web`), the "running web loads the host from the profile deployment copy, building source alone does not take effect" caveat, design decision records (ADR-0001~
|
|
175
|
+
**For plugin developers** (the local dev loop of THIS plugin): see [`AGENTS.md`](./AGENTS.md) and [`docs/adr/`](./docs/adr) in the repo — deployment sync (`node deploy.mjs` → restart `dsh --profile web`), the "running web loads the host from the profile deployment copy, building source alone does not take effect" caveat, design decision records (ADR-0001~0009) and benchmarks (`docs/benchmarks/`). All repo source is TS/TSX and must be built first (`pnpm bundle`) to run (`strip-types` does not apply under `node_modules`).
|
|
165
176
|
|
|
166
177
|
Note: `lib/` is excluded by `.gitignore` but must ship with the package (`files` whitelist includes `lib/`; `exports["./client"]` points to `./lib/client.js`).
|
|
167
178
|
|
package/README.md
CHANGED
|
@@ -48,8 +48,9 @@ TeamFlow 团队研发流水线 —— DeepSeek Harness 可分发插件(`dsh pl
|
|
|
48
48
|
- **backlog 持久化(v0.1.0 起按工作区隔离)到 `$DSH_HOME/teamflow/<workspace>/backlog/`**
|
|
49
49
|
`requirements.json` / `tasks.json` / `bugs.json`,跨重启不丢;backlog 按「工作区(项目)」隔离——一个工作区就是一条项目线,不同工作区各看各的团队工作台。
|
|
50
50
|
- **单任务模型**:一个需求 = 一张轮转任务卡(不再按角色拆任务),任务卡记录 `devAssign` / `qaAssign` / 验收人,状态轮转:待办→开发中→待测试→测试中→待验收→已验收|打回|需人工;交付前端页面同时展示每个角色花在该任务上的**真实 token usage**。
|
|
51
|
-
- **产物收口**:流水线文档(PRD/设计/架构/技术方案/QA/记忆/历史)全部收口到 `docs/teamflow
|
|
52
|
-
-
|
|
51
|
+
- **产物收口**:流水线文档(PRD/设计/架构/技术方案/QA/记忆/历史)全部收口到 `docs/teamflow/`,命令运行日志在 run 期间暂存到 `logs/teamflow/<runId>/`,宿主 `docs/<职责>/` 与项目根不再被 TeamFlow 污染。
|
|
52
|
+
- **日志根在 `$DSH_HOME`,不在你的项目里(v0.1.9)**:子代理受 DSH 文件沙箱约束(`workspace-write` 只能写会话工作区),所以只能先在项目内暂存;**run 一结束 host 就把其中值得留的东西归档到 `$DSH_HOME/teamflow/<workspace>/logs/<runId>/` 并删掉项目内副本**(host 自身的事件日志 `run.log` 直接落归档位)。**不制造输出 dump**:子代理被要求**不要**把命令/套件输出重定向进文件——长输出本来就由宿主截成 tail、全文 spill 到它报告的临时路径(这是 DSH 原生能力),所以要留存的只有**检查脚本**(`scripts/`)、**不可重跑的命令载荷**(`captures.json`)与结论笔记(`.md`),其余(`*.log`/`*.out`/`*.txt`/源码快照)**归档时一律丢弃**。实测一次真实 run 里 93% 是可重跑输出或 git 里已有的副本。崩溃/被 kill 的 run 不留残渣:下次同工作区起跑按同一标准处理残留(自愈),**每个工作区只保留最近 20 次 run**。
|
|
53
|
+
- **交付面与噪音隔离**:只有**代码 + `docs/teamflow/` 任务夹**进收口提交(一个 run 一个 commit);`logs/teamflow/` 是插件自己的运行日志(含子代理的临时验证脚本),**不属于交付物**——host 提交前先把这条规则**幂等写进工作区 `.gitignore`**(随本次提交可见),整树 `git add` 之后再**把该目录从索引里摘掉**(`git rm -r --cached --ignore-unmatch`,只动索引、不删你的文件),因此**目标项目不需要预先配置 .gitignore**(这两道防线覆盖的是「run 进行中你自己提交」的窗口)。若你的仓库已经提交过这批日志,可在目标仓库执行 `git rm -r --cached logs/teamflow` 移出(本地文件保留)。
|
|
53
54
|
- **状态机 + 事件日志**:需求(立项→进行中→待验收→已验收)、任务(待办→开发中→待测试→测试中→待验收→完成|打回|需人工)、缺陷(待认领→处理中→已修复待验→已关闭)。
|
|
54
55
|
- **打回阈值**:单阶段连续 2 次 Agent 失败自动重试,仍失败 → `needs-human`,需人工介入。
|
|
55
56
|
- **并发池**:开发任务按 `maxConcurrency`(默认 3,最大 8)并行执行。
|
|
@@ -66,6 +67,8 @@ TeamFlow 团队研发流水线 —— DeepSeek Harness 可分发插件(`dsh pl
|
|
|
66
67
|
- 历史 run 切换 + 产品切换 + 「⇥ 右栏打开 run 详情」
|
|
67
68
|
- **全局面板**(v0.1.8):侧边栏图标 → 中央主区整块切换为**产品线视角**——左栏产品线列表(`$DSH_HOME/teamflow/<key>`,含 run 计数/活跃数/最近需求与结论),右栏该产品线的 run 列表 + backlog 分组(不依附会话,跨会话可用)。点 run 在**面板内联**看详情(阶段/尝试/验证证据/产出/日志);要并排看产物就点 run 行的「对话右栏」= 切回对话并在右侧栏打开(**右侧栏的会话内容宿主只在对话视图渲染**,这是宿主设计,不是面板缺陷;任何一步不可用都会降级为面板内联并给出可见提示)
|
|
68
69
|
|
|
70
|
+
- **界面中英双语(v0.1.9,P1 客户端面)**:工作台文案跟随宿主语言(设置 → 通用 → 语言)**实时切换、无需重启**——走宿主 `ctx.locale` 服务(插件注册词典 + slot 注册项声明 `locale`,宿主切语言时重渲染每个 outlet),不自建 i18n;状态/阶段/角色/token 口径/时间格式等词表统一查表,247 条 key 中英逐条对齐(`test/smoke.js` 断言守门:两侧 key 集合必须一致,且客户端除 console 诊断外不得残留中文字面量)。**范围边界**:仅**客户端展示层**;host 生成的完成汇报/工具返回/流水线日志与产物文档(PRD/QA-REPORT/ACCEPTANCE…)仍是中文——产物语言与「验收结论」是 host 解析契约,属 P3(见 `docs/TODO.md`)。
|
|
71
|
+
|
|
69
72
|
## AGENTS.md 最小侵入原则(重要)
|
|
70
73
|
|
|
71
74
|
AGENTS.md 会被 harness 无条件注入每个会话,是**团队资产**。TeamFlow 遵循职责分离:
|
|
@@ -190,7 +193,7 @@ node --check lib/host.mjs lib/client.js lib/store.mjs lib/descriptors.mjs
|
|
|
190
193
|
npm run bundle # 构建 client(tsdown → lib/client.js,__ModuleLoader__.load 注册)
|
|
191
194
|
```
|
|
192
195
|
|
|
193
|
-
**插件开发者**(本插件的本地开发链路)见仓库内 [`AGENTS.md`](./AGENTS.md) 与 [`docs/adr/`](./docs/adr)——含部署同步(`node deploy.mjs` → 重启 `dsh --profile web`)、生效前提(运行中 web 从 profile 部署副本加载 host,只构建源码不生效)、设计决策记录(ADR-0001~
|
|
196
|
+
**插件开发者**(本插件的本地开发链路)见仓库内 [`AGENTS.md`](./AGENTS.md) 与 [`docs/adr/`](./docs/adr)——含部署同步(`node deploy.mjs` → 重启 `dsh --profile web`)、生效前提(运行中 web 从 profile 部署副本加载 host,只构建源码不生效)、设计决策记录(ADR-0001~0009)与基准对比(`docs/benchmarks/`)。本仓库其余源码均为 TS/TSX,需先 `pnpm bundle` 构建后再运行(`node_modules` 下 strip-types 不生效)。
|
|
194
197
|
|
|
195
198
|
注意:`lib/` 被 `.gitignore` 排除,但发布必须带上构建产物(`files` 白名单已含 `lib/`;`exports["./client"]` 指向 `./lib/client.js`)。
|
|
196
199
|
|