@dsh-plugin/dsh-loader 1.0.0 → 1.1.0-dev.32287576957

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.
Files changed (74) hide show
  1. package/LICENSE +160 -0
  2. package/README.md +251 -226
  3. package/{README.zh-CN.md → README.zh_CN.md} +227 -202
  4. package/bin/dshloader.mjs +42 -42
  5. package/cordis.patch.yml +8 -8
  6. package/dist/adapters/dsh-1-x.d.ts +23 -0
  7. package/dist/adapters/dsh-1-x.js +223 -0
  8. package/dist/adapters/dsh-1-x.js.map +1 -0
  9. package/dist/adapters/index.d.ts +22 -0
  10. package/dist/adapters/index.js +57 -0
  11. package/dist/adapters/index.js.map +1 -0
  12. package/dist/api.d.ts +13 -0
  13. package/dist/api.js +46 -0
  14. package/dist/api.js.map +1 -0
  15. package/dist/client.d.ts +157 -0
  16. package/dist/client.js +295 -0
  17. package/dist/client.js.map +1 -0
  18. package/dist/index.d.ts +52 -0
  19. package/dist/index.js +89 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/registry.d.ts +35 -0
  22. package/dist/registry.js +229 -0
  23. package/dist/registry.js.map +1 -0
  24. package/dist/services/services.d.ts +4 -0
  25. package/dist/services/services.js +28 -0
  26. package/dist/services/services.js.map +1 -0
  27. package/dist/services/settings.d.ts +41 -0
  28. package/dist/services/settings.js +161 -0
  29. package/dist/services/settings.js.map +1 -0
  30. package/dist/services/web.d.ts +10 -0
  31. package/dist/services/web.js +63 -0
  32. package/dist/services/web.js.map +1 -0
  33. package/dist/setup.d.ts +32 -0
  34. package/dist/setup.js +119 -0
  35. package/dist/setup.js.map +1 -0
  36. package/dist/types.d.ts +111 -0
  37. package/dist/types.js +12 -0
  38. package/dist/types.js.map +1 -0
  39. package/dist/version.d.ts +2 -0
  40. package/{src → dist}/version.js +5 -5
  41. package/dist/version.js.map +1 -0
  42. package/lib/client.js +283 -0
  43. package/lib/client.js.map +1 -0
  44. package/package.json +75 -59
  45. package/src/stable/agent.d.ts +1 -1
  46. package/src/stable/agent.js +2 -2
  47. package/src/stable/llm.d.ts +1 -1
  48. package/src/stable/llm.js +2 -2
  49. package/src/stable/runtime.d.ts +1 -1
  50. package/src/stable/runtime.js +5 -5
  51. package/src/stable/schema-form.d.ts +1 -1
  52. package/src/stable/schema-form.js +2 -2
  53. package/src/stable/settings.d.ts +1 -1
  54. package/src/stable/settings.js +2 -2
  55. package/src/stable/tools.d.ts +1 -1
  56. package/src/stable/tools.js +5 -5
  57. package/src/stable/ui-primitives.d.ts +4 -4
  58. package/src/stable/ui-primitives.js +6 -6
  59. package/src/stable/ui-settings.d.ts +6 -6
  60. package/src/stable/ui-settings.js +4 -4
  61. package/src/stable/ui-slots.d.ts +1 -1
  62. package/src/stable/ui-slots.js +2 -2
  63. package/src/stable/web-react.d.ts +1 -1
  64. package/src/stable/web-react.js +2 -2
  65. package/src/adapters/dsh-1-x.js +0 -236
  66. package/src/adapters/index.js +0 -59
  67. package/src/api.js +0 -56
  68. package/src/client.js +0 -330
  69. package/src/index.js +0 -105
  70. package/src/registry.js +0 -242
  71. package/src/services/services.js +0 -28
  72. package/src/services/settings.js +0 -174
  73. package/src/services/web.js +0 -71
  74. package/src/setup.mjs +0 -125
