@ch4acko3/dsh-turn-fold 0.5.2 → 0.6.1

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/README.md CHANGED
@@ -35,15 +35,17 @@ short open/close transition that unmounts the activity after it closes.
35
35
  ## How it works
36
36
 
37
37
  Three shape-guarded Source Patches run in memory against the compiled browser
38
- bundle of `@deepseek-ai/dsh-client-ui-conversation` (`lib/client.js`) from
39
- `0.1.0-rc.8` through `0.1.1-rc.2`; installed DSH files are never modified.
40
- Every selector must still match exactly once, so an incompatible compiled shape
41
- fails closed instead of modifying an uncertain target.
38
+ bundle. For DSH `0.1.0-rc.8` through `0.1.1-rc.2`, they target
39
+ `@deepseek-ai/dsh-client-ui-conversation`; for DSH `0.1.2-alpha.5` through the
40
+ `0.1.6` line (including prereleases), they follow the renderer into `@deepseek-ai/dsh-client-ui-chat`.
41
+ Installed DSH files are never modified. Every selector must still match exactly
42
+ once, so an incompatible compiled shape fails closed instead of modifying an
43
+ uncertain target.
42
44
 
43
45
  | Patch | Selector (expect 1) | Effect |
44
46
  | --- | --- | --- |
45
47
  | `inject-turn-fold-runtime` | `FunctionDeclaration[name.name="ChatView"], VariableStatement:has(VariableDeclaration[name.name="ChatView"])` | Injects the fold renderer + disclosure UI into either native or decorated `ChatView` |
46
- | `rewrite-node-render-loop` | `CallExpression[expression.name.name="map"][expression.expression.name="order"]` | Replaces the `order.map(...)` node loop with the per-turn renderer |
48
+ | `rewrite-node-render-loop` | legacy `order.map(...)` / 0.1.2 `ChatNodeList` call | Replaces the version-specific native node-list seam with the per-turn renderer |
47
49
  | `install-turn-fold-services` | `VariableStatement:has(VariableDeclaration[name.name="t"][initializer.expression.name.name="bind"])` | Registers the bundled English and Chinese dictionaries through DSH's native locale service and binds the native settings scope |
48
50
 
49
51
  ## Install
@@ -60,7 +62,7 @@ node test/run.cjs
60
62
  ```
61
63
 
62
64
  `npm install` installs the dependencies required by the test harness. The test
63
- suite applies all three patches in memory, parses the final browser bundle, and
65
+ suite applies all three patches to both supported compiled shapes in memory, parses the final browser bundles, and
64
66
  covers completed, split-activity, post-closing, partial-history, failed,
65
67
  interrupted, open, accessibility, localization, settings, and state-retention
66
68
  behavior. A missing target or selector mismatch fails the test; it is never
@@ -87,3 +89,5 @@ Then create and push a version tag whose value matches `package.json`:
87
89
  npm version patch
88
90
  git push --follow-tags
89
91
  ```
92
+
93
+ Compatibility checks cover the real `0.1.5-rc.2` and `0.1.6-alpha.2` bundles. Run `npm test` with `DSH_TURN_FOLD_UPSTREAM_ROOT` pointing to an isolated DSH installation to exercise that chat bundle. Exact selector counts remain required.
package/README.zh-CN.md CHANGED
@@ -16,12 +16,12 @@ https://github.com/user-attachments/assets/3c9dfdcf-a454-4750-9edf-76771ed5a9a6
16
16
 
17
17
  ## 工作原理
18
18
 
19
- 三个带形状校验的 Source Patch 会在内存中修改 `@deepseek-ai/dsh-client-ui-conversation` 从 DSH `0.1.0-rc.8` 至 `0.1.1-rc.2` 的编译后浏览器包(`lib/client.js`),不会修改已安装的 DSH 文件。每条选择器仍必须恰好命中一次,因此遇到不兼容的编译形状时会停止应用,而不会修改不确定的目标。
19
+ 三个带形状校验的 Source Patch 会在内存中修改编译后的浏览器包:DSH `0.1.0-rc.8` 至 `0.1.1-rc.2` 使用 `@deepseek-ai/dsh-client-ui-conversation`,DSH `0.1.2-alpha.5` 至 `0.1.6` 版本线(含预发布版)则跟随渲染器迁移到 `@deepseek-ai/dsh-client-ui-chat`。它们不会修改已安装的 DSH 文件。每条选择器仍必须恰好命中一次,因此遇到不兼容的编译形状时会停止应用,而不会修改不确定的目标。
20
20
 
21
21
  | Patch | 选择器(预期命中 1 次) | 作用 |
22
22
  | --- | --- | --- |
