dsh-plugin-workbench 0.0.14 → 0.0.16
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/CHANGELOG.md +23 -0
- package/README.en.md +19 -5
- package/README.md +18 -5
- package/package.json +1 -1
- package/scripts/layout-anchors.desktop-ci.json +6 -0
- package/scripts/patch-layout.mjs +64 -28
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.0.16] - 2026-09-04
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **适配 dsh 0.1.2-rc.1 布局 bundle**:两处补丁锚点失配导致插件启动时自动重打失败
|
|
8
|
+
(启动日志 `ui-layout patch exited 1`,explorer 布局不生效)。⑴ `css.explorerCol.rule`:
|
|
9
|
+
detailsCol 边框样式 `border-left:1px solid var(--dsw-alias-border-l2)` 在新版改为
|
|
10
|
+
`.5px solid var(--dsw-alias-border-l3)`,锚点与注入规则同步更新;⑵
|
|
11
|
+
`appframe.explorerColumn`:DetailsColumn 的 children 在新版被 `SessionProvider`
|
|
12
|
+
包裹,锚点按新结构更新。其余 22 个锚点与 `computeColumns` 函数体逐字节未变。
|
|
13
|
+
# Changelog
|
|
14
|
+
|
|
15
|
+
## [0.0.15] - 2026-08-29
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- **DSH Desktop 下文件树列不显示([issue #1](https://github.com/Pasumao/dsh-plugin-workbench/issues/1))**:
|
|
20
|
+
布局补丁的锚点按 npm 构建的编译产物逐字节写死,而 DSH Desktop 安装包内置的
|
|
21
|
+
`dsh-client-ui-layout` 是同一版本的另一构建产物(保留注释、缩进不同、折叠侧栏宽度用
|
|
22
|
+
`COLLAPSED_SIDEBAR_WIDTH` 常量),`computeColumns` 锚点失配导致补丁每次启动整体放弃——
|
|
23
|
+
插件加载正常但界面永远不出现。补丁脚本现按目标文件自动探测构建变体(npm / desktop-ci,
|
|
24
|
+
后者锚点存于 `scripts/layout-anchors.desktop-ci.json`),两种产物都能正确打补丁。
|
|
25
|
+
|
|
3
26
|
## [0.0.14] - 2026-08-29
|
|
4
27
|
|
|
5
28
|
- 文档:对标生态头部插件优化 README(首屏新增「装完你会看到」;布局补丁话术改为开箱即用);
|
package/README.en.md
CHANGED
|
@@ -16,6 +16,8 @@ Once installed, the DSH web GUI becomes a lightweight code editor.
|
|
|
16
16
|
> ✅ **Works out of the box**: since 0.0.9 the layout patch is fully automated — it takes effect right after install and
|
|
17
17
|
> restart; if a DSH upgrade overwrites the bundle, the plugin patches it back automatically, with no manual steps
|
|
18
18
|
> required (manual action is only needed if the anchors break, see the "Configuration" section).
|
|
19
|
+
> Since 0.0.15 both build flavors — the npm build and the DSH Desktop bundled build — are detected automatically, so
|
|
20
|
+
> **DSH Desktop works out of the box** too.
|
|
19
21
|
|
|
20
22
|
What you'll see after installing:
|
|
21
23
|
|
|
@@ -81,8 +83,9 @@ What you'll see after installing:
|
|
|
81
83
|
## Configuration
|
|
82
84
|
|
|
83
85
|
No environment variables or config files needed; the layout patch is fully automated (the plugin automatically detects
|
|
84
|
-
and re-runs `scripts/patch-layout.mjs` at startup — idempotent, non-blocking;
|
|
85
|
-
|
|
86
|
+
and re-runs `scripts/patch-layout.mjs` at startup — idempotent, non-blocking; since 0.0.15 both build flavors of the
|
|
87
|
+
same version are detected automatically — the npm build and the DSH Desktop bundled build; anchors are byte-coupled to
|
|
88
|
+
the compiled output, so a DSH upgrade that breaks them requires anchor updates):
|
|
86
89
|
- **Behavior preferences** (word wrap, light/dark theme, tab layout, file tree expansion state) persist per workspace
|
|
87
90
|
and need no manual configuration;
|
|
88
91
|
- **File operation channel**: via the loopback RPC `/dsh-plugin-files`; write operations are executed explicitly under
|
|
@@ -90,9 +93,9 @@ and re-runs `scripts/patch-layout.mjs` at startup — idempotent, non-blocking;
|
|
|
90
93
|
|
|
91
94
|
## Installation
|
|
92
95
|
|
|
93
|
-
>
|
|
94
|
-
> Since 0.0.
|
|
95
|
-
> for details).
|
|
96
|
+
> Layout-patch anchors are byte-coupled to the DSH compiled output; a DSH upgrade that breaks them requires anchor
|
|
97
|
+
> updates. Since 0.0.15 both build flavors (npm / DSH Desktop) are detected automatically and the patch re-applies at
|
|
98
|
+
> startup (see the "Configuration" section for details).
|
|
96
99
|
|
|
97
100
|
```powershell
|
|
98
101
|
# npm (recommended)
|
|
@@ -146,6 +149,8 @@ dsh plugin --profile web remove dsh-plugin-workbench
|
|
|
146
149
|
bytes, with a 20MB limit
|
|
147
150
|
- DSH upgrades overwrite the layout bundle; since 0.0.9 the plugin detects and re-applies the patch automatically at
|
|
148
151
|
startup, so there is no need to re-run it manually; if the anchors break, `scripts/patch-layout.mjs` must be updated
|
|
152
|
+
(since 0.0.15 the anchor table carries two build variants auto-detected per target — npm and desktop-ci, the latter
|
|
153
|
+
stored in `scripts/layout-anchors.desktop-ci.json`)
|
|
149
154
|
- This repository does not include DSH build artifacts
|
|
150
155
|
|
|
151
156
|
## Contributing
|
|
@@ -153,6 +158,15 @@ dsh plugin --profile web remove dsh-plugin-workbench
|
|
|
153
158
|
See [CONTRIBUTING](./CONTRIBUTING.md) and [CODE_OF_CONDUCT](./CODE_OF_CONDUCT.md); the changelog is in
|
|
154
159
|
[CHANGELOG](./CHANGELOG.md).
|
|
155
160
|
|
|
161
|
+
## Compatibility
|
|
162
|
+
|
|
163
|
+
- Tested on DSH `0.1.2-rc.1` (since 0.0.16 the layout patch anchors are adapted to that
|
|
164
|
+
version: the detailsCol border style changed from `1px/--dsw-alias-border-l2` to
|
|
165
|
+
`.5px/--dsw-alias-border-l3`, and the DetailsColumn children gained a `SessionProvider`
|
|
166
|
+
wrapper); for 0.1.1-rc.2 and earlier, use the 0.0.15 anchor table.
|
|
167
|
+
- Since 0.0.9 the plugin re-applies the layout patch automatically at startup, so DSH
|
|
168
|
+
upgrades normally need no manual action; on anchor mismatch the startup log shows
|
|
169
|
+
`ui-layout patch exited 1` — upgrading this plugin fixes it.
|
|
156
170
|
## Related plugins
|
|
157
171
|
|
|
158
172
|
This plugin is part of **Pasumao's dsh plugin ecosystem**; the published plugins in the same series can be used
|
package/README.md
CHANGED
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
> ✅ **开箱即用**:0.0.9 起布局补丁全自动——装完重启即生效;DSH 升级覆盖 bundle
|
|
17
17
|
> 后插件会自动补回,无需任何手动操作(仅锚点失效时才需手动,见「配置」节)。
|
|
18
|
+
> 0.0.15 起自动识别 npm 与 DSH Desktop 两种构建产物,**DSH Desktop 开箱即用**。
|
|
18
19
|
|
|
19
20
|
装完你会看到:
|
|
20
21
|
|
|
@@ -73,15 +74,17 @@
|
|
|
73
74
|
## 配置
|
|
74
75
|
|
|
75
76
|
无需环境变量或配置文件;布局补丁全自动(插件启动时自动检测并重跑
|
|
76
|
-
`scripts/patch-layout.mjs
|
|
77
|
-
|
|
77
|
+
`scripts/patch-layout.mjs`,幂等、非阻塞;0.0.15 起自动识别同一版本的两种构建产物
|
|
78
|
+
——npm 构建与 DSH Desktop 内置构建;锚点与编译产物字节级耦合,DSH 升级后如失配
|
|
79
|
+
需更新锚点):
|
|
78
80
|
- **行为偏好**(自动换行、亮暗主题、标签布局、文件树展开状态)按工作区持久化,无需手动配置;
|
|
79
81
|
- **文件操作通道**:经 loopback RPC `/dsh-plugin-files`,写操作显式以 `danger-full-access` 执行,无外部配置项。
|
|
80
82
|
|
|
81
83
|
## 安装
|
|
82
84
|
|
|
83
|
-
>
|
|
84
|
-
>
|
|
85
|
+
> 布局补丁锚点与 DSH 编译产物字节级耦合,DSH 升级后如失配需更新锚点;0.0.15 起
|
|
86
|
+
> 自动识别 npm / DSH Desktop 两种构建产物,插件启动时自动检测并重打补丁
|
|
87
|
+
> (详见「配置」节)。
|
|
85
88
|
|
|
86
89
|
```powershell
|
|
87
90
|
# npm(推荐)
|
|
@@ -132,7 +135,9 @@ dsh plugin --profile web remove dsh-plugin-workbench
|
|
|
132
135
|
- 图片预览走同源路由 `/dsh-plugin-files/raw/<path>`:仅响应图片扩展名,
|
|
133
136
|
先经 `ctx.fs.resolve → stat`(沙箱一致的路径解析)再读取字节,20MB 上限
|
|
134
137
|
- DSH 升级会覆盖布局 bundle;0.0.9 起插件启动时自动检测并重打补丁,
|
|
135
|
-
无需手动重跑;锚点失效时需更新 `scripts/patch-layout.mjs
|
|
138
|
+
无需手动重跑;锚点失效时需更新 `scripts/patch-layout.mjs`(0.0.15 起锚点表分
|
|
139
|
+
npm / desktop-ci 两个构建变体自动探测,desktop-ci 变体存于
|
|
140
|
+
`scripts/layout-anchors.desktop-ci.json`)
|
|
136
141
|
- 本仓库不包含 DSH 编译产物
|
|
137
142
|
|
|
138
143
|
## 参与贡献
|
|
@@ -140,6 +145,14 @@ dsh plugin --profile web remove dsh-plugin-workbench
|
|
|
140
145
|
见 [CONTRIBUTING](./CONTRIBUTING.md) 与 [CODE_OF_CONDUCT](./CODE_OF_CONDUCT.md);
|
|
141
146
|
变更记录见 [CHANGELOG](./CHANGELOG.md)。
|
|
142
147
|
|
|
148
|
+
## 兼容性
|
|
149
|
+
|
|
150
|
+
- 实测于 DSH `0.1.2-rc.1`(0.0.16 起布局补丁锚点适配该版:detailsCol 边框样式
|
|
151
|
+
`1px/--dsw-alias-border-l2` → `.5px/--dsw-alias-border-l3`、DetailsColumn 的
|
|
152
|
+
children 新增 `SessionProvider` 包裹);0.1.1-rc.2 及更早版本用 0.0.15 的锚点表。
|
|
153
|
+
- 0.0.9 起插件启动时自动检测并重打布局补丁,DSH 升级后通常无需手动操作;
|
|
154
|
+
锚点失配会在启动日志提示 `ui-layout patch exited 1`,此时升级本插件即可。
|
|
155
|
+
|
|
143
156
|
## 相关插件
|
|
144
157
|
|
|
145
158
|
本插件属于 **Pasumao 的 dsh 插件生态**,同系列已发布插件可搭配使用:
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-plugin-workbench",
|
|
3
3
|
"description": "VS Code-style workspace file explorer for the DeepSeek Harness web GUI — editable preview with syntax highlighting, tabs and line numbers, full right-click file operations (create / rename / delete / copy / cut / paste / reveal in file manager), inline image & markdown preview, @-mention files into chat, drag files into the composer, per-workspace state with undo. Turns the dsh web page into a lightweight code editor.",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.16",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@11.21.0",
|
|
7
7
|
"engines": {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
{
|
|
2
|
+
"variant": "desktop-ci",
|
|
3
|
+
"note": "computeColumns anchor/replacement for the DSH Desktop packaged build of @deepseek-ai/dsh-client-ui-layout (2-tab indent, COLLAPSED_SIDEBAR_WIDTH, one stray CRLF). Generated mechanically from a real bundle; do not hand-edit.",
|
|
4
|
+
"anchor": "\t\tfunction computeColumns(viewport, sidebar, details) {\n\t\t\tconst s = sidebar === 0 ? COLLAPSED_SIDEBAR_WIDTH : clampWidth(sidebar, 264, 420);\r\n\t\t\tconst d0 = details === 0 ? 0 : clampWidth(details, 300, 520);\n\t\t\tif (s + d0 + 640 <= viewport) return {\n\t\t\t\tsidebar: s,\n\t\t\t\tcenter: viewport - s - d0,\n\t\t\t\tdetails: d0\n\t\t\t};\n\t\t\tconst d1 = d0 === 0 ? 0 : Math.max(300, viewport - s - 640);\n\t\t\tif (s + d1 + 640 <= viewport) return {\n\t\t\t\tsidebar: s,\n\t\t\t\tcenter: 640,\n\t\t\t\tdetails: d1\n\t\t\t};\n\t\t\treturn {\n\t\t\t\tsidebar: s,\n\t\t\t\tcenter: Math.max(0, viewport - s),\n\t\t\t\tdetails: 0\n\t\t\t};\n\t\t}",
|
|
5
|
+
"replacement": "\t\tfunction computeColumns(viewport, sidebar, explorer, details) {\n\t\t\tconst s = sidebar === 0 ? COLLAPSED_SIDEBAR_WIDTH : clampWidth(sidebar, 264, 420);\r\n\t\t\tconst e0 = explorer === 0 ? 0 : clampWidth(explorer, 200, 420);\r\n\t\t\tconst d0 = details === 0 ? 0 : clampWidth(details, 300, 520);\n\t\t\tif (s + e0 + d0 + 640 <= viewport) return {\n\t\t\t\tsidebar: s,\n\t\t\t\texplorer: e0,\n\t\t\t\tcenter: viewport - s - e0 - d0,\n\t\t\t\tdetails: d0\n\t\t\t};\n\t\t\tconst d1 = d0 === 0 ? 0 : Math.max(300, viewport - s - e0 - 640);\n\t\t\tif (s + e0 + d1 + 640 <= viewport) return {\n\t\t\t\tsidebar: s,\n\t\t\t\texplorer: e0,\n\t\t\t\tcenter: 640,\n\t\t\t\tdetails: d1\n\t\t\t};\n\t\t\treturn {\n\t\t\t\tsidebar: s,\n\t\t\t\texplorer: e0,\n\t\t\t\tcenter: Math.max(0, viewport - s - e0),\n\t\t\t\tdetails: 0\n\t\t\t};\n\t\t}"
|
|
6
|
+
}
|
package/scripts/patch-layout.mjs
CHANGED
|
@@ -8,6 +8,17 @@
|
|
|
8
8
|
* this script performs precise, idempotent string replacements and verifies
|
|
9
9
|
* every anchor landed. It backs up the original before the first write.
|
|
10
10
|
*
|
|
11
|
+
* The same @deepseek-ai/dsh-client-ui-layout version ships as TWO different
|
|
12
|
+
* builds with byte-different output:
|
|
13
|
+
* - "npm": the npm-registry tarball (function bodies at 0 indent,
|
|
14
|
+
* literal `56`, LF-only line endings);
|
|
15
|
+
* - "desktop-ci": the build packaged inside DSH Desktop's resources/app and
|
|
16
|
+
* cloned into its profile (2-tab indented computeColumns,
|
|
17
|
+
* `COLLAPSED_SIDEBAR_WIDTH` constant, one stray CRLF).
|
|
18
|
+
* Every variant shares all anchors except `computeColumns`; both variants are
|
|
19
|
+
* dry-run against the target and the first one whose anchors ALL match is
|
|
20
|
+
* applied. If none matches, the bundle changed again — update the anchors.
|
|
21
|
+
*
|
|
11
22
|
* Usage:
|
|
12
23
|
* node scripts/patch-layout.mjs [--target <abs path to client.js>] [--force]
|
|
13
24
|
*
|
|
@@ -19,6 +30,7 @@ import { basename, dirname, join, resolve } from 'node:path'
|
|
|
19
30
|
import { fileURLToPath } from 'node:url'
|
|
20
31
|
import { homedir } from 'node:os'
|
|
21
32
|
|
|
33
|
+
const SCRIPT_DIR = fileURLToPath(new URL('.', import.meta.url))
|
|
22
34
|
const REPO_ROOT = fileURLToPath(new URL('..', import.meta.url))
|
|
23
35
|
const BACKUP_DIR = join(REPO_ROOT, 'patches', 'layout.backup')
|
|
24
36
|
|
|
@@ -36,8 +48,8 @@ const L = (...lines) => lines.join('\n')
|
|
|
36
48
|
const REPLACEMENTS = [
|
|
37
49
|
{
|
|
38
50
|
id: 'css.explorerCol.rule',
|
|
39
|
-
anchor: '.pI_x6G_detailsCol{border-left
|
|
40
|
-
replacement: '.pI_x6G_detailsCol{border-left
|
|
51
|
+
anchor: '.pI_x6G_detailsCol{border-left:.5px solid var(--dsw-alias-border-l3);min-width:0;overflow:hidden}',
|
|
52
|
+
replacement: '.pI_x6G_detailsCol{border-left:.5px solid var(--dsw-alias-border-l3);min-width:0;overflow:hidden}.pI_x6G_explorerCol{background:var(--dsw-specific-sidebar-fill);border-right:.5px solid var(--dsw-alias-border-l3);min-width:0;overflow:hidden}',
|
|
41
53
|
},
|
|
42
54
|
{
|
|
43
55
|
id: 'css.explorerCol.handleContent',
|
|
@@ -162,7 +174,7 @@ const REPLACEMENTS = [
|
|
|
162
174
|
},
|
|
163
175
|
{
|
|
164
176
|
id: 'appframe.explorerColumn',
|
|
165
|
-
anchor: '\t\t\t\t\t(0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(CenterColumn, { children: renderSlot("conversation", {}) }), (0, react_jsx_runtime.jsx)(DetailsColumn, { children: renderSlot("details", {}) })] }),',
|
|
177
|
+
anchor: '\t\t\t\t\t(0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(CenterColumn, { children: renderSlot("conversation", {}) }), (0, react_jsx_runtime.jsx)(DetailsColumn, { children: (0, react_jsx_runtime.jsx)(SessionProvider, { children: renderSlot("details", {}) }) })] }),',
|
|
166
178
|
replacement: L(
|
|
167
179
|
'\t\t\t\t\t(0, react_jsx_runtime.jsx)("div", {',
|
|
168
180
|
'\t\t\t\t\t\tclassName: AppFrame_module_css_default.explorerCol,',
|
|
@@ -170,7 +182,7 @@ const REPLACEMENTS = [
|
|
|
170
182
|
'\t\t\t\t\t\t\twidth: cols.explorer',
|
|
171
183
|
'\t\t\t\t\t\t})',
|
|
172
184
|
'\t\t\t\t\t}),',
|
|
173
|
-
'\t\t\t\t\t(0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(CenterColumn, { children: renderSlot("conversation", {}) }), (0, react_jsx_runtime.jsx)(DetailsColumn, { children: renderSlot("details", {}) })] }),',
|
|
185
|
+
'\t\t\t\t\t(0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [(0, react_jsx_runtime.jsx)(CenterColumn, { children: renderSlot("conversation", {}) }), (0, react_jsx_runtime.jsx)(DetailsColumn, { children: (0, react_jsx_runtime.jsx)(SessionProvider, { children: renderSlot("details", {}) }) })] }),',
|
|
174
186
|
),
|
|
175
187
|
},
|
|
176
188
|
{
|
|
@@ -242,8 +254,41 @@ const REPLACEMENTS = [
|
|
|
242
254
|
},
|
|
243
255
|
]
|
|
244
256
|
|
|
257
|
+
// desktop-ci variant: same table, with `computeColumns` swapped for the anchor
|
|
258
|
+
// pair extracted mechanically from a real DSH Desktop packaged bundle.
|
|
259
|
+
const DESKTOP_CI = JSON.parse(readFileSync(join(SCRIPT_DIR, 'layout-anchors.desktop-ci.json'), 'utf8'))
|
|
260
|
+
const VARIANTS = [
|
|
261
|
+
{ id: 'npm', replacements: REPLACEMENTS },
|
|
262
|
+
{
|
|
263
|
+
id: 'desktop-ci',
|
|
264
|
+
replacements: REPLACEMENTS.map((item) =>
|
|
265
|
+
item.id === 'computeColumns'
|
|
266
|
+
? { id: 'computeColumns', anchor: DESKTOP_CI.anchor, replacement: DESKTOP_CI.replacement }
|
|
267
|
+
: item
|
|
268
|
+
),
|
|
269
|
+
},
|
|
270
|
+
]
|
|
271
|
+
|
|
245
272
|
const PATCHED_MARKERS = ['"explorerCol": "pI_x6G_explorerCol"', 'setExplorer: (d, px) => {', 'renderSlot("explorer"', 'renderSlot("explorer.preview"', 'conversationSeat']
|
|
246
273
|
|
|
274
|
+
function applyReplacements(original, replacements) {
|
|
275
|
+
let patched = original
|
|
276
|
+
const failures = []
|
|
277
|
+
for (const item of replacements) {
|
|
278
|
+
const count = countOccurrences(patched, item.anchor)
|
|
279
|
+
if (count === 0) {
|
|
280
|
+
failures.push(`${item.id}: anchor not found`)
|
|
281
|
+
continue
|
|
282
|
+
}
|
|
283
|
+
if (count > 1) {
|
|
284
|
+
failures.push(`${item.id}: anchor found ${count} times (expected exactly 1)`)
|
|
285
|
+
continue
|
|
286
|
+
}
|
|
287
|
+
patched = patched.replace(item.anchor, item.replacement)
|
|
288
|
+
}
|
|
289
|
+
return { patched, failures }
|
|
290
|
+
}
|
|
291
|
+
|
|
247
292
|
function main() {
|
|
248
293
|
const target = resolve(targetArg ?? defaultTarget)
|
|
249
294
|
if (!existsSync(target)) {
|
|
@@ -264,6 +309,19 @@ function main() {
|
|
|
264
309
|
console.log('[patch-layout] --force: re-patching from the current file. Consider restoring the .orig backup first.')
|
|
265
310
|
}
|
|
266
311
|
|
|
312
|
+
const trials = VARIANTS.map((variant) => ({ id: variant.id, ...applyReplacements(original, variant.replacements) }))
|
|
313
|
+
const chosen = trials.find((trial) => trial.failures.length === 0)
|
|
314
|
+
if (!chosen) {
|
|
315
|
+
console.error('[patch-layout] ABORTED — the bundle matches no known build variant:')
|
|
316
|
+
for (const trial of trials) {
|
|
317
|
+
console.error(` variant "${trial.id}":`)
|
|
318
|
+
for (const failure of trial.failures) console.error(` - ${failure}`)
|
|
319
|
+
}
|
|
320
|
+
console.error('[patch-layout] the dsh version may have changed; update the variant anchors in scripts/.')
|
|
321
|
+
process.exit(1)
|
|
322
|
+
}
|
|
323
|
+
console.log(`[patch-layout] build variant: ${chosen.id}`)
|
|
324
|
+
|
|
267
325
|
mkdirSync(BACKUP_DIR, { recursive: true })
|
|
268
326
|
const pristine = join(BACKUP_DIR, 'client.js.orig')
|
|
269
327
|
if (!existsSync(pristine)) {
|
|
@@ -274,36 +332,14 @@ function main() {
|
|
|
274
332
|
copyFileSync(real, join(BACKUP_DIR, `client.js.${stamp}.bak`))
|
|
275
333
|
}
|
|
276
334
|
|
|
277
|
-
|
|
278
|
-
const failures = []
|
|
279
|
-
for (const item of REPLACEMENTS) {
|
|
280
|
-
const count = countOccurrences(patched, item.anchor)
|
|
281
|
-
if (count === 0) {
|
|
282
|
-
failures.push(`${item.id}: anchor not found`)
|
|
283
|
-
continue
|
|
284
|
-
}
|
|
285
|
-
if (count > 1) {
|
|
286
|
-
failures.push(`${item.id}: anchor found ${count} times (expected exactly 1)`)
|
|
287
|
-
continue
|
|
288
|
-
}
|
|
289
|
-
patched = patched.replace(item.anchor, item.replacement)
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
if (failures.length > 0) {
|
|
293
|
-
console.error('[patch-layout] ABORTED — the bundle does not match the expected compiled output:')
|
|
294
|
-
for (const failure of failures) console.error(` - ${failure}`)
|
|
295
|
-
console.error('[patch-layout] the dsh version may have changed; update scripts/patch-layout.mjs anchors.')
|
|
296
|
-
process.exit(1)
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
const missingMarkers = PATCHED_MARKERS.filter((marker) => !patched.includes(marker))
|
|
335
|
+
const missingMarkers = PATCHED_MARKERS.filter((marker) => !chosen.patched.includes(marker))
|
|
300
336
|
if (missingMarkers.length > 0) {
|
|
301
337
|
console.error('[patch-layout] verification failed — missing markers:')
|
|
302
338
|
for (const marker of missingMarkers) console.error(` - ${marker}`)
|
|
303
339
|
process.exit(1)
|
|
304
340
|
}
|
|
305
341
|
|
|
306
|
-
writeFileSync(real, patched, 'utf8')
|
|
342
|
+
writeFileSync(real, chosen.patched, 'utf8')
|
|
307
343
|
console.log(`[patch-layout] patched: ${real}`)
|
|
308
344
|
console.log('[patch-layout] verified: explorerCol class, setExplorer action, explorer slot render.')
|
|
309
345
|
console.log('[patch-layout] restart dsh web to serve the new bundle rev.')
|