Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
d313e91
docs(interaction): document the exit sweep and correct the Ctrl+X des…
baobaolaodie Oct 8, 2026
d793249
chore(deps): add zod for the session-list projection schema
baobaolaodie Oct 8, 2026
983c167
feat(adapter): sweep never-spoken sessions on a normal exit
baobaolaodie Oct 8, 2026
90ee4ba
feat(adapter): mirror the session-list metadata projection
baobaolaodie Oct 8, 2026
0a9eb9c
feat(adapter): sweep never-spoken sessions on a clean exit
baobaolaodie Oct 8, 2026
e02fadb
test(ci): register the session-list metadata and sweep regressions
baobaolaodie Oct 8, 2026
1718a19
docs(interaction): drop the Ctrl+X correction and scope the sweep notice
baobaolaodie Oct 8, 2026
0f2f838
fix(adapter): register the projection wire and guard the sweep by hea…
baobaolaodie Oct 8, 2026
d20eb5b
test(adapter): make the exit-sweep regression self-verifying
baobaolaodie Oct 8, 2026
56a72b6
fix(adapter): register the session-list projection before the boot agent
baobaolaodie Oct 9, 2026
f323c69
merge: bring in origin/main (incl. #1395 deferred session persistence)
baobaolaodie Oct 9, 2026
32d9f75
test(adapter): drop stale plugin.ts line pins from the sweep regression
baobaolaodie Oct 9, 2026
0b5085a
test(adapter): describe the DATA_DIR constant instead of pinning its …
baobaolaodie Oct 9, 2026
efb63aa
fix(session): keep never-used fresh sessions out of JSONL despite cre…
baobaolaodie Oct 9, 2026
127d193
fix(session): do not seed a child from a never-used source session
baobaolaodie Oct 9, 2026
bccc7d8
fix(session): stop advertising a resume id for an unstored fork and w…
baobaolaodie Oct 9, 2026
dc9aebf
fix(session): judge the inherited cut, not the source session, for se…
baobaolaodie Oct 9, 2026
19512e9
docs(session): align two comments with the code and pin the gate-inst…
baobaolaodie Oct 9, 2026
7bb1d7b
test(session): label the new persistence probes for the fixed-window …
baobaolaodie Oct 9, 2026
819c47b
test(session): assert the unseeded child for a never-used source
baobaolaodie Oct 9, 2026
13f9cd1
refactor(session): keep the conversation criterion in one place
baobaolaodie Oct 9, 2026
565325d
docs(readme): state that an explicit flush no longer publishes an act…
baobaolaodie Oct 9, 2026
c081df1
fix(session): replay the cut's policy facts into an unseeded child
baobaolaodie Oct 9, 2026
4cfd0bc
fix(session): keep sessions another process write-leases
baobaolaodie Oct 9, 2026
1045d51
merge: bring in origin/main (08c8107a)
baobaolaodie Oct 10, 2026
041635a
fix(session): hold the policy plane back from the fresh-session gate
baobaolaodie Oct 10, 2026
c1e770d
merge: bring in origin/main (3961b3c9)
baobaolaodie Oct 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ Shortcuts sit below the title and effort levels have their own section; DSH, Cla
In `/provider`'s model list, focus a model and press `Tab` to edit its context window, max output tokens, reasoning efforts, and image input capability.

The session manager focuses the most recently used session in the current workspace; if there is no history, it focuses the new-session card. Press `←` to move to the workspace rail. It paints the last successful list immediately while it checks the persistence store for changes. This first-paint snapshot survives restarts on DSH, Claude and Codex and is isolated by backend and storage directory. On a cold Codex scan, pages appear as they arrive. Titles that require a deeper DSH log scan appear first with a fallback name and update in place when recovery finishes.
With DSH's current JSONL backend, startup and `/new` keep initial permission events in memory until further session activity or an explicit durability flush saves the complete log. Restarting an unstored empty session starts fresh.
With DSH's current JSONL backend, startup and `/new` keep initial permission events in memory until further session activity saves the complete log; an explicit durability flush still runs, but it saves nothing for a session that holds only that initialization. Restarting an unstored empty session starts fresh. A normal exit removes sessions no human ever spoke in.
Removing a workspace registration keeps its sessions accessible under a "History only" directory in the rail.
History-only directories offer edit and new-session actions; rename and remove are available for registered workspaces.

Expand Down
2 changes: 1 addition & 1 deletion README_ZH.md
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,7 @@ OpenAI 条款约束。完整操作与当前边界:[Codex 后端](docs/codex-ba
在 `/provider` 模型列表聚焦一项并按 `Tab`,可编辑上下文窗口、最大输出 token、推理档位和图片输入能力。

会话管理界面默认聚焦当前工作区最近使用的会话;没有历史时聚焦“新建会话”卡片,按 `←` 可移到工作区栏。界面会立即显示上次成功读取的列表,同时核对持久化存储的变化。DSH、Claude 和 Codex 的首屏快照都可跨重启复用,并按内核与存储目录隔离。Codex 首次扫描时,分页到达就显示;DSH 中需要深度扫描日志的标题会先显示回退名称,恢复完成后在原行更新。
使用 DSH 当前的 JSONL 后端时,启动与 `/new` 的初始权限事件只保留在内存中;后续会话活动或显式持久化 flush 才会保存完整日志。尚未落盘的空会话重启时会重新创建。
使用 DSH 当前的 JSONL 后端时,启动与 `/new` 的初始权限事件只保留在内存中,直到后续会话活动才会保存完整日志;显式持久化 flush 仍会照常执行,但不会为只有初始化的会话落盘。尚未落盘的空会话重启时会重新创建。正常退出会清理人类从未发言过的会话。
移除工作区登记后,其历史会话仍可从侧栏的「仅历史」目录进入。
「仅历史」目录只提供编辑和新建会话操作;重命名与移除仅适用于已登记工作区。

Expand Down
9 changes: 9 additions & 0 deletions docs/interaction.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,15 @@ those sessions as usual — "no registration" is not "no history".

- The group lives only inside this screen and is never written back to the registry.

On a normal exit (`/exit`, `/quit`, `/q`, a double `Ctrl+C` while idle, `Ctrl+D`), the TUI
removes sessions **no human has ever spoken in** — leftovers from earlier runs included —
and, when anything was cleaned, reports the count in its exit notice.

- Only that path sweeps: hand-offs (`/update`, kernel switch, `/restart`), crashes and
signal-driven exits leave sessions alone.
- A session with any human message (even if its turn never started) and any sub-agent are
**never removed**.

**Behaviour changes versus the old screens** (deliberately removed, and no longer covered by regressions):

- Session-level right-click menu (rename/delete one session).
Expand Down
5 changes: 5 additions & 0 deletions docs/interaction.md
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,11 @@ Bracketed paste(右键或终端原生粘贴)保留普通文本与换行。
- 这些会话照常列出并可恢复——"没有登记"不等于"没有历史"。
- 该分组只在本界面内存活,不会写回登记。

正常退出时(`/exit`、`/quit`、`/q`、空闲时连按两次 `Ctrl+C`、`Ctrl+D`),TUI 会清理**从未被人类发言**的会话(含历史遗留),并在有清理时于退出提示里报出数量。

- 只在正常退出这一条路径上清理:`/update`、内核切换、`/restart` 等交接,以及崩溃与信号退出都不清理。
- 有人类发言的会话(哪怕回合没起来)与子代理**永不删除**。

**旧界面相较之下的行为变更**(有意移除,不再回归):

- 会话级右键菜单(重命名/删除单个会话)。
Expand Down
9 changes: 9 additions & 0 deletions guide/dsh-tui-guide/interaction.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,15 @@ those sessions as usual — "no registration" is not "no history".

- The group lives only inside this screen and is never written back to the registry.

On a normal exit (`/exit`, `/quit`, `/q`, a double `Ctrl+C` while idle, `Ctrl+D`), the TUI
removes sessions **no human has ever spoken in** — leftovers from earlier runs included —
and, when anything was cleaned, reports the count in its exit notice.

- Only that path sweeps: hand-offs (`/update`, kernel switch, `/restart`), crashes and
signal-driven exits leave sessions alone.
- A session with any human message (even if its turn never started) and any sub-agent are
**never removed**.

**Behaviour changes versus the old screens** (deliberately removed, and no longer covered by regressions):

- Session-level right-click menu (rename/delete one session).
Expand Down
5 changes: 5 additions & 0 deletions guide/dsh-tui-guide/interaction.md
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,11 @@ Bracketed paste(右键或终端原生粘贴)保留普通文本与换行。
- 这些会话照常列出并可恢复——"没有登记"不等于"没有历史"。
- 该分组只在本界面内存活,不会写回登记。

正常退出时(`/exit`、`/quit`、`/q`、空闲时连按两次 `Ctrl+C`、`Ctrl+D`),TUI 会清理**从未被人类发言**的会话(含历史遗留),并在有清理时于退出提示里报出数量。

- 只在正常退出这一条路径上清理:`/update`、内核切换、`/restart` 等交接,以及崩溃与信号退出都不清理。
- 有人类发言的会话(哪怕回合没起来)与子代理**永不删除**。

**旧界面相较之下的行为变更**(有意移除,不再回归):

- 会话级右键菜单(重命名/删除单个会话)。
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,8 @@
"usehooks-ts": "^3.1.0",
"wrap-ansi": "^10.0.1",
"ws": "^8.21.3",
"yaml": "^2.9.0"
"yaml": "^2.9.0",
"zod": "^4.4.3"
},
"optionalDependencies": {
"sharp": "0.35.4"
Expand Down
3 changes: 3 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 39 additions & 0 deletions scripts/run-ci-group.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,15 @@ const GROUPS = {
// 字节、不得拉回 raw mode——在途回复与鼠标事件由清理后的 re-drain
// 吞掉,不再落入 shell。
["verify-exit-mouse-residue", ['node', '--import', 'tsx/esm', 'scripts/verify-exit-mouse-residue.tsx']],
// 正常退出分支的清理接线回归(ADR-0012 决策 3/5 · AC-5/AC-6):未发言
// 会话的 sweep 必须在回合结束后折进 finishExit 的通知(await 的 sweep
// 永远到不了那里),崩溃 / `/update` / 内核切换 / `/restart` / 启动失败
// 分支一律不 sweep;恶意依赖只损失回合不损失关机(终端恢复序列与进程
// 交接原位、fail-soft);③ 层吃本进程真实视图(绑定会话、注册表活
// agent、清单血缘),有人类消息无 turn/start 的会话存活,非本进程产出
// 的清单整份放过而不猜血缘。清退分支是 apply() 内的闭包,其接线按源码
// 断言(与 verify-shutdown-fallback 同形),被调用的 helper 直接驱动。
["verify-session-cleanup-exit", ['node', '--import', 'tsx/esm', 'scripts/verify-session-cleanup-exit.tsx']],
// 组件级拖拽协议回归:无修饰左键 press 捕获 drag target,首动 dragstart、
// 连续 dragmove、release/focus-out/reset 收尾 dragend;未移动仍走 click,
// 无 handler 与修饰键区域保留基线文本选择;真实 SGR 管线 + 最小滑块消费者。
Expand Down Expand Up @@ -635,9 +644,39 @@ const GROUPS = {
["verify-session-artifact-cache", ['node', 'scripts/verify-session-artifact-cache.mjs']],
// 跨进程首屏快照:不等慢枚举、来源隔离、失败保留、空库清空与迟到守卫。
["verify-session-list-snapshot", ['node', 'scripts/verify-session-list-snapshot.mjs']],
// 会话清单投影镜像回归(issue #1342 的可见性面):TUI 必须注册与 web 宿主
// **同名同版本**的 sessionListMetadata 投影——定义(键/stateVersion/字段
// 类型/init)逐项对字面量钉死(宿主侧改动要让本脚本红、而不是静默重开
// issue),legacy 拼写 schema/viewSchema/view 必须缺席;fold 矩阵含两条
// 只看值看不到的性质(无变化事件返回同一引用、blank 不回落);
// 跨运行时读取按对方等价形状解析并驱动真实 registry 的 restore;同键双
// 注册的版本判定(首个定义生效、行仍写入);服务缺失/无 register/版本
// 冲突必须降级不崩;宿主包可定位时跑真实实现的漂移探针,定位不到则响亮
// SKIP(含搜索路径与原因),绝不静默通过。
["verify-session-list-metadata", ['node', '--import', 'tsx/esm', 'scripts/verify-session-list-metadata.ts']],
// 空会话须完整读取后才能判定:截断/损坏、帧数上限、纯图片输入与旧缓存
// 不得隐藏真实历史或进入清理名单;真实 JSONL 重开验证落盘后的可见性。
['verify-session-emptiness', ['node', '--import', 'tsx/esm', 'scripts/verify-session-emptiness.ts']],
// 未发言会话清理回归(ADR-0012 / 三层判据):真实临时 sessions 根 + 真 TUI
// 会话索引,走的是出货实现(store.readIndex、sessionLog 的有界读与删除原语、
// sessionHistory 的每会话记录)而不是替身——启动壳(含本次运行之前就存在的
// 「历史」条目)被回收,人类 user/message 无 turn/start 必须保留(宿主自身
// blank 规则会删的反例),turn/start 与受委托运行及其后代保留,本进程仍持有
// 的会话(绑定 / 活后台)保留,缺失/悬空/损坏/预算截断的日志只跳过不删并
// 报出是哪层放过的;对抗用例「索引说 hasPrompt:false 而日志有人类消息」;
// 恒删/恒留/抽掉日志规则的负控(正例不能被常量满足);候选上限与每日志事件
// 预算、依赖抛错不中止本轮(fail-soft);分区恰好覆盖索引一次(不静默丢),
// 真 sweep 只删收集到的 id、索引不动、last-used/agent-view/resume 记录被遗忘。
["verify-unspoken-session-sweep", ['node', '--import', 'tsx/esm', 'scripts/verify-unspoken-session-sweep.tsx']],
// 会话写租约回归(CR-2 / T-FIX-18):真实 JSONL 持久化后端在临时 sessions 根上为
// 夹具会话持有独占写租约(Windows 命名内核信号量 / POSIX flock),验证退出清扫
// 「探不到就不删」——① 被别的写者持有的空壳保留、记为 write-leased(与挂载账本的
// held-elsewhere 可区分)、日志仍在盘上;② 同一形态但无人持有照旧删除;③ 探针不可用
// (平台不支持 / 非争用失败)保留;④ 恒返回 free 的探针必须让 ① 变红(锁着的会话
// 被删)——「完全不看租约」正是修复前那个世界。另覆盖探针失败分类(无服务 / 无方法 /
// 释放失败 ⇒ unknown)、预扫描的预算与顺序、索引不可读则一无所证,以及退出接线的锚:
// 先取证 → 再本轮 → 最后组通知。
["verify-session-write-lease", ['node', '--import', 'tsx/esm', 'scripts/verify-session-write-lease.ts']],
// /resume 会话浏览器按键流回归:子运行折叠/展开、空会话不列出、搜索、
// Esc 先清查询再退出、rename 后光标按 id 跟随目标(不是按行号)、
// confirm-delete 只认无修饰 Enter、Esc 取消。真实 Chat 渲染驱动。
Expand Down
Loading
Loading