package/LICENSE ADDED
@@ -0,0 +1,160 @@
1
+ GNU LESSER GENERAL PUBLIC LICENSE
2
+ Version 3, 29 June 2007
3
+
4
+ Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
5
+ Everyone is permitted to copy and distribute verbatim copies
6
+ of this license document, but changing it is not allowed.
7
+
8
+
9
+ This version of the GNU Lesser General Public License incorporates
10
+ the terms and conditions of version 3 of the GNU General Public
11
+ License, supplemented by the additional permissions listed below.
12
+
13
+ 0. Additional Definitions.
14
+
15
+ As used herein, "this License" refers to version 3 of the GNU Lesser
16
+ General Public License, and the "GNU GPL" refers to version 3 of the GNU
17
+ General Public License.
18
+
19
+ "The Library" refers to a covered work governed by this License,
20
+ other than an Application or a Combined Work as defined below.
21
+
22
+ An "Application" is any work that makes use of an interface provided
23
+ by the Library, but which is not otherwise based on the Library.
24
+ Defining a subclass of a class defined by the Library is deemed a mode
25
+ of using an interface provided by the Library.
26
+
27
+ A "Combined Work" is a work produced by combining or linking an
28
+ Application with the Library. The particular version of the Library
29
+ with which the Combined Work was made is also called the "Linked
30
+ Version".
31
+
32
+ The "Minimal Corresponding Source" for a Combined Work means the
33
+ Corresponding Source for the Combined Work, excluding any source code
34
+ for portions of the Combined Work that, considered in isolation, are
35
+ based on the Application, and not on the Linked Version.
36
+
37
+ The "Corresponding Application Code" for a Combined Work means the
38
+ object code and/or source code for the Application, including any data
39
+ and utility programs needed for reproducing the Combined Work from the
40
+ Application, but excluding the System Libraries of the Combined Work.
41
+
42
+ 1. Exception to Section 3 of the GNU GPL.
43
+
44
+ You may convey a covered work under sections 3 and 4 of this License
45
+ without being bound by section 3 of the GNU GPL.
46
+
47
+ 2. Conveying Modified Versions.
48
+
49
+ If you modify a copy of the Library, and, in your modifications, a
50
+ facility refers to a function or data to be supplied by an Application
51
+ that uses the facility (other than as an argument passed when the
52
+ facility is invoked), then you may convey a copy of the modified
53
+ version:
54
+
55
+ a) under this License, provided that you make a good faith effort to
56
+ ensure that, in the event an Application does not supply the
57
+ function or data, the facility still operates, and performs
58
+ whatever part of its purpose remains meaningful, or
59
+
60
+ b) under the GNU GPL, with none of the additional permissions of
61
+ this License applicable to that copy.
62
+
63
+ 3. Object Code Incorporating Material from Library Header Files.
64
+
65
+ The object code form of an Application may incorporate material from
66
+ a header file that is part of the Library. You may convey such object
67
+ code under terms of your choice, provided that, if the incorporated
68
+ material is not limited to numerical parameters, data structure
69
+ layouts and accessors, or small macros, functions and templates (ten
70
+ or fewer lines in length), you do both of the following:
71
+
72
+ a) Give prominent notice with each copy of the object code that the
73
+ Library is used in it and that the Library and its use are covered
74
+ by this License.
75
+
76
+ b) Accompany the object code with a copy of the GNU GPL and this license
77
+ document.
78
+
79
+ 4. Combined Works.
80
+
81
+ You may convey a Combined Work under terms of your choice that,
82
+ taken together, effectively do not restrict modification of the
83
+ portions of the Library contained in the Combined Work and reverse
84
+ engineering for debugging such modifications, if you also do each of
85
+ the following:
86
+
87
+ a) Give prominent notice with each copy of the Combined Work that
88
+ the Library is used in it and that the Library and its use are
89
+ covered by this License.
90
+
91
+ b) Accompany the Combined Work with a copy of the GNU GPL and this license
92
+ document.
93
+
94
+ c) For a Combined Work that displays copyright notices during
95
+ execution, include the copyright notice for the Library among
96
+ these notices, as well as a reference directing the user to the
97
+ copies of the GNU GPL and this license document.
98
+
99
+ d) Do one of the following:
100
+
101
+ 0) Convey the Minimal Corresponding Source under the terms of this
102
+ License, and the Corresponding Application Code in a form
103
+ suitable for, and under terms that permit, the user to
104
+ recombine or relink the Application with a modified version of
105
+ the Linked Version to produce a modified Combined Work, in the
106
+ manner specified by section 6 of the GNU GPL for conveying
107
+ Corresponding Source.
108
+
109
+ 1) Use a suitable shared library mechanism for linking with the
110
+ Library. A suitable mechanism is one that (a) uses at run time
111
+ a copy of the Library already present on the user's computer
112
+ system, and (b) will operate properly with a modified version
113
+ of the Library that is interface-compatible with the Linked
114
+ Version.
115
+
116
+ e) Provide Installation Information, but only if you would otherwise
117
+ be required to provide such information under section 6 of the
118
+ GNU GPL, and only to the extent that such information is
119
+ necessary to install and execute a modified version of the
120
+ Combined Work produced by recombining or relinking the
121
+ Application with a modified version of the Linked Version. (If
122
+ you use option 4d0, the Installation Information must accompany
123
+ the Minimal Corresponding Source and Corresponding Application
124
+ Code. If you use option 4d1, you must provide the Installation
125
+ Information in the manner specified by section 6 of the GNU GPL
126
+ for conveying Corresponding Source.)
127
+
128
+ 5. Combined Libraries.
129
+
130
+ You may place library facilities that are a work based on the
131
+ Library side by side in a single library together with other library
132
+ facilities that are not Applications and are not covered by this
133
+ License. Such a combined library, if distributed, must be subject to
134
+ this License for the portions of the combined library that are based
135
+ on the Library, and the other library facilities combined with it must
136
+ be subject to terms that permit the user to relink the combined
137
+ library with a modified version of the Library.
138
+
139
+ 6. Revised Versions of the GNU Lesser General Public License.
140
+
141
+ The Free Software Foundation may publish revised and/or new versions
142
+ of the GNU Lesser General Public License from time to time. Such new
143
+ versions will be similar in spirit to the present version, but may
144
+ differ in detail to address new problems or concerns.
145
+
146
+ Each version is given a distinguishing version number. If the
147
+ Library as you received it specifies that a certain numbered version
148
+ of the GNU Lesser General Public License "or any later version"
149
+ applies to it, you have the option of following the terms and
150
+ conditions either of that published version or of any later version
151
+ published by the Free Software Foundation. If the Library as you
152
+ received it does not specify a version number of the GNU Lesser
153
+ General Public License, you may choose any version of the GNU Lesser
154
+ General Public License ever published by the Free Software Foundation.
155
+
156
+ If the Library as you received it specifies that a proxy can decide
157
+ whether future versions of the GNU Lesser General Public License shall
158
+ apply, that proxy's public statement of acceptance of any version is
159
+ permanent authorization for you to choose that version for the
160
+ Library.
package/README.md CHANGED
@@ -1,226 +1,251 @@
1
- # dshloader
2
-
3
- [English](#english) | [中文](README.zh-CN.md)
4
-
5
- ---
6
-
7
- ## English
8
-
9
- A runtime compatibility shim for **dsh** (DeepSeek Harness) cordis bundle
10
- plugins. dshloader decouples third-party plugins from dsh's internal service
11
- names, module paths, package names, and RPC details through a version-aware
12
- **adapter registry**, so that when dsh upgrades and breaks internal APIs, you
13
- only upgrade dshloader — plugins keep working unchanged.
14
-
15
- ### Why
16
-
17
- dsh is moving fast and its internal surface changes between releases:
18
-
19
- - `httpServer` was renamed to `webServer` — old plugins that inject
20
- `httpServer` hang forever.
21
- - Deep source imports like
22
- `@deepseek-ai/dsh-client-runtime/src/client/sessions/context-provenance.ts`
23
- break when dsh ships no `src/`.
24
- - Client UI packages like `@deepseek-ai/dsh-client-ui-primitives` could be
25
- renamed in future dsh versions, breaking every plugin that imports them
26
- directly.
27
- - The official `dsh-host-apiproxy` hardcodes a settings namespace whitelist,
28
- so third-party settings cards never appear in the Web UI.
29
-
30
- dshloader absorbs these (and future) breaks behind a **stable API**:
31
- `ctx.dshLoader` on the host, `window.__dshLoader__` in the browser, and
32
- `@dsh-plugin/dsh-loader/*` stable subpaths for package imports.
33
-
34
- ### Quick start
35
-
36
- #### 1. Install dshloader into a profile
37
-
38
- ```sh
39
- dsh plugin --profile <name> add /path/to/dshloader
40
- # or
41
- DSH_HOME=~/.dsh npx dshloader setup <name>
42
- ```
43
-
44
- #### 2. Plugin `package.json` only depend on dshloader
45
-
46
- ```json
47
- {
48
- "dependencies": {
49
- "@dsh-plugin/dsh-loader": "link:..."
50
- }
51
- }
52
- ```
53
-
54
- > **Plugins must NOT declare any `@deepseek-ai/*` dependency.** All dsh
55
- > packages are accessed through dshloader's stable subpaths.
56
-
57
- #### 3. Host side — use `ctx.dshLoader`
58
-
59
- ```js
60
- export const inject = ['dshLoader'];
61
-
62
- export async function apply(ctx) {
63
- // Settings: register a namespace
64
- const scope = ctx.dshLoader.settings.register('my-plugin', schema);
65
-
66
- // Web: register routes and WebSocket upgrades
67
- ctx.dshLoader.web.get('/api/my-plugin/status', (req, res) => res.json({ ok: true }));
68
- ctx.dshLoader.web.registerUpgrade({ path: '/ws/my-plugin', handler: fn });
69
-
70
- // Services: read cordis services
71
- const sessions = ctx.dshLoader.services.get('sessions');
72
- }
73
- ```
74
-
75
- #### 4. Import dsh packages via stable subpaths
76
-
77
- ```js
78
- // Host packages
79
- const { defineTool } = require('@dsh-plugin/dsh-loader/tools');
80
-
81
- // Client UI packages (in client bundle source)
82
- import { IconCloseFill14 } from '@dsh-plugin/dsh-loader/ui-primitives';
83
- ```
84
-
85
- **Stable subpath real dsh package mapping (dsh 1.x):**
86
-
87
- | Stable subpath | Real dsh package |
88
- |---|---|
89
- | `@dsh-plugin/dsh-loader/tools` | `@deepseek-ai/dsh-tools` |
90
- | `@dsh-plugin/dsh-loader/llm` | `@deepseek-ai/dsh-llm` |
91
- | `@dsh-plugin/dsh-loader/agent` | `@deepseek-ai/dsh-agent` |
92
- | `@dsh-plugin/dsh-loader/settings` | `@deepseek-ai/dsh-settings` |
93
- | `@dsh-plugin/dsh-loader/ui-primitives` | `@deepseek-ai/dsh-client-ui-primitives` |
94
- | `@dsh-plugin/dsh-loader/ui-slots` | `@deepseek-ai/dsh-client-ui-slots` |
95
- | `@dsh-plugin/dsh-loader/ui-settings` | `@deepseek-ai/dsh-client-ui-settings/client` |
96
- | `@dsh-plugin/dsh-loader/web-react` | `@deepseek-ai/dsh-client-web-react` |
97
- | `@dsh-plugin/dsh-loader/schema-form` | `@deepseek-ai/dsh-client-schema-form` |
98
- | `@dsh-plugin/dsh-loader/runtime` | `@deepseek-ai/dsh-client-runtime/client` |
99
-
100
- When dsh renames a package, only the dshloader adapter changes — plugin
101
- source and bundle stay the same.
102
-
103
- #### 5. Client side — use `window.__dshLoader__`
104
-
105
- ```js
106
- // Read cordis client services
107
- const conv = window.__dshLoader__.services.get('conversation');
108
-
109
- // Register a package alias at runtime (fallback)
110
- window.__dshLoader__.registerPackageAlias('@old/pkg', '@new/pkg');
111
- ```
112
-
113
- #### 6. Build config — mark stable subpaths as external
114
-
115
- ```ts
116
- const CLIENT_EXTERNALS = [
117
- 'react', 'react/jsx-runtime', 'react-dom', 'react-dom/client', 'cordis',
118
- '@dsh-plugin/dsh-loader/ui-primitives',
119
- '@dsh-plugin/dsh-loader/ui-slots',
120
- '@dsh-plugin/dsh-loader/ui-settings',
121
- '@dsh-plugin/dsh-loader/web-react',
122
- '@dsh-plugin/dsh-loader/schema-form',
123
- '@dsh-plugin/dsh-loader/runtime',
124
- ]
125
- ```
126
-
127
- ### How it works
128
-
129
- ```
130
- plugin ──▶ ctx.dshLoader.{settings,web,services} ──▶ dshloader adapter
131
-
132
-
133
- real dsh (current version)
134
-
135
- plugin bundle ──▶ require('@dsh-plugin/dsh-loader/ui-primitives')
136
-
137
- ▼ (__ModuleLoader__ wrapper maps stable name)
138
- require('@deepseek-ai/dsh-client-ui-primitives')
139
-
140
-
141
- dsh module table
142
- ```
143
-
144
- 1. **Version detection** reads `node_modules/@deepseek-ai/dsh/package.json`
145
- (or `DSHLOADER_DSH_VERSION` for tests/override).
146
- 2. **AdapterRegistry** selects the best adapter for the detected version
147
- (exact range nearest-low fallback → clear error).
148
- 3. The selected **adapter** registers service aliases, installs package-name
149
- mapping hooks (host: `Module._resolveFilename`; client:
150
- `__ModuleLoader__.load` wrapper), and (only when opted in) the settings
151
- whitelist bypass bridge. All registrations use `ctx.reflect.provide` /
152
- `ctx.effect`, so cordis auto-recycles them on fiber unload.
153
-
154
- > **Load order does not matter.** cordis is reactive dependency injection:
155
- > plugins declaring `inject: [...]` stay `PENDING` until the alias is
156
- > provided, regardless of where dshloader sits in `cordis.patch.yml`.
157
-
158
- ### Settings whitelist bypass (`exposeAllNamespaces`)
159
-
160
- By default dshloader **does not** bypass the official settings namespace
161
- whitelist. Opt in explicitly:
162
-
163
- - env: `DSHLOADER_EXPOSE_ALL_SETTINGS=1`
164
- - profile `package.json`: `dsh.dshloader.exposeAllNamespaces: true`
165
-
166
- > **Security trade-off**: enabling this removes the official default-deny
167
- > boundary for browser settings access. Only enable it in profiles where you
168
- > trust every installed plugin.
169
-
170
- ### CLI
171
-
172
- ```
173
- dshloader setup <profile> Inject dshloader into a profile (dep + patch).
174
- dshloader dump-config <profile> Run `dsh --profile <name> --dump-config`.
175
- dshloader info [profile] Print loader version, detected dsh version,
176
- selected adapter.
177
- ```
178
-
179
- ### Rollback / disable
180
-
181
- - Disable per launch: `DSHLOADER_DISABLE=1 dsh web`
182
- - Remove: `dsh plugin --profile <name> rm @dsh-plugin/dsh-loader`
183
-
184
- ### Project layout
185
-
186
- ```
187
- src/
188
- index.js host bundle entry (name / inject / apply)
189
- client.js client bundle entry (immediately tier)
190
- api.js DshLoaderHostAPI construction
191
- registry.js AdapterRegistry + version detection
192
- version.js loader version + log prefix
193
- stable/ stable subpath re-exports (ui-primitives, tools, ...)
194
- services/
195
- settings.js settings stable API
196
- web.js web stable API
197
- services.js services stable API (get / alias)
198
- adapters/
199
- dsh-1-x.js dsh 1.x adapter
200
- index.js adapter registration
201
- setup.mjs profile injection + dump-config + info
202
- bin/dshloader.mjs CLI entry
203
- docs/
204
- api.md full API reference (Chinese)
205
- design.md design document (Chinese)
206
- tests/ L1 (unit) / module (L2) / integration (L3)
207
- examples/
208
- sample-plugin/ minimal example plugin
209
- dsh-aux-state/ example using ctx.dshLoader only
210
- ```
211
-
212
- ### Develop
213
-
214
- ```sh
215
- pnpm install
216
- npm test # all tests
217
- npm run test:l1 # unit
218
- npm run test:l2 # module
219
- npm run test:l3 # integration
220
- ```
221
-
222
- Node.js >= 18, `node --test`, no extra test framework.
223
-
224
- ### License
225
-
226
- BSD-3-Clause
1
+ <div align="center">
2
+
3
+ ![Banner](./docs/banner.png)
4
+
5
+ # dshloader
6
+
7
+ **A version-aware runtime compatibility shim that keeps third-party plugins working unchanged across dsh (DeepSeek Harness) upgrades.**
8
+
9
+ [English](#english) | [简体中文](README.zh_CN.md)
10
+
11
+ [![DSH Plugin](https://img.shields.io/badge/DeepSeek%20Harness-plugin-4f7cff)](https://github.com/topics/dsh-plugin)
12
+ <a href="https://github.com/dsh-plugins/dsh-loader/actions/workflows/npm-publish.yml">
13
+ <img src="https://github.com/dsh-plugins/dsh-loader/actions/workflows/npm-publish.yml/badge.svg" alt="Build Status">
14
+ </a>
15
+ <a href="https://www.npmjs.com/package/@dsh-plugin/dsh-loader">
16
+ <img src="https://img.shields.io/npm/v/@dsh-plugin/dsh-loader.svg?sanitize=true" alt="Version">
17
+ </a>
18
+ <a href="https://www.npmjs.com/package/@dsh-plugin/dsh-loader">
19
+ <img src="https://img.shields.io/npm/l/@dsh-plugin/dsh-loader.svg?sanitize=true" alt="License">
20
+ </a>
21
+
22
+ </div>
23
+
24
+ ## English
25
+
26
+ A runtime compatibility shim for **dsh** (DeepSeek Harness) cordis bundle
27
+ plugins. dshloader decouples third-party plugins from dsh's internal service
28
+ names, module paths, package names, and RPC details through a version-aware
29
+ **adapter registry**, so that when dsh upgrades and breaks internal APIs, you
30
+ only upgrade dshloader plugins keep working unchanged.
31
+
32
+ ### Why
33
+
34
+ dsh is moving fast and its internal surface changes between releases:
35
+
36
+ - `httpServer` was renamed to `webServer` — old plugins that inject
37
+ `httpServer` hang forever.
38
+ - Deep source imports like
39
+ `@deepseek-ai/dsh-client-runtime/src/client/sessions/context-provenance.ts`
40
+ break when dsh ships no `src/`.
41
+ - Client UI packages like `@deepseek-ai/dsh-client-ui-primitives` could be
42
+ renamed in future dsh versions, breaking every plugin that imports them
43
+ directly.
44
+ - The official `dsh-host-apiproxy` hardcodes a settings namespace whitelist,
45
+ so third-party settings cards never appear in the Web UI.
46
+
47
+ dshloader absorbs these (and future) breaks behind a **stable API**:
48
+ `ctx.dshLoader` on the host, `window.__dshLoader__` in the browser, and
49
+ `@dsh-plugin/dsh-loader/*` stable subpaths for package imports.
50
+
51
+ ### Quick start
52
+
53
+ #### 1. Install dshloader into a profile
54
+
55
+ ```sh
56
+ dsh plugin --profile <name> add /path/to/dshloader
57
+ # or
58
+ DSH_HOME=~/.dsh npx dshloader setup <name>
59
+ ```
60
+
61
+ #### 2. Plugin `package.json` — only depend on dshloader
62
+
63
+ ```json
64
+ {
65
+ "dependencies": {
66
+ "@dsh-plugin/dsh-loader": "link:..."
67
+ }
68
+ }
69
+ ```
70
+
71
+ > **Plugins must NOT declare any `@deepseek-ai/*` dependency.** All dsh
72
+ > packages are accessed through dshloader's stable subpaths.
73
+
74
+ #### 3. Host side — use `ctx.dshLoader`
75
+
76
+ ```js
77
+ export const inject = ['dshLoader'];
78
+
79
+ export async function apply(ctx) {
80
+ // Settings: register a namespace
81
+ const scope = ctx.dshLoader.settings.register('my-plugin', schema);
82
+
83
+ // Web: register routes and WebSocket upgrades
84
+ ctx.dshLoader.web.get('/api/my-plugin/status', (req, res) => res.json({ ok: true }));
85
+ ctx.dshLoader.web.registerUpgrade({ path: '/ws/my-plugin', handler: fn });
86
+
87
+ // Services: read cordis services
88
+ const sessions = ctx.dshLoader.services.get('sessions');
89
+ }
90
+ ```
91
+
92
+ #### 4. Import dsh packages via stable subpaths
93
+
94
+ ```js
95
+ // Host packages
96
+ const { defineTool } = require('@dsh-plugin/dsh-loader/tools');
97
+
98
+ // Client UI packages (in client bundle source)
99
+ import { IconCloseFill14 } from '@dsh-plugin/dsh-loader/ui-primitives';
100
+ ```
101
+
102
+ **Stable subpath → real dsh package mapping (dsh 1.x):**
103
+
104
+ | Stable subpath | Real dsh package |
105
+ |---|---|
106
+ | `@dsh-plugin/dsh-loader/tools` | `@deepseek-ai/dsh-tools` |
107
+ | `@dsh-plugin/dsh-loader/llm` | `@deepseek-ai/dsh-llm` |
108
+ | `@dsh-plugin/dsh-loader/agent` | `@deepseek-ai/dsh-agent` |
109
+ | `@dsh-plugin/dsh-loader/settings` | `@deepseek-ai/dsh-settings` |
110
+ | `@dsh-plugin/dsh-loader/ui-primitives` | `@deepseek-ai/dsh-client-ui-primitives` |
111
+ | `@dsh-plugin/dsh-loader/ui-slots` | `@deepseek-ai/dsh-client-ui-slots` |
112
+ | `@dsh-plugin/dsh-loader/ui-settings` | `@deepseek-ai/dsh-client-ui-settings/client` |
113
+ | `@dsh-plugin/dsh-loader/web-react` | `@deepseek-ai/dsh-client-web-react` |
114
+ | `@dsh-plugin/dsh-loader/schema-form` | `@deepseek-ai/dsh-client-schema-form` |
115
+ | `@dsh-plugin/dsh-loader/runtime` | `@deepseek-ai/dsh-client-runtime/client` |
116
+
117
+ When dsh renames a package, only the dshloader adapter changes — plugin
118
+ source and bundle stay the same.
119
+
120
+ #### 5. Client side — use `window.__dshLoader__`
121
+
122
+ ```js
123
+ // Read cordis client services
124
+ const conv = window.__dshLoader__.services.get('conversation');
125
+
126
+ // Register a package alias at runtime (fallback)
127
+ window.__dshLoader__.registerPackageAlias('@old/pkg', '@new/pkg');
128
+ ```
129
+
130
+ #### 6. Build config — mark stable subpaths as external
131
+
132
+ ```ts
133
+ const CLIENT_EXTERNALS = [
134
+ 'react', 'react/jsx-runtime', 'react-dom', 'react-dom/client', 'cordis',
135
+ '@dsh-plugin/dsh-loader/ui-primitives',
136
+ '@dsh-plugin/dsh-loader/ui-slots',
137
+ '@dsh-plugin/dsh-loader/ui-settings',
138
+ '@dsh-plugin/dsh-loader/web-react',
139
+ '@dsh-plugin/dsh-loader/schema-form',
140
+ '@dsh-plugin/dsh-loader/runtime',
141
+ ]
142
+ ```
143
+
144
+ ### How it works
145
+
146
+ ```
147
+ plugin ──▶ ctx.dshLoader.{settings,web,services} ──▶ dshloader adapter
148
+
149
+
150
+ real dsh (current version)
151
+
152
+ plugin bundle ──▶ require('@dsh-plugin/dsh-loader/ui-primitives')
153
+
154
+ (__ModuleLoader__ wrapper maps stable name)
155
+ require('@deepseek-ai/dsh-client-ui-primitives')
156
+
157
+
158
+ dsh module table
159
+ ```
160
+
161
+ 1. **Version detection** reads `node_modules/@deepseek-ai/dsh/package.json`
162
+ (or `DSHLOADER_DSH_VERSION` for tests/override).
163
+ 2. **AdapterRegistry** selects the best adapter for the detected version
164
+ (exact → range → nearest-low fallback clear error).
165
+ 3. The selected **adapter** registers service aliases, installs package-name
166
+ mapping hooks (host: `Module._resolveFilename`; client:
167
+ `__ModuleLoader__.load` wrapper), and (only when opted in) the settings
168
+ whitelist bypass bridge. All registrations use `ctx.reflect.provide` /
169
+ `ctx.effect`, so cordis auto-recycles them on fiber unload.
170
+
171
+ > **Load order does not matter.** cordis is reactive dependency injection:
172
+ > plugins declaring `inject: [...]` stay `PENDING` until the alias is
173
+ > provided, regardless of where dshloader sits in `cordis.patch.yml`.
174
+
175
+ ### Settings whitelist bypass (`exposeAllNamespaces`)
176
+
177
+ By default dshloader **does not** bypass the official settings namespace
178
+ whitelist. Opt in explicitly:
179
+
180
+ - env: `DSHLOADER_EXPOSE_ALL_SETTINGS=1`
181
+ - profile `package.json`: `dsh.dshloader.exposeAllNamespaces: true`
182
+
183
+ > **Security trade-off**: enabling this removes the official default-deny
184
+ > boundary for browser settings access. Only enable it in profiles where you
185
+ > trust every installed plugin.
186
+
187
+ ### CLI
188
+
189
+ ```
190
+ dshloader setup <profile> Inject dshloader into a profile (dep + patch).
191
+ dshloader dump-config <profile> Run `dsh --profile <name> --dump-config`.
192
+ dshloader info [profile] Print loader version, detected dsh version,
193
+ selected adapter.
194
+ ```
195
+
196
+ ### Rollback / disable
197
+
198
+ - Disable per launch: `DSHLOADER_DISABLE=1 dsh web`
199
+ - Remove: `dsh plugin --profile <name> rm @dsh-plugin/dsh-loader`
200
+
201
+ ### Project layout
202
+
203
+ ```
204
+ src/
205
+ index.ts host bundle entry (name / inject / apply)
206
+ client.ts client bundle entry (immediately tier)
207
+ api.ts DshLoaderHostAPI construction
208
+ registry.ts AdapterRegistry + version detection
209
+ types.ts shared host/client TypeScript types
210
+ version.ts loader version + log prefix
211
+ stable/ stable subpath re-exports (ui-primitives, tools, ...)
212
+ services/
213
+ settings.ts settings stable API
214
+ web.ts web stable API
215
+ services.ts services stable API (get / alias)
216
+ adapters/
217
+ dsh-1-x.ts dsh 1.x adapter
218
+ index.ts adapter registration
219
+ setup.ts profile injection + dump-config + info
220
+ bin/dshloader.mjs CLI entry
221
+ dist/ compiled host build (tsc output, git-ignored)
222
+ lib/ compiled client bundle (tsdown output, git-ignored)
223
+ tsconfig.json typecheck config
224
+ tsconfig.build.json host build config (emits dist/)
225
+ tsdown.client.config.mjs client bundle build config
226
+ docs/
227
+ api.md full API reference (Chinese)
228
+ design.md design document (Chinese)
229
+ tests/ L1 (unit) / module (L2) / integration (L3)
230
+ examples/
231
+ sample-plugin/ minimal example plugin
232
+ dsh-aux-state/ example using ctx.dshLoader only
233
+ ```
234
+
235
+ ### Develop
236
+
237
+ ```sh
238
+ pnpm install
239
+ npm run typecheck # type-check src/**/*.ts
240
+ npm run build # compile host (dist/) + client bundle (lib/)
241
+ npm test # all tests
242
+ npm run test:l1 # unit
243
+ npm run test:l2 # module
244
+ npm run test:l3 # integration
245
+ ```
246
+
247
+ Node.js >= 18, `node --test`, no extra test framework.
248
+
249
+ ### License
250
+
251
+ LGPL-3.0-only (GNU Lesser General Public License v3 only). See [LICENSE](./LICENSE).