Skip to content

Releases: TheLiudawei/dsh-codeflow-canvas

v1.4.2 — Measured, not claimed · 实测,不是口号

Choose a tag to compare

@TheLiudawei TheLiudawei released this 02 Nov 14:35

English · 中文

English

The README's comparison table described behaviour. It now carries measurements — and the suite that produces them fails the day they stop being true.

A reproducible benchmark

npm run bench (tests/bench.mjs, no dependencies) drives a fixed 60-module fixture through the real /flow-import command and the real undo manager, then prints:

measured value
import (cold / warm) ≈90 ms / ≈70 ms (65–120 ms across runs)
agent wakeups during import 0
prompt tokens spent on import 0
tasks / module nodes produced 9 / 39
tasks derived from TODO / FIXME / HACK 5
two independent imports agree on analysis fields 48 / 48
undo checks (byte-exact restore, added file removed, report accurate) 4 / 4

The fixture is generated by a pure function, so it is identical on every machine. The run exits non-zero if determinism or undo stops holding — that is what keeps the published table from rotting.

What it deliberately does not measure

What a model would spend writing the same plan in the transcript. Nobody measured that here, so the README states a labelled lower bound (source bytes ÷ 4 ≈ 3.5k tokens) instead of inventing a saving percentage. A claim without evidence is the exact thing this plugin exists to avoid — the benchmark follows the same rule as the product.

Also in this release

  • Timings are published as a range (65–120 ms), not one run's number, because repeat runs vary while the zeros and the agreement counts do not.
  • bench runs as the 18th suite in npm test and in CI on all three platforms, so a regression in determinism or undo shows up as a red build rather than as a stale README.

Full changelog: v1.4.1...v1.4.2


中文

English

README 里的对比表原先只是在描述行为,现在它带着测量结果——而且产生这些结果的套件,会在数字不再成立的那天变红。

可复现的基准

npm run bench(tests/bench.mjs,零依赖)把一份固定的 60 模块夹具喂给真实的 /flow-import 命令与真实的撤销管理器,然后输出:

实测项 数值
导入(冷 / 热) ≈90 ms / ≈70 ms(多次运行 65–120 ms)
导入期间唤醒 agent 次数 0
导入消耗的 prompt token 0
产出的任务 / 模块节点数 9 / 39
由 TODO / FIXME / HACK 生成的任务 5
两次独立导入的分析字段一致数 48 / 48
撤销校验(逐字节还原、新增文件移除、报告准确) 4 / 4

夹具由纯函数生成,在任何机器上都完全一致。只要确定性或撤销不再成立,这次运行就返回非零——这就是这张表不会悄悄过期的原因。

它刻意不测什么

模型在对话里写同样计划会花多少 token。这里没人测过,所以 README 只给出一个标明来源的下界(源码字节 ÷ 4 ≈ 3.5k token),而不是编一个节省百分比。没有证据的声明,正是这个插件想避免的东西——基准遵循和产品同一条规则。

本版还包括

  • 耗时以区间形式发布(65–120 ms),而不是单次数字:重复运行会浮动,但两个 0 和一致计数不会。
  • bench 作为第 18 个套件进入 npm test 与三平台 CI,所以确定性或撤销一旦退化,是一条红灯,而不是一段过期的 README。

完整变更:v1.4.1...v1.4.2

v1.4.1 — README repositioned around evidence · 首屏改为陈述立场

Choose a tag to compare

@TheLiudawei TheLiudawei released this 02 Nov 14:24

English · 中文

English

Documentation only — no code changed.

The front page argues a position now

The README used to open by describing what the plugin looks like. It now opens with what it is for:

  • Problem first. "You ask an agent to add validation to eight files. It answers done." Then the questions that follow — which eight, did they pass, what else did it touch, how far back do you unwind — and the line the whole plugin exists to answer: prose is not a diff.
  • A five-row comparison against planning in the transcript: where the plan comes from, what failed and why, "it says it finished", undoing a bad run, deliverables.
  • Three claims the transcript cannot make, each citing the code that backs it: deterministic import (lib/importer.js, lib/analyst.js, lib/duo.js), per-run undo (lib/undo.js), and honest node status (lib/gestures.js optimistic running + lib/index.js end-of-turn reconciliation).

No fabricated numbers

There is no "saves 70% of tokens" in that table, because nobody measured it. Every row is a behaviour you can read in the source, which is the point: a claim without evidence is the exact thing this plugin was built to avoid. If a claim here ever stops being true, the code reference next to it is where the correction starts.

ComfyUI-style stays in the opening paragraph, so the phrase people search for is still there.

Full changelog: v1.4.0...v1.4.1


中文

English

只动文档,没有代码变更。

首屏现在陈述立场

README 原先开头在描述这个插件长什么样,现在开头讲它是用来干什么的:

  • 先讲问题。 "你让 agent 给 8 个文件加校验,它回你一句完成了。" 然后是一连串追问——哪 8 个、过没过、还动了什么、要退回哪一步——以及整个插件要回答的那句话:散文不是 diff。
  • 一张五行对比表,对照"在对话里排计划":计划从哪来、哪里失败为什么、"它说完成了"、改坏了怎么退、交付物。
  • 三条对话记录做不到的事,每条都标注支撑它的代码:确定性导入(lib/importer.js、lib/analyst.js、lib/duo.js)、按次撤销(lib/undo.js)、诚实的节点状态(lib/gestures.js 乐观置 running + lib/index.js 回合结束对账)。

没有一个编造的数字

对比表里没有"节省 70% token"这种话,因为没人测过。每一行都是能在源码里读到的行为——这正是重点:没有证据的声明,就是这个插件想解决的问题本身。哪天某条声明不再成立,它旁边那行代码引用就是修正的起点。

ComfyUI 风格留在开头段落里,别人搜索时会用到的词没丢。

完整变更:v1.4.0...v1.4.1

v1.4.0 — Brand mark, version-discipline guard · 品牌标识、版本纪律守卫

Choose a tag to compare

@TheLiudawei TheLiudawei released this 02 Nov 12:54

English · 中文

English

A visible change to the product's face — which is exactly why it gets its own version.

CodeFlow has a mark

