dsh-auto-collapse 0.1.6 → 0.1.8

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/lib/index.js CHANGED
@@ -1,24 +1,55 @@
1
1
  import z from "@deepseek-ai/schemastery";
2
- import { installSettingsSection, settingsNamespace } from "@deepseek-ai/dsh-settings";
3
2
  const name = "dsh-auto-collapse";
4
3
  const inject = [];
5
4
  const DEFAULT_STATUS_TEXT = "Deep sleeping...";
6
- const AUTO_COLLAPSE_SETTINGS_NAMESPACE = settingsNamespace("dsh-auto-collapse");
5
+ const AUTO_COLLAPSE_SETTINGS_NAMESPACE = "dsh-auto-collapse";
7
6
  const AUTO_COLLAPSE_SETTINGS_SCHEMA = z.object({
8
7
  statusText: z.string().default(DEFAULT_STATUS_TEXT)
9
8
  });
9
+ const FIBER_DISPOSED = 4;
10
+ const FIBER_UNLOADING = 5;
11
+ function isUnloading(ctx) {
12
+ const state = ctx?.fiber?.state;
13
+ return state === FIBER_UNLOADING || state === FIBER_DISPOSED;
14
+ }
15
+ function installSettingsSection(ctx, ns, schema, entry, hooks) {
16
+ ;
17
+ ctx.inject(["settings"], (sctx) => {
18
+ const scope = sctx.settings.register(ns, schema, {
19
+ base: entry,
20
+ ...hooks.validate === void 0 ? {} : { validate: hooks.validate }
21
+ });
22
+ hooks.setSource(() => scope.get());
23
+ sctx.effect(() => () => {
24
+ if (isUnloading(ctx)) return;
25
+ hooks.setSource(() => entry);
26
+ hooks.onChange();
27
+ });
28
+ hooks.onChange();
29
+ scope.watch(() => {
30
+ if (isUnloading(ctx)) return;
31
+ hooks.onChange();
32
+ });
33
+ });
34
+ }
10
35
  function apply(ctx, config = {}) {
11
36
  let current = () => ({ statusText: config.statusText ?? DEFAULT_STATUS_TEXT });
12
- installSettingsSection(ctx, AUTO_COLLAPSE_SETTINGS_NAMESPACE, AUTO_COLLAPSE_SETTINGS_SCHEMA, {
13
- statusText: config.statusText ?? DEFAULT_STATUS_TEXT
14
- }, {
15
- setSource: (source) => {
16
- current = source;
37
+ installSettingsSection(
38
+ ctx,
39
+ AUTO_COLLAPSE_SETTINGS_NAMESPACE,
40
+ AUTO_COLLAPSE_SETTINGS_SCHEMA,
41
+ {
42
+ statusText: config.statusText ?? DEFAULT_STATUS_TEXT
17
43
  },
18
- onChange: () => {
19
- void current;
44
+ {
45
+ setSource: (source) => {
46
+ current = source;
47
+ },
48
+ onChange: () => {
49
+ void current;
50
+ }
20
51
  }
21
- });
52
+ );
22
53
  }
23
54
  export {
24
55
  apply,
@@ -1,7 +1,8 @@
1
1
  export declare const name = "dsh-auto-collapse";
2
2
  /**
3
3
  * 不声明必需服务:slots/settingsScope 只是可选增强能力,不能阻止核心折叠
4
- * 插件启动。运行时通过 ctx.get() 读取,服务不存在时仅跳过设置卡片与配置订阅。
4
+ * 插件启动。下方通过 ctx.inject() 等待两个服务,支持晚于插件出现
5
+ * 以及卸载后重连;服务永久缺席时仅跳过设置卡片与配置订阅。
5
6
  */
6
7
  export declare const inject: string[];
7
8
  /** 客户端根上下文的最小结构化类型(仅用 cordis 标准 effect,无运行时依赖)。 */
@@ -9,5 +10,7 @@ export interface FoldClientCtx {
9
10
  effect(fn: () => unknown, label?: string): unknown;
10
11
  /** Cordis 动态客户端上下文提供的可选服务查询。 */
11
12
  get?<T>(name: string): T | undefined;
13
+ /** 可选服务生命周期:服务齐备时进入,detach 时自动清理回调上的 effect。 */
14
+ inject?(services: readonly string[], setup: (ctx: FoldClientCtx) => void): void;
12
15
  }
13
16
  export declare function apply(ctx: FoldClientCtx): void;
@@ -12,10 +12,11 @@
12
12
  * - 全部完成 → 标题 = 类型总结(编辑了文件 / 运行了命令 / 已思考 /
13
13
  * 上下文注入),摘要清空;出错 → 红色,中断 → 琥珀。
14
14
  *
15
- * 另外把官方 ChatView 尾部的运行状态行文字 "Deep diving..." 替换为
16
- * 可配置的状态提示词(默认 "Deep sleeping...";流光特效在 CSS 上,
17
- * 替换文本节点不影响)。React 重渲染会恢复原文,pass() 每轮自愈改回。
18
- * 设置为空时不替换,等价于恢复官方 "Deep diving..."。
15
+ * 另外把官方 ChatView 尾部的运行状态行文字(新版 "深度求索中..." / 旧版
16
+ * "Deep diving...",见 TURN_STATUS_COPY_RE)替换为可配置的状态提示词
17
+ * (默认 "Deep sleeping...";流光特效在 CSS 上,替换文本节点不影响,
18
+ * 宿主追加的用时后缀原样保留)。React 重渲染会恢复原文,pass() 每轮自愈改回。
19
+ * 设置为空时不替换,等价于恢复官方原文。
19
20
  *
20
21
  * 点击一行展开,再点收起;折叠态下若有行被选中(详情联动)自动展开。
21
22
  *
@@ -80,6 +81,7 @@ export declare class FoldController {
80
81
  private bodyTextCache;
81
82
  /** 自上次 pass 以来子树发生变化的 flow 顶层消息;pass 开头统一失效。 */
82
83
  private dirtyMessages;
84
+ /** 在途显示动画(元素 → 记录):冲突仲裁、记账对齐与生命周期清理的依据。
83
85
  /** 在途显示动画(元素 → 记录):冲突仲裁、记账对齐与生命周期清理的依据。
84
86
  * 用 Map 不用 WeakMap——switchFlow/stop 需要遍历全量 cancel。 */
85
87
  private pendingAnims;
@@ -98,6 +100,20 @@ export declare class FoldController {
98
100
  * attributes 批次(流式文本、data-state 翻转)不改变块结构,跳过全量
99
101
  * querySelectorAll 重扫(issue #14:长会话下每轮重扫造成主线程卡顿)。 */
100
102
  private structureDirty;
103
+ /** 本轮 pass 的原生 turn 摘要快照(turn id → 开合态):每轮重建,不跨轮复用;
104
+ * data-open 翻转不改变块结构也能驱动重算,见 buildNativeTurnMap。 */
105
+ private nativeTurns;
106
+ /** 被折叠掏空后藏起的中间包装层(真机 44px vs 28px 真因:think 行全隐后
107
+ * 其父容器变零高度空壳,仍作为 flex item 参与父级 gap,凭空多出 16px)。
108
+ * 内容恢复(展开/流式追加/块转世)时同函数恢复显示;switchFlow 清空。 */
109
+ private emptiedWrappers;
110
+ /** 本轮 pass 内有过 display 实写(hide/restore 瞬时路径)。空洞发现的触发
111
+ * 条件之一:纯 display 收放不产生 childList,不触发 structureDirty。
112
+ * settle 触发的后续 pass 则由 settleFired 覆盖。读后即清(见发现调用点)。 */
113
+ private displayTouched;
114
+ /** 有 fade 自然结算过(chipSettle 跑过)。结算本身不写 display,但它意味着
115
+ * 某行刚变隐藏——空洞可能刚形成。 */
116
+ private settleFired;
101
117
  /** 滚动稳定化(issue #14):flow 最近的滚动容器缓存(按 flow 身份失效)。 */
102
118
  private scrollContainer;
103
119
  private scrollContainerFlow;
@@ -165,7 +181,39 @@ export declare class FoldController {
165
181
  private createProcessedRow;
166
182
  private syncProcessedRow;
167
183
  private placeProcessedRow;
184
+ /** 原生收起时隐藏本块插件自有 overlay(chip/合并行+内容块):只做
185
+ * display 直写,不清钉住之外的账本、不删展开态,供原生再展开后复用。
186
+ * 在途 WAAPI 动画不追踪取消——收尾回调只做幂等终态对齐,无残留。 */
187
+ private hideOverlayForNativeCollapse;
168
188
  private reconcileBlock;
189
+ /**
190
+ * 掏空包装层对账(真机 44px vs 28px 真因修复)。
191
+ *
192
+ * 折叠把某容器的子行全部 display:none 后,该容器变零高度空壳,但仍是
193
+ * 父级 flex 的 item 并参与 gap(如正文体 flex-column gap:16px),凭空多出
194
+ * 一份间距。隐藏这类空壳可让 gap 塌缩;子内容恢复可见(展开/流式追加/
195
+ * 块转世)时恢复显示。
196
+ *
197
+ * 安全边界:
198
+ * - 只看 block.host 内部、不含 host 本人(宿主显隐归 segment 逻辑);
199
+ * - 跳过结构 seat(data-chat-flow-kind / data-chat-anchor-key)与插件
200
+ * 自身 overlay(dshcf- 前缀类);
201
+ * - 只隐藏内容空洞(无可见子内容):零高度无文本的空壳 display:none 与
202
+ * 保持显示像素一致,只塌缩父级 gap;任何一方恢复内容即恢复显示。
203
+ */
204
+ /**
205
+ * 空洞包装层兜底发现:按宿主直扫 div(仅结构变化轮次调用)。
206
+ * 只做隐藏侧:空洞即藏并记入 tracked;恢复侧由 syncEmptiedWrappers 的
207
+ * tracked 复核与 audit 承担。与按行 walk 共用同一安全边界(结构 seat /
208
+ * 插件 overlay / 宿主本人不碰)。
209
+ */
210
+ private discoverHollowWrappers;
211
+ private syncEmptiedWrappers;
212
+ /** 内容空洞判定:无可见子内容(文本/元素任一可见即非空洞)。隐藏者是谁
213
+ * 不重要——零高度无文本节点 display:none 与保持显示像素一致(只塌缩父级
214
+ * gap,正是要修的幻影);任何一方恢复内容,下轮 pass/audit 即恢复显示。
215
+ * isDisplayed 走 getComputedStyle(桩内退化为内联,语义一致)。 */
216
+ private isHollow;
169
217
  private ensureChip;
170
218
  private suppressBlock;
171
219
  private retainDisplayControl;
@@ -249,6 +297,17 @@ export declare class FoldController {
249
297
  * 淡完 onfinish 写 display:none 并保持双条目(镜像 hideElement 终态契约)。
250
298
  * fill:'forwards' 占位到终态写入后释放;无几何锁、无 gap 补偿。 */
251
299
  private startFadeCollapse;
300
+ /**
301
+ * 收起 fade 终态结算(onfinish 与僵尸收割共用)。仅被同元素新动画
302
+ * supersede 时早退;被 sweep 删账(元素已断连)或收割时仍执行 settle——
303
+ * 回调经 controller 可达,动画必然触发 onfinish,早退会把 chip 内联 16px
304
+ * 钉住永久残留。重挂载同节点不可能(React 只建新节点),重启动的新动画
305
+ * 由第一条守卫覆盖,无误伤。
306
+ */
307
+ private finishFadeCollapse;
308
+ /** 动画是否已播完(终态未结算):finish 事件丢失时的兜底判定。WAAPI 桩
309
+ * 无 playState/effect 时一律 false,走正常事件路径,测试行为不变。 */
310
+ private isAnimOverdue;
252
311
  /** 轻量视觉 reveal(opacity + 4px 微位移):用于插件全资元素的即时显示
253
312
  * 路径——chip(一级展开时出现)与 merged-think 行(二级展开时出现)。
254
313
  * 这些元素的 display 完全由插件直写、无 React 协调竞争,因此不入
@@ -1,11 +1,17 @@
1
1
  /** Host 插件名。 */
2
2
  export declare const name = "dsh-auto-collapse";
3
- /** Host 侧不注入额外服务;settings 是可选的运行能力,由 installSettingsSection 惰性接入。 */
3
+ /** Host 侧不注入额外服务;settings 是可选的运行能力,由下方接线惰性接入。 */
4
4
  export declare const inject: string[];
5
5
  /** 插件配置。 */
6
6
  export interface Config {
7
7
  /** 自定义状态提示词;留空恢复官方 "Deep diving..."。 */
8
8
  statusText?: string;
9
9
  }
10
+ /** settings 消费者钩子,与官方 SettingsSectionHooks 同形。 */
11
+ export interface SettingsSectionHooks<T> {
12
+ setSource(source: () => T): void;
13
+ onChange(): void;
14
+ validate?(value: T): void;
15
+ }
10
16
  /** Host 插件体:注册设置命名空间。 */
11
17
  export declare function apply(ctx: unknown, config?: Config): void;
package/package.json CHANGED
@@ -1,69 +1,68 @@
1
- {
2
- "name": "dsh-auto-collapse",
3
- "version": "0.1.6",
4
- "description": "DeepSeek Harness Web 客户端插件:把会话里的工具卡片与 Think 推理块折叠成一行,折叠态实时显示当前正在进行的工作(工具名 + 正在执行的命令/参数、或思考内容),运行中带流光动画;点击展开/收起。让界面只保留模型说的话。",
5
- "type": "module",
6
- "repository": {
7
- "type": "git",
8
- "url": "git+https://github.com/a179-sanae/dsh-auto-collapse.git"
9
- },
10
- "homepage": "https://github.com/a179-sanae/dsh-auto-collapse#readme",
11
- "bugs": {
12
- "url": "https://github.com/a179-sanae/dsh-auto-collapse/issues"
13
- },
14
- "main": "lib/index.js",
15
- "types": "lib/types/index.d.ts",
16
- "exports": {
17
- ".": {
18
- "types": "./lib/types/index.d.ts",
19
- "default": "./lib/index.js"
20
- },
21
- "./client": {
22
- "types": "./lib/types/client.d.ts",
23
- "default": "./lib/client.js"
24
- },
25
- "./package.json": "./package.json"
26
- },
27
- "dsh": {
28
- "bundle": {
29
- "patch": "./cordis.patch.yml"
30
- },
31
- "client": {
32
- "inject": [
33
- "@deepseek-ai/dsh-client-runtime",
34
- "@deepseek-ai/dsh-client-ui-settings"
35
- ],
36
- "platform": "web"
37
- }
38
- },
39
- "scripts": {
40
- "build": "node build.mjs",
41
- "deploy": "node deploy.mjs",
42
- "test": "node test/run-all.mjs",
43
- "typecheck": "tsc --noEmit --pretty false",
44
- "check": "npm run typecheck && npm test",
45
- "prepack": "node build.mjs"
46
- },
47
- "files": [
48
- "lib",
49
- "cordis.patch.yml"
50
- ],
51
- "keywords": [
52
- "dsh",
53
- "deepseek-harness",
54
- "client-plugin",
55
- "ui",
56
- "collapse",
57
- "auto-collapse",
58
- "chat"
59
- ],
60
- "license": "MIT",
61
- "devDependencies": {
62
- "esbuild": "0.25.0",
63
- "typescript": "5.9.3"
64
- },
65
- "peerDependencies": {
66
- "@deepseek-ai/dsh-settings": "^0.1.1-rc.2",
67
- "@deepseek-ai/schemastery": "^3.18.1"
68
- }
69
- }
1
+ {
2
+ "name": "dsh-auto-collapse",
3
+ "version": "0.1.8",
4
+ "description": "DeepSeek Harness Web 客户端插件:把会话里的工具卡片与 Think 推理块折叠成一行,折叠态实时显示当前正在进行的工作(工具名 + 正在执行的命令/参数、或思考内容),运行中带流光动画;点击展开/收起。让界面只保留模型说的话。",
5
+ "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/a179-sanae/dsh-auto-collapse.git"
9
+ },
10
+ "homepage": "https://github.com/a179-sanae/dsh-auto-collapse#readme",
11
+ "bugs": {
12
+ "url": "https://github.com/a179-sanae/dsh-auto-collapse/issues"
13
+ },
14
+ "main": "lib/index.js",
15
+ "types": "lib/types/index.d.ts",
16
+ "exports": {
17
+ ".": {
18
+ "types": "./lib/types/index.d.ts",
19
+ "default": "./lib/index.js"
20
+ },
21
+ "./client": {
22
+ "types": "./lib/types/client.d.ts",
23
+ "default": "./lib/client.js"
24
+ },
25
+ "./package.json": "./package.json"
26
+ },
27
+ "dsh": {
28
+ "bundle": {
29
+ "patch": "./cordis.patch.yml"
30
+ },
31
+ "client": {
32
+ "inject": [
33
+ "@deepseek-ai/dsh-client-modules",
34
+ "@deepseek-ai/dsh-client-ui-settings"
35
+ ],
36
+ "platform": "web"
37
+ }
38
+ },
39
+ "scripts": {
40
+ "build": "node build.mjs",
41
+ "deploy": "node deploy.mjs",
42
+ "test": "node test/run-all.mjs",
43
+ "typecheck": "tsc --noEmit --pretty false",
44
+ "check": "npm run typecheck && npm test",
45
+ "prepack": "node build.mjs"
46
+ },
47
+ "files": [
48
+ "lib",
49
+ "cordis.patch.yml"
50
+ ],
51
+ "keywords": [
52
+ "dsh",
53
+ "deepseek-harness",
54
+ "client-plugin",
55
+ "ui",
56
+ "collapse",
57
+ "auto-collapse",
58
+ "chat"
59
+ ],
60
+ "license": "MIT",
61
+ "devDependencies": {
62
+ "esbuild": "0.25.0",
63
+ "typescript": "5.9.3"
64
+ },
65
+ "peerDependencies": {
66
+ "@deepseek-ai/schemastery": "^3.18.1"
67
+ }
68
+ }