Repository navigation
v0.2.6
TeamFlow v0.2.6
Release — 「枚举不再被截断 + 大文档不再被裸 clip + 宿主升到 0.2.0」版本(23 笔新提交 / 47 个文件 / +3450 −139 行,v0.2.5..HEAD 全量对比)。无破坏性:宿主窗口由 >=0.1.7-alpha.1 <0.2.0 放宽为并集区间(含 0.2.0 预览版);journal / 任务夹契约 / teamflow_* 工具参数全部向后兼容。
中文
⬆️ 升级要点
- 🐛 安装阻塞修复(发版前最后一步拦下的):
postinstall: lefthook install→prepare。postinstall在消费者从 registry 安装时也会跑,而lefthook是 devDependency(不在 tarball 里)⇒ 安装直接失败。- 反证(同一 tarball,只改这一个字段):
版本 npm install <tarball>结果postinstall(v0.2.5 形态)❌ npm error command … lefthook install/'lefthook' 不是内部或外部命令prepare(本版)✅ added 1 package in 9s,lib/齐全 prepare只在本地 install / pack / publish 时跑 ⇒ git hook 仍自动装,发布不再炸。- 门禁:
test/smoke.js断言preinstall/install/postinstall必须为空、prepare必须是lefthook install。
- 反证(同一 tarball,只改这一个字段):
- 宿主窗口放宽到 dsh 0.2.0-rc.2(预览版)。区间是并集
">=0.1.7-alpha.1 <0.3.0 || >=0.2.0-rc.1 <0.3.0"——⚠ 上界不能简单放宽:semver 的「预发布只匹配同 tuple 区间」规则下,把<0.2.0直接改成<0.3.0,0.2.0-rc.1/0.2.0-rc.2仍判 fail(semver 7.7.4 实测)。 - 桌面版(dsh 0.2.0 起)需要单独安装一次:它用独立的
desktopprofile(~/.dsh/profiles/desktop),与web各自一份 node_modules。只装在 web 上,桌面版里看不到本插件(不是插件坏了,是那份 profile 里没装)。且 CLI 明确拒绝--profile desktop(error: profile "desktop" is managed exclusively by the Electron application)⇒ 桌面版请用应用内的插件管理界面安装。 - 升完重启
dsh --profile web(桌面版重启桌面应用)生效。 - ⚠ prompt 变长了:
host/prompts/index.ts净增 76 行(craft 五条款 + 四处磁盘路径指引)。本仓的instruction-budget门禁只管 AGENTS.md、不管 prompt,所以这部分未量化(增量以百字符计,单次调用多几十到几百 tok)。 - 新增日志键
log.hostScanTruncated。
① 交付枚举不再被上限截断(本版头条)
取证:tf-mupnk8h0-1otbl2(工作区 E:\Code\Probe\tf-stpanel-r1)——工作区里有 pnpm 的 .pnpm-store/,里面是几千个无扩展名 blob,而旧的跳过名单漏了 .pnpm-store,且它在 readdir 顺序里排在 AGENTS.md 之前 ⇒ 瞬间吃满 400 上限 ⇒ 返回的 400 条里源文件 0 个、HTML 0 个 ⇒ 四项检查同时静默跳过:
host 侧加载检查:本次未执行(no-html;根=E:\Code\Probe\tf-stpanel-r1)
host 侧接口核对:本次未执行(skip;源文件 0 个)
host 侧冒烟:本次未执行(no-html)
QA 验证证据观察:交付未见可执行入口(扫到 400 个交付文件),本项跳过
而交付其实完好:28 个交付文件 / 13 个源文件 / 1 个 index.html。机制复现:同目录形状 + 1000 个 store blob ⇒ 不跳点目录时「400 条 / 源文件 0 / HTML 0」;跳过点目录后恢复「23 条 / 源文件 11 / HTML 1」。用户是在浏览器里点不动才把它暴露出来的。
改动:scanDeliverableFiles(root, limit) 返回 { files, truncated, limit },点目录一律不遍历(它们从不是交付物,又最易吃满配额);listDeliverableFiles 退为薄包装(签名与旧行为不变)。三项检查任一 truncated ⇒ 追加一条 log.hostScanTruncated 撤回提示。
⚠ 措辞要说准:那三条「未执行 / 源文件 0 个 / no-html」的原文保留(检查确实没执行),撤回靠的是后一条 warn 点名它们不是事实 ⇒ 顺序也是契约(编排测试第 ⑨ 组钉住,实测 neg@13 / warn@16)。
门禁两层:test/smoke-check.test.js ②b 段(扫描器层)、test/orchestration.test.js 第 ⑨ 组(接线层,430 个无扩展名文件顶满 400)。变异实测:短路 if (scanTruncated) ⇒ 4 条立刻红。
② 大文档注入:裸 clip → 「小 teaser + 磁盘完整路径」
按 256 份真实任务夹文档实测:TECHNICAL.md 中位 19075 / 最大 35547;DESIGN.md 中位 9338;PRD 中位 6334;QA-REPORT 中位 4430。
| 文档 | 原阈值 | 会截断 | 处置 |
|---|---|---|---|
| TECHNICAL.md(dev / qaFix) | 12000 | 47/50(94%) | 4000 + 磁盘路径 |
| DESIGN.md(scaffold / tech) | 10000 | 11/31(35%) | 4000 + 磁盘路径 |
| PRD.md(design / tech / architect) | 15000 / 12000 | 3 |
阈值不动,只补路径 |
| QA-REPORT.md(qaFix) | 12000 | 2/51(4%) | 阈值不动,只补路径 |
⚠ 一个反直觉结论:TECHNICAL 中位 19075 ⇒ 连 4000 的 teaser 也截 94% ⇒ 磁盘路径才是修复主体,teaser 价值有限——缺了它,模型根本不知道后面还有内容。
明确不动的两处:clip(scaffold, 10000) 与 clip(devSummary, 8000)——它们不是磁盘文件,无路径可指,加提示就是空话。
门禁:clip 纪律源码锁 6 道(tech / design 各一条「只用 4000」+ 四条「路径指引覆盖 N 处」:TECHNICAL 2 处、DESIGN 3 处、PRD 3 处、QA 1 处)。
③ craft 引导通道(design → dev 接通)
来源是「流水线 vs 裸跑」对照的机制归因:designPrompt 写出的 DESIGN.md 到不了 dev 手里(devPrompt 签名没有 design 参数)⇒ 流水线在「做好看」这件事上结构性输给单 agent。
devPrompt(task, tech, prd, design, …)新增 design 入参,注入视觉规格 + 磁盘路径,明写「视觉规格写在 DESIGN.md 开头,先读它再动手做任何可见的东西」。- 开关
TEAMFLOW_CRAFT:未设置 / 空串 = 开,只有0/false/off/no才关;经util.envFlagOn→options.craft→state.__runCtx.craft。不做工具参数(工具 description 每次都进主会话上下文),resume 读 journal 快照不读环境变量。 - 定位收窄为交互反馈下限 + 状态可见性,不做审美裁决;QA 只记 P3 observation、绝不阻断(弱/本地模型产不出 craft,硬门禁会让插件对它们不可用)。
- ⚠ 净收益至今无定论:三组样本方向互不相同,全被 QA 返工轮 / dev 任务拆分数 / host 检查静默跳过盖住。详见
docs/benchmarks/craft-ab-pomodoro.md。
④ 新增脚本
scripts/artifact-selfcheck.mjs—— 产物自洽探针(静态、零浏览器依赖):[geo]几何自洽 /[bind]未绑定按钮与歧义选择器 /[craft]反馈态计数 /[state]死快照 /[persist]持久化缺口。[state]来自一次真实误判:某产物「滑块点不动」,而此前所有静态指标(反馈态规则数 10 vs 9、AC 数、bind/geo)全绿——真问题(入口把 value 写死成常量)没有任何门禁看得见。scripts/hi-report.mjs—— 人工介入归因巡检(只读)。动机是本仓曾长期按「humanIntervention 8/23 = 35%」排优先级,而那是早于 09-17 的样本。分层实测 91 个 run:09-17 之前 58 个(20.7%、failed 12);09-17 之后 33 个(9.1%、failed 0),且剩下 3 次全部是knownIssuesAcceptance(QA 复验超限 → 产品决策刻意交给人,不是缺陷)。
⇒ 没有可复跑的度量,旧数字就会一直驱动错误的优先级——本脚本就是那个度量。
⑤ 护栏 / 编排 / 客户端(本轮前段)
- 澄清闸门埋点(ADR-0010 第 1 步)。
- env-unavailable 不再误杀「文件级可自愈冲突」,并加进展豁免(用成功调用判定,不用
lastMutationAt——后者在 tool/call 就更新,反复失败的写会让检测永不触发)。 - 「工具在这一层不适用」不再判死(子代理无 Agent Team 身份 / 无委派深度时调用必失败,但那不代表工作区全废)+ 禁调协作工具 + dev 端到端证据。
- 可续跑终态不归档暂存日志——resume 要靠上一轮的 checker 当回归契约。
- 消除「验证脚本会随 run 丢弃」的误导定性,禁止拆 checker 重建任务。
- 客户端窄屏:画布支持触摸、缩放下限不再写死、窄容器默认列表(issue #10);⚠ 缩放下限保留 0.5(0.12 时卡片只有 37×7px,糊成一团;上一版把「能看全」当目标是错的,已 revert);详情浮层修窄屏左侧溢出;画布提示改设备中性。移动端不在支持范围(宿主 dsh 自身未做)——记进
docs/TODO.md⛔ 已否决清单,不写 README。
⑥ 语料 / 测试
corpus/qa-defect-rich-columns.md:补「富列 + 列序由表头决定(严重级刻意放最后一列)+ 转义|还原」。此前 5 份缺陷语料全走parseDefects投影 ⇒reproduce/expected/actual/ac/check/criterion与整张columns从未被断言。变异实测:不认转义时只有新语料变红——那份 note 自称「R3-2 转义回归门禁」的旧语料照旧全绿 ⇒ 一条语料断言了什么只能由变异测试回答,不能由它的 note 回答。corpus/tech-blueprint-valid.md/tech-blueprint-unrepairable.md:补extractBlueprint的正常路径与「不可抢救 ⇒ null」,连同既有那条构成合法 / 可抢救 / 不可抢救三态(conformance 24 → 26)。test/locale.test.js新增占位符覆盖门禁(224 处带参调用)。起因是桌面版首跑 journal 里出现字面量host 侧冒烟:{entry} 真浏览器加载后…——模板有{entry}而调用只传了{draw, raf, mut, ms}。同型漏传全仓 2 处(另一处guard.envProgress缺label)。⚠ 参数表必须括号配平地取:实调用常嵌t(..., { n }),用[^}]*会把「已传」误判成「漏传」。
⑦ 宿主兼容核对(dsh 0.2.0-rc.2)
逐项核对:未发现破坏,七条证据(完整版见 CHANGELOG.md 对应节):
tsc --noEmit直接对着 profile 里已装的 0.2.0-rc.2 编译(tsconfig.json的 paths 指向~/.dsh/profiles/node_modules/@deepseek-ai/*)且 0 错;host 源码 12036 行里只有 14 行用: any(0.1%)⇒「类型过」不是靠any糊过去的。- 实际 import 的
@deepseek-ai/*只有 4 个包、每包 1 个符号,运行时导出逐个核对 ⇒ 0 缺失。 dsh.client.inject语义未变。⚠ manifest 类型里那句 "Informational … not Cordis service injection" 指的是对 Cordis 而言,运行时仍用 manifest 的inject排 factory 到达顺序——别把它误读成语义变更。- manifest schema 兼容;新增的
external是可选的,本插件不需要。 cordis.patch.yml的insert:行仍被支持(0.2.0 的新能力是新增「bundle 自列其 rows」)。- 宿主只校验
peerDependencies、不读engines.dsh。 - dsh 侧无
CHANGELOG;docs/upgrade-guide/尚无 0.2.0 篇。
⚠ 以上全是静态核对:运行时(cordis 服务在 activate 时是否仍在、插件能否在桌面版 profile 正常加载)需重启宿主实测。
验证
- 桌面版首次验证:
tf-mur2p4y0-9qkpqh——completed/humanIntervention=false/ 12m04s / input 1.43M / 49 calls。分诊判成 lite(design / scaffold 未经历,符合「小活别上流水线」);三项 host 检查全部执行(接口核对是skip;源文件 0 个 —— 不足两个源文件,属有明确原因的合理 skip,不是静默跳过);ACCEPTANCE.md末行验收结论:✅ 通过,46 条断言 0 失败。 - 全量:
npm test/tsc --noEmit/oxlint --deny-warnings/ conformance 26/26 / instruction-budget(19 条锚点、无孤儿)全绿;web 与 desktop 两个 profile 副本逐字节一致。
English
⬆️ Upgrade notes
- Host window widened to dsh 0.2.0-rc.2 (preview). The range is a union,
">=0.1.7-alpha.1 <0.3.0 || >=0.2.0-rc.1 <0.3.0"— ⚠ the upper bound cannot simply be widened: under semver's rule that a prerelease only matches a range on the same tuple, changing<0.2.0to<0.3.0still fails for0.2.0-rc.1/0.2.0-rc.2(measured with semver 7.7.4). - The desktop app (dsh 0.2.0+) needs its own install: it runs from a separate
desktopprofile with its ownnode_modules. Installed only intoweb, the desktop app will not show the plugin (nothing is broken — that profile simply doesn't have it). The CLI also refuses--profile desktop(managed exclusively by the Electron application) ⇒ install it from the desktop app's own plugin management UI. - Restart
dsh --profile web(or the desktop app) after upgrading. - ⚠ Prompts got longer:
host/prompts/index.tsgrows by 76 lines net (five craft clauses + four disk-path pointers). This repo'sinstruction-budgetgate covers AGENTS.md only, not prompts, so the cost is unquantified (increment is in the hundreds of characters per prompt). - New log key:
log.hostScanTruncated.
① The deliverable scan no longer gets cut off (headline)
Evidence: tf-mupnk8h0-1otbl2 — the workspace held a pnpm .pnpm-store/ with thousands of extension-less blobs, and the old skip list missed it while readdir returns it before AGENTS.md ⇒ the 400-file cap was consumed instantly ⇒ the returned 400 entries contained 0 source files and 0 HTML ⇒ all four host checks (load / interface / smoke / evidence observation) silently skipped and the journal read as "the delivery contains nothing" — while the delivery was intact (28 files / 13 sources / 1 index.html). It surfaced only when the user found the demo page's slider un-clickable in the browser.
Fix: scanDeliverableFiles(root, limit) returns { files, truncated, limit } and never walks dot-directories (they are never deliverables and are the usual cap-eaters); listDeliverableFiles becomes a thin wrapper (same signature, same behaviour). If any of the three checks reports truncated, a log.hostScanTruncated retraction line is appended.
⚠ Wording matters: the three "not executed / 0 source files / no-html" lines are kept verbatim (the checks genuinely didn't run) — the retraction is a following warn that names them as not facts ⇒ order is part of the contract (pinned by orchestration test group ⑨: neg@13 / warn@16).
Two test layers: scanner level (test/smoke-check.test.js §2b) and wiring level (test/orchestration.test.js group ⑨ — 430 extension-less files saturating the 400 cap). Mutation check: short-circuiting if (scanTruncated) turns 4 assertions red.
② Large-document injection: bare clip → small teaser + on-disk full path
Measured over 256 real task-folder documents: TECHNICAL.md median 19075 / max 35547; DESIGN.md median 9338; PRD median 6334; QA-REPORT median 4430.
| Document | Old cap | Truncated | Action |
|---|---|---|---|
| TECHNICAL.md (dev / qaFix) | 12000 | 47/50 (94%) | 4000 + disk path |
| DESIGN.md (scaffold / tech) | 10000 | 11/31 (35%) | 4000 + disk path |
| PRD.md (design / tech / architect) | 15000 / 12000 | 3–6/56 (5–11%) | cap unchanged, path added |
| QA-REPORT.md (qaFix) | 12000 | 2/51 (4%) | cap unchanged, path added |
⚠ Counter-intuitive: with a median of 19075, even a 4000-char teaser is truncated 94% of the time ⇒ the disk path is the actual fix; the teaser is marginal — without it the model has no idea more content exists.
Deliberately untouched: clip(scaffold, 10000) and clip(devSummary, 8000) — neither is an on-disk file, so there is nothing to point at; a pointer would be noise.
Gate: 6 source-level locks (tech / design "only 4000" + four "path pointer covers N sites": TECHNICAL 2, DESIGN 3, PRD 3, QA 1).
③ craft guidance channel (design → dev connected)
Born from the mechanism analysis of the "pipeline vs bare agent" comparison: the DESIGN.md written by designPrompt never reached dev (devPrompt had no design parameter), so the pipeline structurally lost to a single agent on "make it look good".
devPrompt(task, tech, prd, design, …)gained thedesignparameter, injects the visual spec + disk path, and states that the visual spec is written first in DESIGN.md and must be read before writing anything visible.- Switch
TEAMFLOW_CRAFT: unset / empty = on; only0/false/off/noturn it off; wiredutil.envFlagOn→options.craft→state.__runCtx.craft. Not a tool parameter (tool descriptions enter the main session context every time); resume reads the journal snapshot, not the environment variable. - Narrowed to an interaction-feedback floor plus state visibility, not an aesthetic verdict; QA records P3 observations only, never blocking (weak/local models cannot produce craft — a blocking gate would make the plugin unusable for them).
- ⚠ Net benefit is still unproven: three samples point in different directions, all confounded by QA rework rounds / dev task granularity / silently-skipped host checks. See
docs/benchmarks/craft-ab-pomodoro.md.
④ New scripts
scripts/artifact-selfcheck.mjs— static artifact self-check (no browser):[geo]geometric consistency,[bind]unbound buttons and ambiguous selectors,[craft]feedback-state count,[state]dead snapshot,[persist]persistence gaps.[state]came from a real false negative: a deliverable whose slider did nothing, while every static metric (feedback rules 10 vs 9, AC count, bind/geo) was green.scripts/hi-report.mjs— read-only human-intervention attribution. Motivation: the repo had been prioritising against "humanIntervention 8/23 = 35%", a figure from samples older than 09-17. Measured over 91 runs: 58 before 09-17 (20.7%, 12 failed) vs 33 after (9.1%, 0 failed), and all 3 remaining cases areknownIssuesAcceptance(QA rework limit reached ⇒ the product decision is deliberately handed to a human, not a defect).
⇒ Without a repeatable measurement, stale numbers keep driving priorities — this script is that measurement.
⑤ Guards / orchestration / client (earlier part of this cycle)
- Clarification-gate telemetry (ADR-0010 step 1).
- env-unavailable no longer kills "file-level self-healing conflicts"; a progress exemption was added (judged by successful calls, not
lastMutationAt). - "Tool not applicable at this layer" is no longer fatal (a subagent without an Agent Team identity can't call those tools, but the workspace is fine) + collaboration tools banned in prompts + dev end-to-end evidence.
- A resumable terminal state no longer archives the staging logs — resume relies on the previous round's checker as the regression contract.
- Removed the misleading "verification scripts get dropped with the run" framing; splitting checkers into "rebuild" tasks is now forbidden.
- Client narrow-screen: touch on the pipeline canvas, zoom floor no longer hard-coded, list view by default on narrow containers (issue #10); ⚠ the zoom floor stays at 0.5 (at 0.12 cards are 37×7px and blur into one blob — an earlier attempt mistook "see everything" for the goal and was reverted); fixed the detail popover's left overflow on narrow containers; canvas hints are device-neutral. Mobile is out of scope (the dsh host itself doesn't do it) — recorded as a ⛔ rejected item in
docs/TODO.md, not in the README.
⑥ Corpus / tests
corpus/qa-defect-rich-columns.md: adds rich columns + header-driven column order (severity deliberately last) + escaped-pipe restoration. The five existing defect corpora all go through theparseDefectsprojection, soreproduce/expected/actual/ac/check/criterionand the wholecolumnsmap were never asserted. Mutation check: with escaping disabled only the new corpus turns red — the older sample whose note calls itself "the R3-2 escaped-pipe regression gate" stays green ⇒ what a corpus asserts can only be answered by mutation testing, not by its note.corpus/tech-blueprint-valid.md/tech-blueprint-unrepairable.md: completeextractBlueprint's three states (valid / repairable / unrepairable ⇒ null); conformance 24 → 26.test/locale.test.jsgained a placeholder-coverage gate (224 parameterised calls). Origin: the first desktop run's journal printed a literalhost 侧冒烟:{entry} …because the template has{entry}while the call site passed only{draw, raf, mut, ms}. Two such misses existed repo-wide (the other isguard.envProgressmissinglabel). ⚠ The argument table must be extracted with balanced braces: call sites often embedt(..., { n }), and[^}]*truncates at the nested}and reports "already passed" as "missing".
⑦ Host compatibility audit (dsh 0.2.0-rc.2)
Item-by-item audit: no breakage found (seven evidence items in the CHANGELOG.md section for this release). ⚠ All of it is static: runtime behaviour (whether cordis services survive plugin activation, whether the plugin loads in the desktop profile) needs a host restart to verify.
Verification
- First desktop-profile verification:
tf-mur2p4y0-9qkpqh—completed/humanIntervention=false/ 12m04s / input 1.43M / 49 calls. Triage chose lite (no design/scaffold, matching "don't run the pipeline for small work"); all three host checks executed (the interface check reportedskip; 0 source files — fewer than two source files, a legitimate skip with a stated reason, not a silent one);ACCEPTANCE.mdends with验收结论:✅ 通过, 46 assertions, 0 failures. - Full suite green:
npm test/tsc --noEmit/oxlint --deny-warnings/ conformance 26/26 / instruction-budget (19 anchors, no orphans); thewebanddesktopprofile copies are byte-identical.