The sidebar icon, the toolbar logo and the empty state used to draw ⬡: a text glyph that renders differently on every platform and every font stack. They now share one vector mark — a hex canvas cut by the flow channel:

  • Toolbar and empty state draw the mark inline from tools/port-canvas.mjs (17px and 46px), colours baked into the SVG so the canvas stays theme-independent.
  • The sidebar draws the same geometry in currentColor, so the host still owns hover and selected tints.
  • assets/branding/ is the source of truth: logo.svg (colour), logo-on-light.svg, logo-mono.svg, and PNGs at 32 / 64 / 128 / 256 / 512 for stores, docs and cards.
  • Both READMEs lead with the mark, and docs/images/social-preview.png (1280×640) is ready for the repository's social card.

Version discipline is now enforced

This release exists because of a process failure: a feat(brand) commit landed past the v1.3.2 tag while package.json still said 1.3.2. Anyone reporting "the icon looks different" had no version to point at — tag, version and code disagreed.

tests/release.mjs now makes that impossible:

  • HEAD is the latest tag → package.json must match the tag;
  • HEAD has unreleased commits → package.json must be strictly greater than the latest tag, and the failure message states how many commits are ahead and both versions;
  • no semver tags (shallow clone, new repo) → the check is skipped rather than faked.

It runs as the 17th suite in CI (the checkout now uses fetch-depth: 0, otherwise tags are missing) and in npm test. Both directions were verified before release: 1.4.0 ahead of v1.3.2 passes; 1.3.2 ahead of v1.3.2 fails.

Full changelog: v1.3.2...v1.4.0


中文

English

产品门面上的可见变化——正因如此它值得一个自己的版本号。

CodeFlow 有了正式标识

侧栏图标、工具栏 logo 与空状态原先画的是 ⬡:一个在每台机器、每种字体栈上渲染都不一样的文本字形。三处现在共用同一枚矢量标——六边形画布被流程通道切开:

  • 工具栏与空状态由 tools/port-canvas.mjs 内联绘制(17px 与 46px),颜色写死在 SVG 内,画布因此与主题解耦。
  • 侧栏用 currentColor 画同一套几何,悬停与选中色仍归宿主决定。
  • assets/branding/ 是唯一事实来源:logo.svg(彩色)、logo-on-light.svg、logo-mono.svg,以及 32 / 64 / 128 / 256 / 512 的 PNG,供商店、文档与卡片使用。
  • 两份 README 都以该标识开头,docs/images/social-preview.png(1280×640)已备好用于仓库社交卡。

版本纪律现在由测试强制

这一版的存在本身就是一次流程失误的修正:一个 feat(brand) 提交落在了 v1.3.2 标签之后,而 package.json 仍是 1.3.2。任何人反馈"图标长得不一样"时都无处可指——标签、版本号、代码三方各说各话。

tests/release.mjs 让这种情况不再可能:

  • HEAD 就是最近标签 → package.json 必须与该标签一致;
  • HEAD 有未发布提交 → package.json 必须严格大于最近标签,失败信息会写明领先多少个提交、两个版本号各是多少;
  • 没有可用的 semver 标签(浅克隆、新仓库)→ 跳过而不是伪造通过。

它作为第 17 个套件跑在 CI 里(checkout 已改为 fetch-depth: 0,否则拿不到标签),也包含在 npm test 中。发布前双向验证过:1.4.0 领先 v1.3.2 通过;1.3.2 领先 v1.3.2 失败。

完整变更:v1.3.2...v1.4.0

v1.3.2 — Stricter card anchors, drift downgrade, run-all · 卡片锚点收紧、漂移降级、测试聚合

Choose a tag to compare

@TheLiudawei TheLiudawei released this 02 Nov 12:02

English · 中文

English

Card identity got stricter, and two long-standing defects the CI matrix caught are fixed.

Only path-shaped tokens become source anchors

A card's identity is task:<type>:<source anchor>. The old rule took any fragment containing a dot, so v1.2.3, 3.5, https://example.com/x.md and e.g. all became anchors. Two consequences: two unrelated cards could pair up, or the same card could stop pairing after a re-import — and silently lose its run state.