23
23
  | `inject-turn-fold-runtime` | `FunctionDeclaration[name.name="ChatView"], VariableStatement:has(VariableDeclaration[name.name="ChatView"])` | 向原生或已装饰的 `ChatView` 注入折叠渲染器和折叠 UI |
24
- | `rewrite-node-render-loop` | `CallExpression[expression.name.name="map"][expression.expression.name="order"]` | 将 `order.map(...)` 节点循环替换为按回合渲染器 |
24
+ | `rewrite-node-render-loop` | 旧版 `order.map(...)` / 0.1.2 `ChatNodeList` 调用 | 将对应版本的原生节点列表接缝替换为按回合渲染器 |
25
25
  | `install-turn-fold-services` | `VariableStatement:has(VariableDeclaration[name.name="t"][initializer.expression.name.name="bind"])` | 通过 DSH 原生语言服务注册内置的中英文词典,并绑定原生设置作用域 |
26
26
 
27
27
  ## 安装
@@ -37,7 +37,7 @@ dsh harmony status --profile web # 三个 Patch 都必须为 `bound`
37
37
  node test/run.cjs
38
38
  ```
39
39
 
40
- `npm install` 会安装测试工具所需的依赖。测试套件会在内存中应用三个 Patch、解析最终浏览器包,并覆盖已完成回合、分段活动、结束后活动、部分历史、失败、中断、进行中、无障碍、本地化、设置和状态保留等行为。目标缺失或选择器不匹配会使测试失败,不会被报告为跳过后通过。
40
+ `npm install` 会安装测试工具所需的依赖。测试套件会对两种受支持的编译形状分别在内存中应用三个 Patch、解析最终浏览器包,并覆盖已完成回合、分段活动、结束后活动、部分历史、失败、中断、进行中、无障碍、本地化、设置和状态保留等行为。目标缺失或选择器不匹配会使测试失败,不会被报告为跳过后通过。
41
41
 
42
42
  ## CI 与发布
43
43
 
@@ -60,3 +60,5 @@ npx npm@^11.15.0 trust github @ch4acko3/dsh-turn-fold \
60
60
  npm version patch
61
61
  git push --follow-tags
62
62
  ```
63
+
64
+ 已使用真实 `0.1.5-rc.2` 和 `0.1.6-alpha.2` 包验证。设置 `DSH_TURN_FOLD_UPSTREAM_ROOT` 指向隔离的 DSH 安装后运行 `npm test`,可对该版本的聊天包执行测试。选择器仍要求精确命中。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ch4acko3/dsh-turn-fold",
3
- "version": "0.5.2",
3
+ "version": "0.6.1",
4
4
  "description": "Codex-style turn folding for the DSH WebUI conversation, implemented as a dsh-harmony provider.",
5
5
  "main": "./index.cjs",
6
6
  "engines": {
@@ -55,11 +55,15 @@
55
55
  "@deepseek-ai/schemastery": "^3.18.1"
56
56
  },
57
57
  "peerDependencies": {
58
- "@deepseek-ai/dsh-client-ui-conversation": ">=0.1.0-rc.8 <=0.1.1-rc.2",
59
- "@deepseek-ai/dsh-settings": ">=0.1.0-rc.8 <=0.1.1-rc.2",
60
- "dsh-harmony": "^0.8.10"
58
+ "@deepseek-ai/dsh-client-ui-chat": ">=0.1.2-alpha.5 <0.1.3-0 || >=0.1.3-0 <0.1.4-0 || >=0.1.4-0 <0.1.5-0 || >=0.1.5-0 <0.1.6-0 || >=0.1.6-0 <0.1.7-0",
59
+ "@deepseek-ai/dsh-client-ui-conversation": ">=0.1.0-rc.8 <=0.1.1-rc.2 || >=0.1.2-alpha.5 <0.1.3-0 || >=0.1.3-0 <0.1.4-0 || >=0.1.4-0 <0.1.5-0 || >=0.1.5-0 <0.1.6-0 || >=0.1.6-0 <0.1.7-0",
60
+ "@deepseek-ai/dsh-settings": ">=0.1.0-rc.8 <=0.1.1-rc.2 || >=0.1.2-alpha.5 <0.1.3-0 || >=0.1.3-0 <0.1.4-0 || >=0.1.4-0 <0.1.5-0 || >=0.1.5-0 <0.1.6-0 || >=0.1.6-0 <0.1.7-0",
61
+ "dsh-harmony": "^0.8.11"
61
62
  },
62
63
  "peerDependenciesMeta": {
64
+ "@deepseek-ai/dsh-client-ui-chat": {
65
+ "optional": true
66
+ },
63
67
  "@deepseek-ai/dsh-client-ui-conversation": {
64
68
  "optional": true
65
69
  },
@@ -71,10 +75,11 @@
71
75
  }
72
76
  },
