@ch4acko3/dsh-turn-fold 0.5.2 → 0.6.0
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 +8 -6
- package/README.zh-CN.md +3 -3
- package/package.json +8 -3
- package/patch.cjs +103 -37
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
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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.2` line, 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` | `
|
|
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
|
|
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
|
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
|
|
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.2` 版本线则跟随渲染器迁移到 `@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` |
|
|
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`
|
|
40
|
+
`npm install` 会安装测试工具所需的依赖。测试套件会对两种受支持的编译形状分别在内存中应用三个 Patch、解析最终浏览器包,并覆盖已完成回合、分段活动、结束后活动、部分历史、失败、中断、进行中、无障碍、本地化、设置和状态保留等行为。目标缺失或选择器不匹配会使测试失败,不会被报告为跳过后通过。
|
|
41
41
|
|
|
42
42
|
## CI 与发布
|
|
43
43
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ch4acko3/dsh-turn-fold",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
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-
|
|
59
|
-
"@deepseek-ai/dsh-
|
|
58
|
+
"@deepseek-ai/dsh-client-ui-chat": ">=0.1.2-alpha.5 <0.1.3-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",
|
|
60
|
+
"@deepseek-ai/dsh-settings": ">=0.1.0-rc.8 <=0.1.1-rc.2 || >=0.1.2-alpha.5 <0.1.3-0",
|
|
60
61
|
"dsh-harmony": "^0.8.10"
|
|
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,6 +75,7 @@
|
|
|
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",
|
package/patch.cjs
CHANGED
|
@@ -1,37 +1,87 @@
|
|
|
1
|
-
// @ch4acko3/dsh-turn-fold — Harmony Source Patches for the DSH
|
|
1
|
+
// @ch4acko3/dsh-turn-fold — Harmony Source Patches for the DSH chat flow.
|
|
2
2
|
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
//
|
|
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 0.1.2 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
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
const LEGACY_RANGE = '>=0.1.0-rc.8 <=0.1.1-rc.2'
|
|
14
|
+
const DSH_012_RANGE = '>=0.1.2-alpha.5 <0.1.3-0'
|
|
15
|
+
|
|
16
|
+
function manifestVersion(filename) {
|
|
17
|
+
return JSON.parse(fs.readFileSync(filename, 'utf8')).version
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
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
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
select: '
|
|
51
|
-
expect: 1,
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function dsh012Patches() {
|
|
99
|
+
return commonPatches(target('@deepseek-ai/dsh-client-ui-chat', DSH_012_RANGE), {
|
|
100
|
+
select: 'CallExpression[arguments.0.name="ChatNodeList"]',
|
|
52
101
|
apply({ node, sourceFile, edit }) {
|
|
53
|
-
const
|
|
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
|
-
|
|
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_012_RANGE: { value: DSH_012_RANGE },
|
|
125
|
+
})
|
|
126
|
+
|
|
127
|
+
module.exports = patches
|