A token now qualifies when it contains a path separator, or ends in a known source extension (SOURCE_EXTENSIONS, ~90 entries: code, config, docs, stylesheets, markup). Explicitly rejected: scheme URLs (https://, file://, vscode://), version patterns (v1.2.3, 2.0), bare numbers (3.5), abbreviations (e.g., i.e.) and timestamps. Line suffixes (path:12) still work, Windows separators are normalised, and a URL followed by a real path picks the path.

Five counterexamples and seven positive cases are in tests/cards.mjs — all of them reproduce on the previous rule.

Drifted cards drop back to pending

When the scanned source changed since the last import (paramsDrift), the old "done" is no longer evidence about the current state. Such cards now:

  • return to pending — the same rule as "not executed means failed": never let a stale result pose as the current state;
  • keep a note 源码已变,需重跑 in detail;
  • show an amber 源码已变,需重跑 badge (distinct from the grey dashed "no longer in source" badge), which disappears as soon as the card runs again.

No drift, no change — re-importing an unchanged project leaves statuses untouched.

npm test is one aggregator

tests/run-all.mjs spawns all sixteen suites in order, collects every exit code, and prints one summary table with per-suite timing. It is aligned with CI's if: always(): a failing suite never hides the ones after it. Exit code is 0 only when all sixteen pass.

Two defects found by the CI matrix

  • Undo reported same-size edits as unchanged. files.modified was derived from size plus a 1 ms mtime tolerance; a same-size edit (print("v1") → print("v2")) written within the same millisecond on a high-resolution filesystem was silently dropped, so the restore report came back empty on Linux. dryRun and restore now compare contents when size matches and the timestamps are within 1 ms.
  • Fixture cleanup raced the plugin. rm(recursive) occasionally threw ENOTEMPTY on macOS because the plugin's debounced persistence can drop a file back into the directory while it is being deleted. Recursive removals in validate now retry with a short backoff instead of failing the run.

Full changelog: v1.3.1...v1.3.2


中文

English

卡片身份更严格了,另外修掉两个由 CI 矩阵抓出来的既有缺陷。

只有「像路径」的 token 才能成为源锚点

卡片身份是 task:<类型>:<源锚点>。旧规则把任何含小数点的片段都当路径,于是 v1.2.3、3.5、https://example.com/x.md、e.g. 都会变成锚点。后果有两个:两张无关的卡片可能配到一起;或者同一张卡片换个导入就配不上了——运行状态悄悄丢失。

现在 token 要么含路径分隔符,要么命中已知源码扩展名(SOURCE_EXTENSIONS,约 90 项,覆盖代码、配置、文档、样式、标记语言)。显式排除:带 scheme 的 URL(https://、file://、vscode://)、版本号(v1.2.3、2.0)、纯数字(3.5)、缩写(e.g.、i.e.)、时间戳。行号后缀(path:12)仍然有效,Windows 分隔符照常归一,URL 后面跟着真路径时取那个路径。

五条反例与七条正例都在 tests/cards.mjs——它们在旧规则下全部可复现。

漂移的卡片退回 pending

当扫描到的源码相对上次导入发生变化(paramsDrift)时,旧的「完成」就不再是当前状态的证据。这类卡片现在:

  • 退回 pending——与「未执行即失败」同一口径:绝不让过期结果冒充当前状态;
  • 在 detail 里记一条「源码已变,需重跑」;
  • 画布上挂琥珀色「源码已变,需重跑」徽章(与灰虚线「源码中已不存在」区分),重跑后自动消失。

没有漂移则什么都不动——重新导入未变更的项目不会改动任何状态。

npm test 合并成一个聚合器

tests/run-all.mjs 顺序启动全部 16 个套件、收集每个退出码、末尾打印一张带耗时的汇总表。与 CI 的 if: always() 对齐:失败的套件不再掩盖它之后的套件。只有 16 个全过,退出码才是 0。

CI 矩阵揪出的两个缺陷

  • 撤销把同尺寸修改判成未修改。 files.modified 原先按 size 加 1ms 的 mtime 容差推导;同尺寸改动(print("v1") → print("v2"))若落在同一毫秒内,在高分辨率文件系统上会被静默丢弃,于是 Linux 上恢复报告是空的。dryRun 与 restore 现在在「尺寸相同且时间差 ≤1ms」时按内容比对。
  • 临时目录清理与插件抢跑。 rm(recursive) 在 macOS 上偶尔抛 ENOTEMPTY——插件去抖落盘可能在删除过程中把文件放回去。validate 里的递归删除改为短退避重试,不再因竞态整轮标红。

完整变更:v1.3.1...v1.3.2

v1.3.1 — Cross-platform test suite, CI on three OS · 跨平台测试、三平台 CI

Choose a tag to compare

@TheLiudawei TheLiudawei released this 02 Nov 11:47

English · 中文

English

No feature changes. This release makes the test suite trustworthy on machines that are not the author's — and fixes one real geometry bug the expanded suite caught.

Test suite: platform-independent

  • Reading a file no longer depends on how git checked it out. Several assertions matched multi-line source fragments with a literal \n, which breaks the moment a Windows clone checks the file out with CRLF. The shared read() now normalises CRLF to LF, assertions compare content rather than line endings, and .gitattributes pins * text=auto eol=lf so every checkout — and the committed canvas — is byte-identical across platforms.
  • One assertion was Windows-only. It compared the identity key produced with the host platform against the win32 result, so it could only ever pass on Windows. The following lines already asserted the win32 and POSIX cases explicitly, so the placeholder is gone.
  • /flow-import checks are hermetic. Four of them passed only because a stale %TEMP%/codeflow-fake-cwd happened to exist from an earlier run; on a clean machine they failed with NO_WORKSPACE. They now pass the fixture root explicitly.
  • Windows paths are asserted with an explicit platform. The workspace and browse suites used C:\… / UNC inputs while the implementation folds case only on win32 and parentOf follows node:path — so those checks asserted Windows semantics on Linux and macOS. Windows cases are now guarded (or pass 'win32'), with POSIX counterparts added.

Canvas freshness is a content hash

The button audit used to compare mtimes. In a fresh clone git writes the tree in index order, so the generated canvas always looks older than the patch files and the check reported a false positive every time. The generator now stamps the hash of its inputs into the canvas header (tools/canvas-sources.mjs is the single input list) and the audit recomputes it — verified in both directions: editing a patch without regenerating reports stale-canvas with both hashes; restoring it passes again.

Fixed: popover height clamp

fit-popover computed its minimum height as Math.min(minListHeight, Math.max(minListHeight, innerH)), which is identically minListHeight — the clamp did nothing. A short stage still demanded 96px and pushed the list past the bottom edge. It is now Math.min(minListHeight, innerH), with maxHeight clamped to the available height after the branch. The boundary test drops from a 200px stage to 100px (inner height 84px < 96px) so it actually exercises the case.

CI

Sixteen suites now run on Ubuntu, Windows and macOS (Node 22), all blocking. Every step carries if: always(): one failing suite no longer hides every suite after it, so a single run reports the whole picture. npm test runs the same sixteen locally.

This closes the two failures reported in #2 — thank you for the reproduction: it closed the gap between "green on the author's machine" and "green on a user's machine".

Full changelog: v1.3.0...v1.3.1


中文

English

没有新功能。这一版让测试套件在别人的机器上也可信,并修掉了测试扩容后抓到的一个真实几何 bug。

测试:不再依赖平台

  • 读文件不再取决于 git 怎么检出。 多条断言用字面量 \n 匹配跨行源码片段,Windows 克隆一旦检出成 CRLF 就全部失效。现在共享的 read() 统一把 CRLF 归一为 LF,断言只比内容不比行尾;.gitattributes 固定 * text=auto eol=lf,各平台检出(以及提交进仓库的画布)逐字节一致。
  • 一条断言只在 Windows 成立。 它拿宿主平台算出的标识去比 win32 的结果,因此只可能在 Windows 上通过;紧随其后的两行本来就分别断言了 win32 与 POSIX 情形,占位行删除。
  • /flow-import 检查已 hermetic。 其中四条之所以通过,只是因为 %TEMP%/codeflow-fake-cwd 里恰好残留着上一次运行留下的目录;干净机器上会报 NO_WORKSPACE。现在显式传入 fixture 根目录。
  • Windows 路径断言显式传平台。 workspace 与 browse 套件用 C:\… / UNC 作为输入,而实现只在 win32 折叠大小写、parentOf 走 node:path——等于在 Linux/macOS 上断言 Windows 语义。现在 Windows 分支加了守卫(或显式传 'win32'),并补了 POSIX 对照断言。

画布新鲜度改用内容哈希

按钮审计原先比 mtime。全新克隆里 git 按目录顺序写文件,生成物永远显得比补丁文件旧,于是每次都误报。现在生成器把输入源哈希写进画布头部(tools/canvas-sources.mjs 是唯一清单),审计重算比对——正反两个方向都验过:改补丁不重新生成会报 stale-canvas 并给出两个哈希,还原后恢复通过。

修复:弹层高度夹取

fit-popover 的最小高度写成 Math.min(minListHeight, Math.max(minListHeight, innerH))——恒等于 minListHeight,夹取形同虚设。极矮 stage 下仍然要 96px,把列表顶出下边界。现在改为 Math.min(minListHeight, innerH),并在分支后把 maxHeight 夹到可用高度。边界用例也从 200px stage 降到 100px(内高 84px < 96px),真正覆盖到这种情况。

CI

16 个套件现在跑在 Ubuntu、Windows、macOS 三平台(Node 22),全部阻塞。每个步骤都带 if: always():一个套件失败不再掩盖它之后的所有套件,一轮就能拿到全貌。本地 npm test 跑的是同一套。

本版修复了 #2 报告的两项失败——感谢那份带完整复现路径的报告,它补上的正是"作者机器上的绿"和"用户机器上的绿"之间的差距。

完整变更:v1.3.0...v1.3.1

v1.3.0 — UX overhaul · 使用体验优化

Choose a tag to compare

@TheLiudawei TheLiudawei released this 02 Nov 10:29

English · 中文

English

This release adds no new analysis capability. Everything is about everyday feel: the toolbar never wraps, the secondary node list always fits, re-importing no longer loses task progress, and problems can be inspected from settings. Zero new npm dependencies.

1. Toolbar rebuilt as named menus + primary actions

The old toolbar was one flat row of buttons that wrapped and shifted in narrow windows. It is now:

logo · Project / Run / View / Help · view tabs · New / Import / Run all · Undo / Save / Settings

  • flex-wrap: nowrap — no wrapping at any width; below 720px the four menus collapse into a ☰ panel
  • Collapsed and expanded states come from one model: lib/ui/menu.js defines the structure, lib/ui/menu-html.js renders static markup at build time, and tools/patches/menu-ui.js only delegates events through an action-key → existing-function lookup, so both states share the same handlers and cannot drift
  • Fully keyboard accessible: ↑/↓ to move, Home/End to jump, Esc to close; complete ARIA (role=menu/menuitem, aria-expanded/aria-haspopup)

2. The secondary node list always fits inside the canvas

  • Position and height are derived by a pure function, lib/ui/fit-popover.js, from the available stage space (inlined at build time — one implementation): a 480px-tall list with 200 nodes can still scroll to the last row
  • The search field stays visible; it is never pushed out of the viewport
  • The wheel over the list no longer zooms the canvas; the category rail scrolls on its own

3. Task cards survive re-import (opt-in, default off)

Re-importing the same project used to overwrite the whole graph, losing run status, tuned parameters and arranged positions. Now:

  • The canvas asks once per workspace the first time it opens (cards.asked in CodeFlow/config.json) and never bothers you again
  • When enabled, cards merge by stable identity (lib/cards/identity.js): run state, results, position, edited titles and params attach to the freshly scanned graph
  • Tasks deleted from source are kept as stale cards — excluded from Run all, removable from the project menu in one click, so history is never silently dropped
  • Merging is a pure function (lib/cards/merge.js); a failure only warns and never blocks the import
  • With the option off, behaviour matches v1.2.2 exactly (overwrite + .bak- backup)

4. Work log viewer in settings

Since v1.2.2 the plugin writes a JSONL log, but you had to dig through folders. Settings → View work log (also the Help menu) now opens a read-only viewer:

  • Level filtering and case-insensitive search
  • Tail-follow (2 s polling, stops when closed — nothing stays resident)
  • Copy the visible raw JSONL lines; "reveal in folder" degrades to copying the path with an explicit notice when the host lacks the capability — it never pretends to succeed
  • Backed by GET /api/log (tail / rotated / level / q): the file path is bound at assembly time, so request parameters cannot point elsewhere

Compatibility and regressions

  • The 73-control manifest (lib/ui/actions.js) is updated; tests/buttons.mjs and the manual checklist cover the new menu entries
  • New tests/cards.mjs (merge pure function, stale cards, behaviour when the option is off) and tests/log-viewer.mjs (filter / search / follow / path binding)
  • tests/architecture.mjs keeps pinning the layering: menu, fit-popover and merge are all pure functions that never touch req/res
  • No breaking changes: without card retention enabled, behaviour matches v1.2.2

Full changelog: v1.2.2...v1.3.0


中文

English

本版不新增分析能力,全部改动集中在日常操作的手感:顶栏不再换行、二级列表永远放得下、重新导入不再丢任务进度、出问题能在设置里直接看日志。零新增 npm 依赖。

一、顶栏重构为「命名菜单 + 主操作」

旧顶栏是一排没有层次的按钮,窄窗口下换行错位。现在改为:

logo · 项目 / 运行 / 视图 / 帮助 · 视图 tab · 新建 / 导入 / 运行全部 · 撤销 / 保存 / 设置

  • flex-wrap: nowrap——任何宽度都不换行;<720px 时四个菜单收进 ☰ 分组面板
  • 折叠态与展开态出自同一份模型:lib/ui/menu.js 定义结构,lib/ui/menu-html.js 在构建期渲染成静态标记,tools/patches/menu-ui.js 只做事件委托,经一张 action key → 现有函数的查表复用同一份处理逻辑——两个状态不可能行为不一致
  • 全键盘可用:↑/↓ 移动、Home/End 跳首尾、Esc 关闭;ARIA 完整(role=menu/menuitem、aria-expanded/aria-haspopup)

二、二级节点列表永远完整落在画布内

  • 位置与高度由纯函数 lib/ui/fit-popover.js 按 stage 可用空间反推(构建期内联,单一实现):480px 高度 + 200 个节点也能滚到最后一行
  • 搜索框始终可见,不会被挤到视口外
  • 列表上滚轮不再带动画布缩放;左侧分类栏自身可独立滚动

三、任务卡片重新导入不丢失(默认关闭)

以前重新导入同一项目会覆盖整张图,跑过的状态、调好的参数、挪好的位置全没了。现在:

  • 首次打开画布按工作区询问一次(cards.asked 写入 CodeFlow/config.json),不打扰后续使用
  • 开启后按稳定标识合并(lib/cards/identity.js):运行状态、结果、位置、改过的标题与参数都附着到新扫描的图上
  • 源码里已删除的任务保留为「失效卡片」——不参与「运行全部」,可从项目菜单一键清理,避免默默丢失历史
  • 合并是纯函数(lib/cards/merge.js);合并失败只警告,绝不阻断导入
  • 关闭时行为与 1.2.2 完全一致(覆盖 + .bak- 备份)

四、设置里可直接查看工作日志

v1.2.2 起插件会写 JSONL 日志,但只能去文件夹翻。现在「设置 → 查看工作日志」(或「帮助」菜单)打开只读查看器:

  • 级别过滤、大小写不敏感搜索
  • 跟随尾部(2 秒轮询,关闭即停,不常驻)
  • 复制可见的原始 JSONL 行、「打开所在目录」(宿主无此能力时降级为复制路径并明确提示,不假装成功)
  • 底层 GET /api/log(tail / rotated / level / q):文件路径在装配时绑定,请求参数指不到别处

兼容性与回归

  • 顶栏的 73 个控件清单(lib/ui/actions.js)同步更新,tests/buttons.mjs 与手动清单继续覆盖新菜单项
  • 新增 tests/cards.mjs(合并纯函数、失效卡片、开关关闭时的旧行为)与 tests/log-viewer.mjs(过滤/搜索/跟随/路径绑定)
  • tests/architecture.mjs 继续钉住分层:menu/fit-popover/merge 均为纯函数,不接触 req/res
  • 无破坏性变更:不开启卡片保留时,行为与 v1.2.2 一致

完整变更:v1.2.2...v1.3.0

v1.2.2 — Workspace addressing, UI audit, import roots, file logging · 工作区寻址、控件审计、导入根、文件日志

Choose a tag to compare

@TheLiudawei TheLiudawei released this 01 Nov 14:27

English · 中文

English

Changes since v1.2.0, covering the v1.2.1 and v1.2.2 change sets. Everything ships with zero new npm dependencies.

Workspace addressing rebuilt · 工作区寻址重建(v1.2.1)

Fixes the "project landed in the wrong place" class of bugs at the root:

  • New projects require a registered workspace. The new-project dialog gains a workspace dropdown (read-only GET /codeflow/api/workspaces) and a computed absolute-path preview. Requests without a registered workspace are rejected (400/409) — the plugin never creates or registers workspace roots on its own, and nothing is written to disk on rejection.
  • One explicit resolution chain. Binding → project directory → session cwd, longest-prefix matched against the workspace registry at each step; unresolvable now hard-fails with a candidate list. The old "first registered workspace" fallback — the source of projects silently landing elsewhere — is deleted.
  • Canvas sessions belong to their workspace. When the host exposes workspace entities, dedicated sessions are created with a workspaceId and attached to that workspace group instead of landing in "未分组".
  • Directory-tree picker for import. The import dialog's path field gains a 浏览… button over the read-only GET /codeflow/api/browse: directories only, symlinks/junctions never followed, 500 entries per level, 5 s timeout, keyboard-first (↑/↓/Enter/Backspace/Esc).

Audited UI · 可点击控件全部有绑定(v1.2.2)

Every clickable control in the canvas now has a manifest, a binding and an audit trail:

  • lib/ui/actions.js is the single source of truth (73 controls). tests/buttons.mjs statically proves each is registered with at least one binding path; the generator injects window.__CF_ACTION_MANIFEST__ for an in-canvas real-click self-test; the rest are covered by a manual checklist.
  • The audit found and fixed four real defects: the toolbar 「耦合分析」 button had never been click-bound (HTML-disabled, reachable only via right-click); the session chip was a focusable fake button (now opens the dedicated-session view); and the ✕ buttons of the drop confirm / progress / conflict dialogs were dead — close/cancel is now delegated once on #cf-dialog.

Conservative import roots · 导入只认真实项目根(v1.2.2)

Nested "shell-wrapped" imports no longer guess:

  • All three import channels (archive drop, folder drop, path/dialog import) share one conservative root resolver (lib/import/root-detect.js). After stripping an archive's outermost layer, descending continues only for project markers / obvious shell names / same-name-as-parent.
  • proj/src keeps proj as the root; an unmarked single-link shell answers 400 SHELL_AMBIGUOUS instead of inventing a project name; empty shells 400; multi-project parents keep the parent with a multiProject warning. tests/import-shells.mjs covers 51 fixture × channel combinations.

File logging · 工作与报错日志(v1.2.2)

  • The plugin writes a JSONL log codeflow.log at its install root: 5 MiB rotation (one .1 kept), serialized writes, degrade-don't-crash. It records lifecycle, import, coupling and HTTP/UI errors — never prompts, source code, graph JSON, cookies or tokens (key-name redaction + truncation).
  • The canvas reports ui.action / ui.error / ui.selftest via POST /codeflow/api/log (whitelisted, 64 KiB cap, 20 per batch). CODEFLOW_LOG=off disables; CODEFLOW_LOG_FILE overrides the path.
  • tests/architecture.mjs pins the layering: logging/root-detect have zero domain dependencies, the import pipeline never touches req/res, the static import graph is acyclic.

macOS field diagnostic kit · macOS 现场诊断套件

A standalone diagnostic suite for macOS issues, attached above as codeflow-mac-kit-1.2.2.zip (also in-repo at tests/mac/):

  • Host-side checks: environment, package integrity, canvas document, HTTP boot, paths/Unicode, deterministic import, archives/Finder drop, undo
  • A DevTools console probe for keyboard/IME/trackpad/context-menu/drag/UI behavior
  • Markdown/JSON report writer with filtering and redaction, a double-clickable .command launcher, a manual checklist and a report template
  • Documents known macOS findings: Finder's __MACOSX/._* scanned as source, missing 7z/rar tools, wheel-to-zoom, no isComposing guard

Full changelog: v1.2.0...v1.2.2


中文

English

自 v1.2.0 起的改动,合并 v1.2.1 与 v1.2.2 两个变更集。零新增 npm 依赖。

工作区寻址重建(v1.2.1)

从根上治「项目落到错的地方」这一类问题:

  • 新建项目必须选已登记的工作区。 新建对话框新增工作区下拉(数据来自只读的 GET /codeflow/api/workspaces)与最终绝对路径预览。请求缺少已登记工作区时直接拒绝(400/409)——插件绝不自己创建或登记工作区根目录,被拒时磁盘上什么都不多出来。
  • 工作区寻址只剩一条显式链。 绑定 → 项目目录 → 会话 cwd,逐档对工作区注册表做最长前缀匹配;解析不出就硬失败并给出候选清单。旧的「取第一个已登记工作区」回退——项目悄悄落到别处的根源——已删除。
  • 画布会话归属自己的工作区。 宿主提供工作区实体时,专用会话以 workspaceId 创建并 attach 进该工作区分组,不再落进「未分组」。
  • 导入新增目录树选择器。 导入对话框路径框右侧新增「浏览…」,底层是只读的 GET /codeflow/api/browse:只列目录、不跟符号链接/junction、单层 500 项、5 秒超时、键盘优先(↑/↓/Enter/Backspace/Esc)。

可点击控件全部有绑定(v1.2.2)

画布上每个可点击控件现在都有清单、有绑定、有审计:

  • lib/ui/actions.js 是单一事实来源(73 个控件)。tests/buttons.mjs 静态证明每个控件都登记且至少有一条绑定路径;生成器注入 window.__CF_ACTION_MANIFEST__ 供画布内真实点击自检;其余路径由手动清单逐项验收。
  • 审计揪出并修复了四个真实缺陷:「耦合分析」工具栏按钮从未绑过 click(HTML 里 disabled,只能从右键进入);会话 chip 是可聚焦但无动作的假按钮(现在点开「画布专用会话」);拖拽确认/进度/冲突三个对话框的 ✕ 是死按钮——close/cancel 现在由 #cf-dialog 上的一次事件委托统一兜底。

导入只认真实项目根(v1.2.2)

外壳套外壳的导入不再猜:

  • 三条导入通道(拖拽压缩包、拖拽文件夹、路径/对话框导入)共用一个保守根解析器(lib/import/root-detect.js)。压缩包先按既有语义剥最外层,之后只有「项目标记 / 明显外壳名 / 与父同名」才继续下钻。
  • proj/src 保留 proj 作为根;无标记的单链外壳直接答 400 SHELL_AMBIGUOUS,绝不生成名字/根目录错误的项目;空壳 400;多项目父目录保留父目录并记 multiProject 警告。tests/import-shells.mjs 覆盖 51 个「夹具 × 通道」组合。

工作与报错日志(v1.2.2)

  • 插件在安装根目录写 JSONL 日志 codeflow.log:5 MiB 轮转(保留一个 .1)、串行写、失败降级不崩。记录生命周期、导入、耦合分析与 HTTP/UI 错误——绝不记录提示词、源码、图 JSON、Cookie 或 Token(按键名脱敏 + 截断)。
  • 画布通过 POST /codeflow/api/log 上报 ui.action / ui.error / ui.selftest(白名单、64 KiB 上限、单批 20 条)。CODEFLOW_LOG=off 关闭;CODEFLOW_LOG_FILE 覆盖路径。
  • tests/architecture.mjs 钉住分层:logging/root-detect 零领域依赖、导入管道不接触 req/res、静态 import 图无环。

macOS 现场诊断套件

面向 macOS 问题的独立诊断套件,见上方附件 codeflow-mac-kit-1.2.2.zip(仓库内也有 tests/mac/):

  • 宿主侧检查:环境、包完整性、画布文档、HTTP 启动、路径/Unicode、确定性导入、压缩包与 Finder 拖拽、撤销
  • 一份 DevTools 控制台探针,覆盖键盘/输入法/触控板/右键菜单/拖拽/UI 行为
  • 报告写入器(Markdown/JSON,支持过滤与脱敏)、双击即用的 .command 启动器、手动测试清单与报告模板
  • 记录了已知的 macOS 现象:Finder 压缩包里的 __MACOSX/._* 会被当源码扫描、缺少 7z/rar 工具、滚轮缩放、缺 isComposing 守卫

完整变更:v1.2.0...v1.2.2

v1.2.0 — Feature mapping, coupling analysis, drag-and-drop import · 功能归属、耦合分析、拖拽导入

Choose a tag to compare

@TheLiudawei TheLiudawei released this 01 Nov 03:57

English · 中文

English

All three headline features are zero-LLM, zero-npm-dependency, offline-capable — everything is deterministic host-side computation.

A. Feature mapping index · 功能归属识别(v1.1)

A pure-local, deterministic index mapping feature → file → canvas node, persisted as features.json next to workflow.json:

  • Zero model calls — detection is all local: design.md parsing, entry signals, top-level symbols, directory/filename dictionaries, node text. No network, no LLM.
  • Durable keys are files (relative to the source root); nodes is only a cache of the current graph and re-maps by file when the graph is re-imported.
  • The manual section has highest priority and survives every rebuild.
  • Forgiving parsing: bad fields are dropped with at most one console.warn — never crashes the menu. With zero signals it honestly reports features: [] instead of fabricating clusters.

B. Module coupling analysis · 模块耦合分析(屎山程度)

Right-click a file-level module to analyze that file, right-click empty canvas (or the toolbar button) to analyze all — import runs it once automatically:

  • Per-node badges: a small 耦合 · 低|中|高 capsule (green/yellow/red, light-theme adjusted) plus a 3px color strip on the card edge — node size and ports untouched.
  • Overall card top-left: 屎山程度 · 中 + 模块 12 · 平均 42 · 环 2, with partial/stale states; clicking opens a detail dialog with the full per-module table (score, fan-in Ca, fan-out Ce, cycles, internal refs, symbols) and a re-analyze button.
  • Deterministic algorithm (lib/coupling.js, all constants exported for testing): score = round(0.6×intra + 0.4×inter) over the intra-file symbol graph and inter-module dependency graph, saturating functions, fixed thresholds 30/60; overall = row-weighted mean + cycle penalty. Same source, byte-identical results.

C. Drag-and-drop import · 拖拽导入

Drop a folder or archive onto the canvas to import:

  • Full-screen overlay → local precheck (type/count/size) → confirm dialog (editable project name, recursion depth, comment-task & test switches) → progress modal (prepare → upload N/M → extract → analyze, cancellable) → auto-opens the new project + auto coupling + toast.
  • Upload channel as the main path (the iframe can't see real dropped paths): folders are read recursively via webkitGetAsEntry() and POSTed to a staging area CodeFlow/imports/.staging/<token>/, finalized by a single rename; archives upload then extract to imports/<name>/. If the host bridge exposes getPathForFile (feature-detected), archives can take the fast local path.
  • Formats: zip / tar / tar.gz parsed in pure Node; 7z / rar degrade to system tools.

Architecture refactor (7 steps)

A large internal restructuring pass — behavior-preserving, comments unified to Chinese:

  • New lib/core/ foundation (fsio/path/text) breaking the store⇄paths cycle; graph-format extracted
  • Scan layer split out (walk/comments/symbols): importer.js 628→351 lines, analyst.js 509→313
  • Config layer (codeflow-config.js) and migration (migration.js) extracted; paths.js 533→155 lines as a pure resolution facade
  • store.js reshaped into five internal helper zones + public API
  • features split into six responsibility subpackages; features.js becomes the aggregation entry (1221-line single file retired)
  • HTTP layer split: routes.js 1725→220 lines across respond/context/canvas/state/import/features/project modules; gestures.js now owns the [CodeFlow:*] protocol; index.js is pure assembly

Full changelog: v1.0.1...v1.2.0


中文

English

三项主要能力都是 零 LLM、零 npm 依赖、可离线——全部是宿主侧的确定性计算。

A. 功能归属识别(v1.1)

一个纯本地、确定性的索引,把「功能 → 文件 → 画布节点」映射起来,落在 workflow.json 同目录的 features.json:

  • 零模型调用 —— 识别全部在本地完成:解析 design.md、入口信号、顶层符号、目录/文件名词典、节点文字。不访问网络,不调用模型。
  • 持久键是文件(相对源码根);nodes 只是当前图的缓存,图重新导入后按文件重新映射。
  • manual 段优先级最高,任何重建都原样保留。
  • 宽容解析:坏字段直接丢弃,最多 console.warn 一次——绝不把菜单搞崩。完全没有信号时如实返回 features: [],不做目录硬聚类。

B. 模块耦合分析(屎山程度)

右键文件级模块分析该文件,右键空白画布(或工具栏按钮)分析全部;导入完成后自动跑一次「全部」:

  • 节点徽章:节点头部一枚 耦合 · 低|中|高 小胶囊(绿/黄/红,浅色主题文字加深),卡片右缘 3px 颜色条——不改节点尺寸与端口位置。
  • 左上角卡片:屎山程度 · 中 + 模块 12 · 平均 42 · 环 2,支持部分结果与过期状态;点击打开详情弹窗,含逐模块表格(分数、扇入 Ca、扇出 Ce、成环、内部引用、符号)与「重新分析」按钮。
  • 确定性算法(lib/coupling.js,常量全部导出供测试):score = round(0.6×intra + 0.4×inter),intra 为文件内符号互引图、inter 为模块依赖图,配合饱和函数与固定阈值 30/60;整体分 = 行数加权均分 + 成环惩罚。同一份源码两次分析结果逐字节一致。

C. 拖拽导入

把文件夹或压缩包拖到画布上即可导入:

  • 全屏遮罩 → 本地预检(类型/数量/大小)→ 确认框(可编辑项目名、递归深度、注释任务与补测试开关)→ 进度框(准备 → 上传 N/M → 解压 → 分析,可取消)→ 自动打开新项目 + 自动耦合 + toast。
  • 上传通道是主路径(iframe 拿不到拖入项的真实路径):文件夹经 webkitGetAsEntry() 递归读取后 POST 到暂存区 CodeFlow/imports/.staging/<token>/,finalize 时整体 rename;压缩包上传后解压到 imports/<包名>/。若宿主桥接暴露 getPathForFile(特性探测),压缩包可走本地快速路径。
  • 格式:zip / tar / tar.gz 由纯 Node 解析;7z / rar 降级到系统工具。

架构重构(7 步)

一次较大规模的内部整形:行为不变,注释统一中文。

  • 新增 lib/core/ 基础层(fsio/path/text),斩断 store⇄paths 循环;提取 graph-format
  • 扫描层独立(walk/comments/symbols):importer.js 628→351 行,analyst.js 509→313 行
  • 配置层(codeflow-config.js)与迁移(migration.js)独立;paths.js 533→155 行,成为纯解析门面
  • store.js 整形成五个内部助手区 + 对外 API
  • features 拆成六片职责子包,features.js 变成聚合入口(1221 行单文件退役)
  • HTTP 层拆分:routes.js 1725→220 行,落到 respond/context/canvas/state/import/features/project 等模块;gestures.js 承载 [CodeFlow:*] 协议;index.js 成为纯装配

完整变更:v1.0.1...v1.2.0

v1.0.1 — Real test runs, edge-to-edge canvas, relocatable project root · 测试运行真实执行、画布贴边、项目根可迁移

Choose a tag to compare

@TheLiudawei TheLiudawei released this 31 Oct 09:39

English · 中文

English

A. Test runs execute for real ·「测试运行」空转修复

Field report: clicking 测试运行 sent [CodeFlow:RUN_NODE] to the dedicated session, the agent replied but never executed anything — the node stayed pending forever. Four layers fix it:

  • Self-contained run requests — RUN_NODE carries node (type/title/params, cmd included), upstream (direct upstream results, clipped to 120 chars), cwd (the directory commands must run in) and expect (one-line acceptance criterion); RUN_ALL carries the topo order of pending/failed nodes. The host appends a three-line execution-requirement footer after the first-line JSON: you must really execute this time, you must fill back via progress, and an un-executed node will be marked failed.
  • Hardened skill semantics — SKILL.md and references/node-types.md spell out the testrun contract: run in the project root, record the real command / exit code / output tail, missing runtime → failed with an actionable reason, marking done without executing is forbidden (especially "ran it earlier in this session").
  • Optimistic running — the target node flips to running the moment the prompt queues; delivery failure rolls the state back.
  • End-of-turn reconciliation + retry — a run whose turn ends without any progress call is marked failed (result: agent 未执行该节点), surfaced as a banner with a one-click retry (rerun=true).

B. Edge-to-edge canvas · 画布四边贴满面板

  • The generated canvas.html used to start with -->\--> — the port script kept the closing marker and the header replacement added another one, rendering as a ~22px gap plus a stray "arrow" at the top. The port script no longer duplicates terminators and self-checks before writing.
  • The embedded shell drops the 1px border and 14px radius of the canvas root; the toolbar wraps on narrow widths. Standalone preview keeps the card look.

C. Relocatable project root · 项目迁入 <workspace>/CodeFlow/

  • New layout: <root>/flow-projects/<project>/ with the default root at <workspace>/CodeFlow. lib/paths.js is now the single place assembling project paths.
  • The root is configurable in the canvas toolbar ⚙ settings (global root + per-project override, GET/POST /codeflow/api/config). The config file stays at <workspace>/CodeFlow/config.json so it remains discoverable per workspace.
  • Automatic legacy migration: on first resolve, projects under <workspace>/flow-projects/ move into the new root. Directories are moved as-is; conflicts are never overwritten; failures keep the old directory — data is never lost.

Packaging

  • Version labels unified to v1.0.1 across package.json, READMEs (English + 简体中文), skill docs and code comments; tools/export-archive.* output renamed accordingly.

Full changelog: 0083ffd...7065c48


中文

English

A.「测试运行」空转修复

实测现场:点「测试运行」后,专用会话收到 [CodeFlow:RUN_NODE],agent 回了几句话却没有执行任何命令,节点永远停在 pending。四层修复:

  • 运行请求自包含 —— RUN_NODE 直接携带目标节点的 type/title/params(含 cmd)、直接上游的 upstream(结果摘要,截断到 120 字)、命令必须执行所在的 cwd,以及一句话验收标准 expect;RUN_ALL 携带 pending/failed 节点的拓扑序 order。首行 JSON 之后,宿主再附三行「本次执行要求」:本次必须真实执行、结束前必须用 progress 回填、未执行就结束回合会被宿主置为 failed。
  • 技能语义硬化 —— SKILL.md 与 references/node-types.md 写死 testrun 契约:在项目根执行、记录真实命令/退出码/输出尾部;运行时缺失 → failed 并给出可行动原因;禁止未执行就置 done(尤其"之前跑过")。
  • 乐观置 running —— prompt 入队成功的一刻,目标节点立即变 running;投递失败回滚原状态。
  • 回合结束对账 + 重试 —— 运行回合结束但目标节点没有任何 progress 时,宿主置 failed(result: agent 未执行该节点),画布显示横幅并给出一键「重试」(rerun=true)。

B. 画布四边贴满面板

  • 生成的 canvas.html 开头曾是 -->\-->:port 脚本保留了结束标记、header 替换又自带一个,浏览器把多余的 --> 当正文渲染出一条 ~22px 的空隙和一个"箭头"。现在脚本不再重复终止符,并在写入前自检。
  • 嵌入外壳去掉画布根节点的 1px 边框与 14px 圆角;窄宽度下工具栏自动换行。独立预览保留卡片外观。

C. 项目迁入 <工作区>/CodeFlow/,支持自定义

  • 新布局:<根>/flow-projects/<项目名>/,默认根为 <工作区>/CodeFlow。lib/paths.js 成为项目路径的唯一拼装点。
  • 根目录可在画布工具栏 ⚙ 设置里配置(全局根 + 单项目覆盖,GET/POST /codeflow/api/config)。配置文件固定放在 <工作区>/CodeFlow/config.json,换根之后仍按工作区可发现。
  • 旧数据自动迁移:首次解析时把 <工作区>/flow-projects/ 下的项目搬进新根。只搬目录、不改内容;冲突不覆盖、失败保留旧目录——绝不丢数据。

打包

  • 版本标签统一为 v1.0.1:package.json、中英 README、技能文档与代码注释同步;tools/export-archive.* 的输出文件名一并更新。

完整变更:0083ffd...7065c48

v1.0.0 — Initial release · 首个发布

Choose a tag to compare

@TheLiudawei TheLiudawei released this 31 Oct 07:07

English · 中文

English

First public release: the DSH port of the ZCode plugin codeflow-canvas v0.2.2.

The canvas editor carries over from the original implementation; all host wiring was rewritten for DSH (DeepSeek Harness). At this point the plugin already provides:

  • Dual views — one deterministic import produces both the task pipeline (workflow.json) and the module graph (workflow.modules.json); switch from the toolbar at any time
  • Module highlighting — driven by real file-write tool calls (edit / write / apply_patch …, never guessed from prose)
  • Searchable two-level module navigation on the left rail
  • Native delivery through DSH's present tool, writing docs/DELIVERY.md
  • A dedicated session per project (CodeFlow · <project>); canvas runs never touch the active session
  • Live execution traces — reasoning stream, steps and progress, with an honest degradation ladder when reasoning is unavailable
  • Per-run undo — the project tree is snapshotted before each run; restores are strictly LIFO and survive restarts
  • 16 node types with typed ports, plus import from a folder or the /flow-import command

Install

dsh plugin --profile desktop add link:<absolute path to this checkout>

Restart DSH afterwards (the host half does not hot-reload), then refresh the page. Verify with curl -i http://127.0.0.1:<port>/codeflow/canvas — expect 200 and HTML.

Full changelog: 0083ffd


中文

English

首次公开发布:ZCode 插件 codeflow-canvas v0.2.2 的 DSH 迁移版。

画布编辑器沿用原实现;与宿主的接线(会话、工具协议、持久化、交付、撤销)全部为 DSH(DeepSeek Harness)重写。此版本已具备:

  • 双视图 —— 一次确定性导入同时产出任务流水线(workflow.json)与模块结构图(workflow.modules.json),工具栏随时切换
  • 修改高亮 —— 依据真实写文件工具调用(edit / write / apply_patch……),绝不从对话文本猜测
  • 左侧可搜索的二级模块导航
  • 原生交付 —— 通过 DSH 的 present 工具,并写 docs/DELIVERY.md
  • 每项目专用会话(CodeFlow · <项目>)—— 画布的运行不碰当前会话
  • 实时执行过程 —— 思考流、步骤与进度;拿不到 reasoning 时按降级阶梯如实说明
  • 按次撤销 —— 每次运行前快照项目源码树,严格 LIFO,重启后仍可用
  • 16 种节点、端口有类型;支持从文件夹导入或 /flow-import

安装

dsh plugin --profile desktop add link:<本目录的绝对路径>

装完重启 DSH(宿主半侧不参与热重载)并刷新页面。用 curl -i http://127.0.0.1:<端口>/codeflow/canvas 验证,应返回 200 与 HTML。

完整变更:0083ffd