73
77
  "devDependencies": {
78
+ "@deepseek-ai/dsh-client-ui-chat": "0.1.2-alpha.5",
74
79
  "@deepseek-ai/dsh-client-ui-conversation": "0.1.1-rc.2",
75
80
  "@deepseek-ai/dsh-settings": "0.1.1-rc.2",
76
81
  "@phenomnomnominal/tsquery": "^6.2.0",
77
- "dsh-harmony": "^0.8.10",
82
+ "dsh-harmony": "^0.8.11",
78
83
  "react": "18.3.1",
79
84
  "react-test-renderer": "18.3.1",
80
85
  "semver": "^7.8.5",
package/patch.cjs CHANGED
@@ -1,37 +1,87 @@
1
- // @ch4acko3/dsh-turn-fold — Harmony Source Patches for the DSH conversation chat flow.
1
+ // @ch4acko3/dsh-turn-fold — Harmony Source Patches for the DSH chat flow.
2
2
  //
3
- // These three patches run in order, in memory only, against the compiled browser
4
- // bundle of @deepseek-ai/dsh-client-ui-conversation (lib/client.js). They never
5
- // modify the installed package.
6
- //
7
- // All three selectors use an exact `expect: 1` inside a bounded target-version
8
- // range, so a compiled-shape drift still fails loudly in `dsh harmony status`.
3
+ // DSH 0.1.2 split the visual chat renderer out of ui-conversation and into
4
+ // ui-chat. Keep the old compiled shape bounded through 0.1.1-rc.2, then select
5
+ // the new target and render seam for the modern chat line.
9
6
 
7
+ const fs = require('node:fs')
8
+ const path = require('node:path')
9
+ const { createRequire, findPackageJSON } = require('node:module')
10
+ const { pathToFileURL } = require('node:url')
10
11
  const INLINE = require('./inline-source.cjs')
11
12
 
12
- const TARGET = {
13
- package: '@deepseek-ai/dsh-client-ui-conversation',
14
- version: '>=0.1.0-rc.8 <=0.1.1-rc.2',
15
- file: 'lib/client.js',
13
+ const LEGACY_RANGE = '>=0.1.0-rc.8 <=0.1.1-rc.2'
14
+ const DSH_MODERN_RANGE = '>=0.1.2-alpha.5 <0.1.7-0'
15
+
16
+ function manifestVersion(filename) {
17
+ return JSON.parse(fs.readFileSync(filename, 'utf8')).version
16
18
  }
17
19
 
18
- module.exports = [
19
- {
20
- id: 'inject-turn-fold-runtime',
21
- description: 'Provides the Turn Fold rendering, disclosure, metrics, settings, and locale runtime used by ChatView.',
22
- target: TARGET,
23
- select: 'FunctionDeclaration[name.name="ChatView"], VariableStatement:has(VariableDeclaration[name.name="ChatView"])',
24
- expect: 1,
25
- apply({ node, sourceFile, edit }) {
26
- edit.prependLeft(node.getStart(sourceFile), INLINE + '\n\n')
20
+ function activeDshVersion() {
21
+ const entry = process.env.DSH_HARMONY_ACTIVE_DSH_ENTRY ?? process.env.DSH_HARMONY_DSH_ENTRY
22
+ if (entry !== undefined && typeof findPackageJSON === 'function') {
23
+ const manifest = findPackageJSON('@deepseek-ai/dsh', pathToFileURL(path.resolve(entry)))
24
+ if (manifest !== undefined) return manifestVersion(manifest)
25
+ }
26
+
27
+ const localRequire = createRequire(__filename)
28
+ try {
29
+ return manifestVersion(localRequire.resolve('@deepseek-ai/dsh/package.json'))
30
+ } catch {}
31
+ try {
32
+ return manifestVersion(localRequire.resolve('@deepseek-ai/dsh-client-ui-conversation/package.json'))
33
+ } catch {}
34
+ throw new Error('@ch4acko3/dsh-turn-fold: cannot determine the active DSH version')
35
+ }
36
+
37
+ function usesUiChat(version) {
38
+ const match = /^(\d+)\.(\d+)\.(\d+)/.exec(version)
39
+ if (match === null) throw new Error(`@ch4acko3/dsh-turn-fold: invalid DSH version ${JSON.stringify(version)}`)
40
+ const [major, minor, patch] = match.slice(1).map(Number)
41
+ return major > 0 || minor > 1 || (minor === 1 && patch >= 2)
42
+ }
43
+
44
+ function target(packageName, version) {
45
+ return { package: packageName, version, file: 'lib/client.js' }
46
+ }
47
+
48
+ function commonPatches(targetSpec, rewrite) {
49
+ return [
50
+ {
51
+ id: 'inject-turn-fold-runtime',
52
+ description: 'Provides the Turn Fold rendering, disclosure, metrics, settings, and locale runtime used by ChatView.',
53
+ target: targetSpec,
54
+ select: 'FunctionDeclaration[name.name="ChatView"], VariableStatement:has(VariableDeclaration[name.name="ChatView"])',
55
+ expect: 1,
56
+ apply({ node, sourceFile, edit }) {
57
+ edit.prependLeft(node.getStart(sourceFile), INLINE + '\n\n')
58
+ },
59
+ },
60
+ {
61
+ id: 'rewrite-node-render-loop',
62
+ description: 'Routes ChatView node rendering through Turn Fold while preserving the native node renderer.',
63
+ target: targetSpec,
64
+ select: rewrite.select,
65
+ expect: 1,
66
+ apply: rewrite.apply,
27
67
  },
28
- },
29
- {
30
- id: 'rewrite-node-render-loop',
31
- description: 'Routes ChatView node rendering through Turn Fold while preserving the native node renderer.',
32
- target: TARGET,
68
+ {
69
+ id: 'install-turn-fold-services',
70
+ description: 'Registers Turn Fold locales and connects its settings when the chat UI starts.',
71
+ target: targetSpec,
72
+ select: 'VariableStatement:has(VariableDeclaration[name.name="t"][initializer.expression.name.name="bind"])',
73
+ expect: 1,
74
+ apply({ node, sourceFile, edit }) {
75
+ const statement = sourceFile.text.slice(node.getStart(sourceFile), node.getEnd())
76
+ edit.overwrite(node.getStart(sourceFile), node.getEnd(), `${statement}\n\t\t\t__ch4acko3DshTurnFoldInstall(ctx);`)
77
+ },
78
+ },
79
+ ]
80
+ }
81
+
82
+ function legacyPatches() {
83
+ return commonPatches(target('@deepseek-ai/dsh-client-ui-conversation', LEGACY_RANGE), {
33
84
  select: 'CallExpression[expression.name.name="map"][expression.expression.name="order"]',
34
- expect: 1,
35
85
  apply({ node, sourceFile, edit }) {
36
86
  const callback = node.arguments[0]
37
87
  if (callback === undefined) throw new Error('@ch4acko3/dsh-turn-fold: order.map callback is missing')
@@ -42,20 +92,36 @@ module.exports = [
42
92
  `__ch4acko3DshTurnFoldRender({ order, nodeStore, timeline, sessionId, renderNode: ${renderNode}, t })`
43
93
  )
44
94
  },
45
- },
46
- {
47
- id: 'install-turn-fold-services',
48
- description: 'Registers Turn Fold locales and connects its settings when the conversation UI starts.',
49
- target: TARGET,
50
- select: 'VariableStatement:has(VariableDeclaration[name.name="t"][initializer.expression.name.name="bind"])',
51
- expect: 1,
95
+ })
96
+ }
97
+
98
+ function dsh012Patches() {
99
+ return commonPatches(target('@deepseek-ai/dsh-client-ui-chat', DSH_MODERN_RANGE), {
100
+ select: 'CallExpression[arguments.0.name="ChatNodeList"]',
52
101
  apply({ node, sourceFile, edit }) {
53
- const statement = sourceFile.text.slice(node.getStart(sourceFile), node.getEnd())
102
+ const props = node.arguments[1]
103
+ if (props === undefined) throw new Error('@ch4acko3/dsh-turn-fold: ChatNodeList props are missing')
104
+ const jsx = sourceFile.text.slice(node.expression.getStart(sourceFile), node.expression.getEnd())
105
+ const nativeProps = sourceFile.text.slice(props.getStart(sourceFile), props.getEnd())
54
106
  edit.overwrite(
55
107
  node.getStart(sourceFile),
56
108
  node.getEnd(),
57
- `${statement}\n\t\t\t__ch4acko3DshTurnFoldInstall(ctx);`
109
+ `__ch4acko3DshTurnFoldRender({ order, nodeStore, timeline, sessionId, renderNode: (nodeKey) => ${jsx}(ChatNodeSeat, { ...(${nativeProps}), nodeKey }, nodeKey), t })`
58
110
  )
59
111
  },
60
- },
61
- ]
112
+ })
113
+ }
114
+
115
+ function createPatches(version) {
116
+ return usesUiChat(version) ? dsh012Patches() : legacyPatches()
117
+ }
118
+
119
+ const patches = createPatches(activeDshVersion())
120
+ Object.defineProperties(patches, {
121
+ createPatches: { value: createPatches },
122
+ activeDshVersion: { value: activeDshVersion },
123
+ LEGACY_RANGE: { value: LEGACY_RANGE },
124
+ DSH_MODERN_RANGE: { value: DSH_MODERN_RANGE },
125
+ })
126
+
127
+ module.exports = patches