@lybx-leyw/dsh-pages 0.0.0-stage → 0.1.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/DESIGN-ZH.md ADDED
@@ -0,0 +1,85 @@
1
+ # dsh-pages —— 设计说明
2
+
3
+ [English](<DESIGN.md>) | 中文 · [使用指南](<README-ZH.md>)
4
+
5
+ ## 1. 当前架构
6
+
7
+ 页面壳通过普通 `shell.overlay` 注册增加并行导航与产品页面内容。该注册声明并拥有新增的 root 作用域 keyed 子槽 `page.content`,由持有声明权限的 owner 渲染选中的 key;贡献插件通过原始 slots 服务注册内容。
8
+
9
+ ```text
10
+ 原生 DSH root(不改动,持续挂载)
11
+ └─ shell.overlay
12
+ └─ dsh-pages 页面壳(拥有自己的子槽声明)
13
+ ├─ 常驻导航栏
14
+ └─ page.content[key = 活动页] / 内置管理页
15
+ ```
16
+
17
+ 这是视觉组合,不是搬迁原生树。页面壳不替换原生 root 组件、不重新声明原生 children、不改写原生 key、不移动原生 DOM,也不重挂载原生 root。`home` 显示下方已存在的工作台,不再渲染第二份 DSH;产品页面覆盖工作台内容区域。
18
+
19
+ 可撤销样式通过 `:has([data-dsh-pages-shell])` 限定原生 `#root` 的左侧 padding。实时导航宽度同时驱动导航与内容几何。卸载页面壳即移除布局规则,无需恢复任何原生 root 字段。
20
+
21
+ ### 模块与入口
22
+
23
+ - [page-shell.jsx](<src/page-shell.jsx>):页面壳呈现与 `installPageShell` 安装。
24
+ - [pages-service.js](<src/pages-service.js>):`createPages`、内置元数据注册、状态/服务装配及浏览器偏好。
25
+ - [state.js](<src/state.js>):页面身份、选择、排列、固定、宽度与快照。
26
+ - [page-manager.jsx](<src/page-manager.jsx>):操作同一注册表的管理 UI。
27
+ - [preferences.js](<src/preferences.js>):经过校验的浏览器本地偏好存储。
28
+ - [client.jsx](<src/client.jsx>):客户端入口;`apply` 与 `applyWithConfig` 安装同一套页面壳。
29
+
30
+ ## 2. 槽所有权与设置
31
+
32
+ 原生槽声明继续归原生 owner 所有。页面壳不接管 `slots` 服务,也不替原生树建立命名空间。产品页面元数据与槽内容是两份独立贡献,均由贡献插件负责清理;只注册元数据不会自动提供内容。
33
+
34
+ 设置完整留在原生设置面板。设置项属于该面板拥有的子槽,无关的页面壳不能仅凭槽名渲染它们。因此不提供替代设置页,导航栏也不增加设置入口;这不等于已验证任意第三方 UI。
35
+
36
+ ## 3. 导航模型
37
+
38
+ 内置 DSH 工作台(`home`)与页面管理(`pages`)和其他页面使用同一注册表,不另建导航状态机。配置中的 home 与 manager 身份必须不同。
39
+
40
+ 页面壳只拥有**导航与页面生命周期,绝不规定页面版式**。它给当前页一块裸的整幅区域,区域内的一切都归页面自己:标题、工具条、返回链接、可读栏宽、空态、图标。曾经的默认图标、「返回工作台」按钮与居中的内容栏,等于让页面壳替所有页面决定版式 —— 复杂页面因此被强行塞进壳的形状里。
41
+
42
+ 图标随注册一起由页面声明:`icon` 组件,或没有图标库时用 `glyph` 字符串。页面壳只渲染页面声明的东西,不做任何替代 —— 漏声明会暴露出来,而不是被相似的默认图形掩盖。
43
+
44
+ 键盘处理遵循同一条边界:页面壳只在按 Escape 时关闭自己的导轨浮层,其余焦点收束、Tab 顺序与 Escape 都留给页面。带编辑器、对话框或「离开本页」手势的页面自己拥有这三件事。
45
+
46
+ 三个显式分组为 `top`、`overflow`(回收组)、`bottom`。回收是用户编排动作,不是空间不足时自动挤出页面。`overflow` 非空时显示 **…**,回收页仍可从中访问。管理页自身也能回收,并从该入口重新打开。
47
+
48
+ 固定是独立状态:回收页面保持 `region: 'overflow'`,以 `pinned` 与 `pinOrder` 控制顶部组 **…** 后追加的快捷入口,同时仍列在回收组。取消固定只移除快捷入口,不会把页面晋升为 `top`。普通排序与固定排序不能混为一谈;`promotePage` 是编排动作,不是固定状态的权威。
49
+
50
+ 导航宽度为 40–96 像素的整数,默认 64。修改后立即更新快照与布局,并保存明确设置的偏好。导航图标(包括固定尺寸的插件图标和更多按钮)按 `width / 64` 同比缩放;菜单与管理页内容保留自己的尺寸。
51
+
52
+ 服务提供配置、`getSnapshot`、`subscribe`、`selectPage`、`registerPage`、`setPageRegion`、`setPageOrder`、`promotePage`、`setPagePinned`、`setRailWidth`。UI 消费者订阅快照,不应再维护第二份页面注册表。
53
+
54
+ ## 4. 生命周期边界
55
+
56
+ - **原生 UI:** 持续挂载在产品页面下方。覆盖它不会清理其 React effect、重置面板/会话选择、停用插件、取消任务或撤销全局快捷键。
57
+ - **产品内容:** 页面壳渲染当前 keyed 内容。切走可能卸载该页的 React 子树并执行组件清理,但不会 dispose 插件或其元数据/内容注册;再次进入可能创建新的组件实例。
58
+ - **贡献:** 注册存活到其所属 effect 被撤销。元数据与内容清理相互独立,贡献者必须管理两者。移除活动元数据后选中 home;迟到的 disposer 不应移除复用同一 id 的较新注册。
59
+ - **页面壳:** 导航与管理共享服务生命周期。卸载只清理自己的注册、订阅与样式,不清理原生业务服务或已保存偏好。
60
+
61
+ 这不是隔离:插件仍共享 Cordis、文档和应用级 portal。原生浮层可能覆盖产品页。焦点处理不会让页面壳成为安全边界,也不会禁用 document 捕获阶段的快捷键。自动浮窗转页、协调 owner 关闭/撤销不属于现行架构。
62
+
63
+ ## 5. 持久化
64
+
65
+ 明确的用户动作将页面排列(`region`、`order`)、固定状态(`pinned`、`pinOrder`)及 `railWidth` 保存到 `localStorage`。仅注册默认值不会写入覆盖偏好。相同 id 的真实页面注册时应用保存值,也支持晚到注册。卸载页面保留其偏好,以供之后恢复;保存的 id 不会凭空创建页面。
66
+
67
+ 存储键为 `dsh-pages:preferences:v1:` 加上 `[navigationSlot, pageSlot, classPrefix, homePage]` JSON 数组的 URI 编码。偏好属于该产品身份、浏览器配置与 origin,不属于账号,不做跨标签页同步。
68
+
69
+ 旧版本 1 文档继续使用相同存储键。未知字段(包括废弃的 `exportedSlots`)在读取时丢弃,不再写回。
70
+
71
+ 偏好层不保存活动页面、原生面板/会话状态、组件、DOM 或业务数据。JSON 损坏、文档版本不支持、存储不可用或配额不足时警告,内存操作仍可用。删除相应产品存储键后,下次加载重置保存的偏好。
72
+
73
+ ## 6. 历史方案——已废弃,不是现行契约
74
+
75
+ 早期方案尝试包装或遮蔽原生 root 注册、保留 owner 渲染权限、通过 portal 导出侧栏槽视图,并在锚点之间转移原生 main 内容。root 遮蔽曾在真实宿主遇到重复声明子槽失败。这些方案依赖原生所有权和可变内部实现细节;当前两个入口均不安装它们。
76
+
77
+ 另一些废弃工作将浮动 dialog/menu/popover 映射为全页几何、协调 owner 的关闭/撤销,并在切页时卸载原生视图作用域。以上都不是当前页面壳的能力承诺。尤其“离开 home 销毁原生 UI”的旧说法,与现行原生 root 持续挂载相冲突。
78
+
79
+ 旧键改写 facade、原生槽导出 API、适配器引用/协议保证、结构回滚机制、宿主版本兼容列表及历史测试数量,均不得理解为当前公共保证。它们描述的是另一套实现,而非现行实现的可选功能。
80
+
81
+ ## 7. 兼容性与验证限制
82
+
83
+ 当前集成仍依赖宿主允许 `shell.overlay` owner 声明自己的子槽并渲染 keyed 内容,以及预期的 root 几何、CSS `:has()` 支持和 overlay 层级。保留原生所有权可避免一类已知冲突,但不能证明任意插件、任意全局浮层或宿主升级都兼容。
84
+
85
+ 本文记录架构与边界,不是新一轮实机测试报告。宿主升级与第三方组合需要单独验证。未来上游正式布局契约可能减少几何与层级假设,但它不是当前依赖或已实现功能。
package/DESIGN.md ADDED
@@ -0,0 +1,85 @@
1
+ # dsh-pages — design
2
+
3
+ English | [中文](<DESIGN-ZH.md>) · [User guide](<README.md>)
4
+
5
+ ## 1. Current architecture
6
+
7
+ The shell adds parallel navigation and product-page content through an ordinary `shell.overlay` registration. That registration declares and owns a new root-scoped, keyed child slot, `page.content`. The authorized owner renders the selected key; contributing plugins register content into that slot through the original slots service.
8
+
9
+ ```text
10
+ Native DSH root (unchanged and continuously mounted)
11
+ └─ shell.overlay
12
+ └─ dsh-pages shell (owns its own child declaration)
13
+ ├─ persistent navigation rail
14
+ └─ page.content[key = active page] / built-in manager
15
+ ```
16
+
17
+ This is visual composition, not native-tree relocation. The shell does not replace the native root component, redeclare native children, rewrite native keys, reparent native DOM, or remount the native root. `home` reveals the workbench already beneath the shell; it is not a second rendering of DSH. A product page covers the native workbench's content area.
18
+
19
+ A reversible stylesheet scopes native `#root` left padding with `:has([data-dsh-pages-shell])`. The live rail width drives both navigation and content geometry. Removing the shell removes its layout rule; no native root field needs restoration.
20
+
21
+ ### Modules and entry points
22
+
23
+ - [page-shell.jsx](<src/page-shell.jsx>): shell presentation and `installPageShell` installation.
24
+ - [pages-service.js](<src/pages-service.js>): `createPages`, built-in metadata registrations, state/service wiring, and browser preferences.
25
+ - [state.js](<src/state.js>): page identity, selection, arrangement, pinning, width, and snapshots.
26
+ - [page-manager.jsx](<src/page-manager.jsx>): management UI over the same registry.
27
+ - [preferences.js](<src/preferences.js>): validated browser-local preference storage.
28
+ - [client.jsx](<src/client.jsx>): client entry; `apply` and `applyWithConfig` install the same shell.
29
+
30
+ ## 2. Slot ownership and settings
31
+
32
+ Native slot declarations remain with their native owners. The shell does not take over the `slots` service or claim a namespace for the native tree. Product metadata and slot content are separate contributions; both must be disposed by their contributing plugin. A metadata registration alone does not supply page content.
33
+
34
+ Settings remain in the native settings panel. Settings contributions are child slots owned by that panel; an unrelated shell cannot render them merely by knowing their names. There is no replacement settings page or settings entry on this rail, and no promise that arbitrary third-party UI has been verified.
35
+
36
+ ## 3. Navigation model
37
+
38
+ The built-ins are DSH workbench (`home`) and Page manager (`pages`), registered into the same page registry as other pages. They are not a separate navigation state machine. The configured home and manager identities must differ.
39
+
40
+ The shell owns **navigation and the active-page lifecycle, never page layout**. It allocates a bare full-bleed region for the active page; everything inside that region belongs to the page: headings, toolbars, back links, readable-width columns, empty states, icons. A shell that supplied a default icon, a "back to workbench" button, or a centred content column was deciding page-level UI for every page at once, which is exactly what forces complex pages into a shell-shaped box.
41
+
42
+ A page contributes its icon as part of its registration — an `icon` component, or a `glyph` string for packages without an icon library. The shell renders what the page declared and substitutes nothing, so a missing icon stays visible instead of being masked by a look-alike default.
43
+
44
+ Keyboard handling follows the same boundary: the shell closes its own rail popover on Escape and otherwise leaves focus containment, tab order, and Escape to the page. A page with an editor, a dialog, or a "leave this page" gesture owns all three.
45
+
46
+ The three explicit groups are `top`, `overflow` (recycle), and `bottom`. Recycling is a user arrangement choice, not automatic eviction caused by limited rail space. Nonempty `overflow` displays **…**, so recycled pages remain reachable. The manager itself can be recycled and reopened there.
47
+
48
+ Pinning is independent state: a recycled page retains `region: 'overflow'`, with `pinned` and `pinOrder` controlling its extra shortcut after **…** in the top group. It remains listed in the recycle group. Unpinning removes that shortcut without promoting the page into `top`. Normal ordering and pin ordering must not be conflated; `promotePage` is an arrangement action, not the pin-state authority.
49
+
50
+ Rail width is an integer from 40 to 96 pixels, default 64. Updating it changes the live snapshot and layout immediately and saves the explicit preference. Rail icons, including fixed-size plugin icons and the more button, scale by `width / 64`; menu and manager content keep their own sizing.
51
+
52
+ The service exposes configuration, `getSnapshot`, `subscribe`, `selectPage`, `registerPage`, `setPageRegion`, `setPageOrder`, `promotePage`, `setPagePinned`, and `setRailWidth`. UI consumers subscribe to snapshots rather than maintain another page registry.
53
+
54
+ ## 4. Lifecycle boundaries
55
+
56
+ - **Native UI:** remains mounted beneath product pages. Covering it does not tear down its React effects, reset panel/session selection, disable plugins, cancel tasks, or revoke global shortcuts.
57
+ - **Product content:** the shell renders the active keyed content. Switching away can unmount that page's rendered React subtree and run its component cleanup; it does not dispose the plugin or its metadata/content registrations. Returning may create a fresh component instance.
58
+ - **Contributions:** registrations live until their owning effects are disposed. Metadata and content cleanup are independent; a contributor must own both. Removing the active metadata registration selects home. A stale disposer must not remove a newer registration reusing the same id.
59
+ - **Shell:** navigation and management share the service lifetime. Removing the installation cleans up its own registrations, subscriptions, and styles, not native domain services or saved preferences.
60
+
61
+ This is not isolation: all plugins still share Cordis, the document, and application-level portals. Native overlays may extend above the covering page. Focus handling does not make the shell a security boundary or disable document-capture shortcuts. No automatic floating-carrier conversion or owner-close orchestration belongs to this architecture.
62
+
63
+ ## 5. Persistence
64
+
65
+ Explicit user actions save page arrangement (`region`, `order`), pin state (`pinned`, `pinOrder`), and `railWidth` in `localStorage`. Registration defaults alone do not create saved overrides. Matching live ids receive saved arrangement, including late registrations. Unloading a page retains its preferences for a later registration; stored ids never create missing pages.
66
+
67
+ The storage key is `dsh-pages:preferences:v1:` plus the URI-encoded JSON array `[navigationSlot, pageSlot, classPrefix, homePage]`. Preferences belong to that product identity, browser profile, and origin, not an account. There is no cross-tab synchronization.
68
+
69
+ Old version-1 documents are accepted without changing the storage key. Unknown fields, including the retired `exportedSlots` field, are discarded on load and are not written back.
70
+
71
+ Active selection, native panel/session state, components, DOM, and business data are not persisted by this preference layer. Invalid JSON, unsupported documents, unavailable storage, and quota failures warn and leave in-memory operation available. Clearing the corresponding product key resets saved preferences on the next load.
72
+
73
+ ## 6. Historical approaches — retired, not current contracts
74
+
75
+ Earlier designs attempted to wrap or shadow a native root registration, preserve owner rendering authority, export sidebar slot views through portals, and move native main content between anchors. Root shadowing encountered duplicate child-slot declaration failures on a real host. These approaches depend on native ownership and mutable implementation details; they are not installed by either current entry point.
76
+
77
+ Other retired work mapped floating dialogs/menus/popovers into full-page geometry, coordinated owner close/undo behavior, and unmounted native view scopes on page switches. None of those behaviors is a promise of the current shell. In particular, the former claim that leaving home destroys native UI conflicts with the current continuously mounted native root.
78
+
79
+ Former key-rewriting facades, native-slot export APIs, adapter lease/protocol guarantees, structural rollback mechanisms, host-version compatibility lists, and historical test counts must not be read as current public guarantees. They describe a different implementation, not optional features of this one.
80
+
81
+ ## 7. Compatibility and verification limits
82
+
83
+ The current integration depends on the host permitting the owned `shell.overlay` child declaration and rendering keyed content, plus the expected root geometry, CSS `:has()` support, and overlay layering. Preserving native ownership avoids a known class of collisions; it does not prove compatibility with every plugin, every global overlay, or every host upgrade.
84
+
85
+ This document records architecture and boundaries, not a fresh real-device test report. Host upgrades and third-party combinations require separate validation. An upstream supported layout contract could reduce geometry and layering assumptions, but is not a current dependency or implemented feature.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 lybx-leyw and zju-workbench contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README-ZH.md ADDED
@@ -0,0 +1,86 @@
1
+ # dsh-pages
2
+
3
+ npm 包名:`@lybx-leyw/dsh-pages`。仓库名和插件 id 仍为 `dsh-pages`。
4
+
5
+ [English](<https://github.com/lybx-leyw/dsh-pages/blob/chore/initial-import/README.md>) | 中文
6
+
7
+ ![dsh-pages 与原生 DSH 工作台](<https://raw.githubusercontent.com/lybx-leyw/dsh-pages/refs/heads/chore/initial-import/docs/screenshot.png>)
8
+
9
+ 为 DeepSeek Harness 增加常驻页面导航栏,内置 **DSH 工作台**和**页面管理**。可添加自己的页面,不替换、不重挂载原生工作台。
10
+
11
+ ## 安装
12
+
13
+ 需要 Node.js **22.x 中的 22.19+,或 24+**,以及 DSH Web 宿主。本包是 DSH 插件,不是独立网页应用。
14
+
15
+ 在目标 DSH profile 目录执行:
16
+
17
+ ```sh
18
+ npm install @lybx-leyw/dsh-pages
19
+ ```
20
+
21
+ 将 `@lybx-leyw/dsh-pages` 追加到该 profile 的 `dsh.profile.bundles`,保留宿主 bundle 和已有插件。例如:
22
+
23
+ ```json
24
+ {
25
+ "dsh": {
26
+ "profile": {
27
+ "bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "@lybx-leyw/dsh-pages"]
28
+ }
29
+ }
30
+ }
31
+ ```
32
+
33
+ 安装后重启目标 DSH 宿主,并刷新其网页。
34
+
35
+ ## 页面管理
36
+
37
+ 打开**页面管理**调整导航:
38
+
39
+ - **顶部组**:导航栏顶部的普通入口。
40
+ - **回收组**:收起的页面;非空时显示 **…**,仍能从中打开页面。
41
+ - **底部组**:导航栏底部的入口。
42
+ - 可切换分组、排序、打开或回收页面,管理页自身也遵循相同规则。
43
+ - 固定回收页面后,在顶部组的 **…** 后追加快捷入口。页面仍留在回收菜单中,取消固定只移除快捷入口。
44
+ - 导航宽度可设为 **40–96px**,默认 **64px**;图标、按钮、间距和留白同比缩放。
45
+
46
+ 修改立即生效。排列和宽度保存在同一浏览器、同一 origin 的本地偏好中,不跨设备或标签页同步。
47
+
48
+ ## 添加页面
49
+
50
+ 贡献页面的客户端插件需注入 `pages` 和 `slots`。导航元数据与内容使用同一 id,并分别用 effect 管理注册生命周期:
51
+
52
+ ```jsx
53
+ export const inject = ['pages', 'slots'];
54
+
55
+ export function apply(ctx) {
56
+ ctx.effect(() => ctx.pages.registerPage({
57
+ id: 'notes', label: '笔记', region: 'top', order: 10,
58
+ }));
59
+
60
+ ctx.effect(() => ctx.slots.inject('page.content', () =>
61
+ ctx.slots.register({ name: 'page.content', key: 'notes' }, NotesPage)
62
+ ));
63
+ }
64
+ ```
65
+
66
+ `NotesPage` 是你自己的 React 组件。存活页面 id 必须唯一。移除活动页面后返回工作台;保存的偏好不会凭空恢复已卸载的页面。示例使用默认内容槽名。
67
+
68
+ 产品 bundle 也可从 `@lybx-leyw/dsh-pages/client` 导入 `apply` 或 `applyWithConfig`,通过代码安装页面壳。安装插件应注入 `slots` 和 `locale`,不要注入它自己将创建的 `pages` 服务。两种安装方式选其一,不要重复安装。
69
+
70
+ ## 限制
71
+
72
+ - 原生设置仍归 DSH 所有;不导出原生槽、不重建设置、不自动把浮窗转为页面。
73
+ - 被覆盖的原生 UI 保持挂载;切页不会停止原生插件、后台任务或全局快捷键。
74
+ - 插件共享文档与服务,本包不是安全沙箱。
75
+ - 兼容性取决于宿主槽契约、overlay 层级、root 几何与浏览器 CSS 支持;未验证任意第三方组合。
76
+ - 存储失败时仍能在内存中操作,但偏好可能无法跨刷新保留。
77
+
78
+ ## 相关链接
79
+
80
+ - [设计与生命周期边界](<https://github.com/lybx-leyw/dsh-pages/blob/chore/initial-import/DESIGN-ZH.md>)
81
+ - [发布检查清单](<https://github.com/lybx-leyw/dsh-pages/blob/chore/initial-import/VERSIONING.md>)
82
+ - [问题反馈](<https://github.com/lybx-leyw/dsh-pages/issues>)
83
+
84
+ ## 许可证
85
+
86
+ [MIT](<https://github.com/lybx-leyw/dsh-pages/blob/chore/initial-import/LICENSE>)
package/README.md CHANGED
@@ -1,3 +1,86 @@
1
- # Temporary Holding Version
1
+ # dsh-pages
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Scoped npm package: `@lybx-leyw/dsh-pages`. The repository and plugin id stay `dsh-pages`.
4
+
5
+ English | [中文](<https://github.com/lybx-leyw/dsh-pages/blob/chore/initial-import/README-ZH.md>)
6
+
7
+ ![dsh-pages with the native DSH workbench](<https://raw.githubusercontent.com/lybx-leyw/dsh-pages/refs/heads/chore/initial-import/docs/screenshot.png>)
8
+
9
+ A persistent page rail for DeepSeek Harness, with **DSH workbench** and **Page manager** built in. Add your own pages without replacing or remounting the native workbench.
10
+
11
+ ## Install
12
+
13
+ Requires Node.js **22.19+ in the 22.x line, or 24+**, and a DSH web host. This is a DSH plugin, not a standalone web application.
14
+
15
+ Run in your target DSH profile directory:
16
+
17
+ ```sh
18
+ npm install @lybx-leyw/dsh-pages
19
+ ```
20
+
21
+ Append `@lybx-leyw/dsh-pages` to that profile's `dsh.profile.bundles`. Keep the host bundles and any existing plugins; for example:
22
+
23
+ ```json
24
+ {
25
+ "dsh": {
26
+ "profile": {
27
+ "bundles": ["@deepseek-ai/dsh-base", "@deepseek-ai/dsh-web-app", "@lybx-leyw/dsh-pages"]
28
+ }
29
+ }
30
+ }
31
+ ```
32
+
33
+ Restart the target DSH host and refresh its web page after installation.
34
+
35
+ ## Manage pages
36
+
37
+ Open **Page manager** to arrange navigation:
38
+
39
+ - **Top:** normal entries at the top of the rail.
40
+ - **Recycle:** collapsed pages, reachable through **…** whenever the group is nonempty.
41
+ - **Bottom:** entries at the bottom of the rail.
42
+ - Change groups, reorder, open, or recycle pages—including the manager itself.
43
+ - Pin a recycled page to append a shortcut after **…** in the top group. It stays in the recycle menu; unpinning removes only the shortcut.
44
+ - Adjust navigation width from **40–96px**, default **64px**. Icons, buttons, spacing, and padding scale together.
45
+
46
+ Changes apply immediately. Arrangement and width are saved locally for the same browser and origin; they do not sync across devices or tabs.
47
+
48
+ ## Add a page
49
+
50
+ A contributing client plugin must inject `pages` and `slots`. Register navigation metadata and content using the same id, and own both registrations through effects:
51
+
52
+ ```jsx
53
+ export const inject = ['pages', 'slots'];
54
+
55
+ export function apply(ctx) {
56
+ ctx.effect(() => ctx.pages.registerPage({
57
+ id: 'notes', label: 'Notes', region: 'top', order: 10,
58
+ }));
59
+
60
+ ctx.effect(() => ctx.slots.inject('page.content', () =>
61
+ ctx.slots.register({ name: 'page.content', key: 'notes' }, NotesPage)
62
+ ));
63
+ }
64
+ ```
65
+
66
+ `NotesPage` is your React component. Live ids must be unique. Removing the active page returns to the workbench; saved preferences never recreate uninstalled pages. The example uses the default content-slot name.
67
+
68
+ A product bundle may instead install the shell programmatically with `apply` or `applyWithConfig` from `@lybx-leyw/dsh-pages/client`. Inject `slots` and `locale` in the installing plugin; do not inject the `pages` service it creates. Use one installation method, not both.
69
+
70
+ ## Limits
71
+
72
+ - Native settings remain with DSH. No native-slot export, replacement settings page, or automatic floating-window conversion.
73
+ - Covered native UI stays mounted. Switching pages does not stop native plugins, background tasks, or global shortcuts.
74
+ - Plugins share the document and services; this is not a sandbox.
75
+ - Compatibility depends on host slot contracts, overlay layering, root geometry, and browser CSS support. Arbitrary third-party combinations are not verified.
76
+ - Storage failure leaves controls usable in memory, but preferences may not survive reload.
77
+
78
+ ## Links
79
+
80
+ - [Design and lifecycle boundaries](<https://github.com/lybx-leyw/dsh-pages/blob/chore/initial-import/DESIGN.md>)
81
+ - [Release checklist](<https://github.com/lybx-leyw/dsh-pages/blob/chore/initial-import/VERSIONING.md>)
82
+ - [Issues](<https://github.com/lybx-leyw/dsh-pages/issues>)
83
+
84
+ ## License
85
+
86
+ [MIT](<https://github.com/lybx-leyw/dsh-pages/blob/chore/initial-import/LICENSE>)
package/VERSIONING.md ADDED
@@ -0,0 +1,32 @@
1
+ # Versioning and release
2
+
3
+ `dsh-pages` is released from this standalone repository. Its package version follows semantic versioning; release tags use `dsh-pages-v<version>`.
4
+
5
+ ## Prepare without publishing
6
+
7
+ 1. Update package metadata, the English README, and the Chinese README before building. The npm page displays the README included in the published package.
8
+ 2. Choose a version that has not already been published. npm versions cannot be overwritten.
9
+ 3. Run:
10
+
11
+ ```sh
12
+ npm test
13
+ npm run build
14
+ npm pack --dry-run
15
+ ```
16
+
17
+ 4. Confirm the payload contains the built client, current source, bundle patch, documentation, screenshot, and license. Exclude credentials, local paths, temporary files, dependencies, and test artifacts.
18
+ 5. Confirm the README's GitHub links point to an existing branch or release. Update them if the repository's release branch changes.
19
+
20
+ `prepublishOnly` runs tests and builds before `npm publish`. It does not run during `npm pack`, so packing alone does not prove that the client is current. A dry run does not publish anything.
21
+
22
+ ## Publishing is a separate action
23
+
24
+ Only with explicit approval, sign in to npm, verify package-name ownership, and publish publicly. After publishing, verify the registry version and test installation in a clean DSH profile. Do not use a second installation alongside an existing shell instance.
25
+
26
+ Later README changes intended for the npm page require another package version. A major release is required for incompatible public config or export changes; internal renames alone are not breaking changes. Publishing npm does not push Git commits or tags to GitHub; those are separate approved actions.
27
+
28
+ ## Compatibility claims
29
+
30
+ The shell does not mutate native root registrations. Compatibility still depends on host overlay/child-slot support, CSS geometry, and browser behavior. Record release-specific verification rather than carrying forward historical adapter host lists or test counts.
31
+
32
+ Architecture and lifecycle boundaries are documented in [DESIGN](<DESIGN.md>).
@@ -0,0 +1,14 @@
1
+ # dsh bundle patch: insert the pages plugin.
2
+ #
3
+ # Optional configuration overrides for this entry:
4
+ #
5
+ # config:
6
+ # homePage: home # reveals the existing native workbench
7
+ # managerPage: pages # built-in page manager
8
+ # pageSlot: page.content # owned keyed content slot; must start with page.
9
+ #
10
+ # The shell starts on homePage. Navigation width and page arrangement are
11
+ # managed in the page manager and stored as browser-local preferences.
12
+ - insert:
13
+ - id: dsh-pages
14
+ name: "@lybx-leyw/dsh-pages"
Binary file