dsh-tiered-plugin-go 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +18 -2
- package/cordis.patch.yml +3 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +413 -0
- package/dist/index.js.map +1 -0
- package/package.json +79 -4
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 dsh-tiered-plugin-menu 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.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
-
#
|
|
1
|
+
# DSH 分级配置 · dsh-go
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
dsh-go 原生 JSON 界面的分级菜单。依赖 `dsh-tiered-plugin-core`,在“分级配置”会话标签页或功能页中管理插件、MCP、Skill,以及本级/下级默认。
|
|
4
|
+
|
|
5
|
+
其他插件通过公开 `dshGo` 服务注册的面板、数据、动作、状态条、回合注释及能力事件,按当前会话转发给对应实例。同一插件的多个实例不会用同名面板覆盖对方。插件的数据目录和后端注册继续使用共享核心的隔离机制;没有按第三方插件名称编写适配。
|
|
6
|
+
|
|
7
|
+
安装 `dsh-tiered-plugin-go`,并启用 dsh-go 的原生桥接。菜单在桥接服务出现时加载。与 Web、TUI 共用同一 DSH 宿主时,共用一份核心。
|
|
8
|
+
|
|
9
|
+
配置用 JSON 表单编辑;手机宿主对输入和事件大小有限制,超过限制的配置应在 Web 中修改。原生插件贡献清单目前是包级别的,没有会话级隐藏接口,因此未启用范围仍可能看到入口;其视图会提示未启用,操作不会送往别的会话。
|
|
10
|
+
|
|
11
|
+
使用官方 SDK 和桥接源码完成了同名原生面板、不同会话配置、数据订阅清理、表单和动作校验。官方 dsh-go 1.0.15 APK 已在 Android 15 模拟器中实测,通过 SSH 连接隔离虚拟机内的 DSH rc.2:分级 Skill 编辑、会话 MCP、原生插件面板和动作、下级默认及 App/后端完整冷启动恢复通过,截图见仓库的 `docs/LIVE_UI_TESTING.md`。未测试物理手机或手机本地 PRoot 引擎。固定端口、直接绕过服务注册的共享外部状态仍不保证隔离。
|
|
12
|
+
|
|
13
|
+
MIT License。
|
|
14
|
+
|
|
15
|
+
## English
|
|
16
|
+
|
|
17
|
+
Native dsh-go tiered settings for plugins, MCP and Skills. The adapter routes public `dshGo` registrations to the instance selected for the current session, including views, actions and data feeds. Same-package contributions no longer overwrite another instance. The shared core owns backend isolation and configuration; no third-party plugin names are special-cased.
|
|
18
|
+
|
|
19
|
+
Requires the native bridge. Official SDK and bridge tests pass. Live testing with the official dsh-go 1.0.15 APK on an Android 15 emulator, using SSH to an isolated DSH rc.2 host, covered scoped Skill edits, session MCP, native plugin views/actions, child defaults and full App/backend cold restoration. Physical phones and local PRoot remain untested. The host's contribution inventory is package-wide, so an inactive scope may still show an entry with an inactive message. JSON input limits apply; edit oversized configurations in Web. Fixed ports and external state bypassing host services are not isolated.
|
package/cordis.patch.yml
ADDED
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { Config, inject, tieredManagerFrontend } from "dsh-tiered-plugin-core";
|
|
2
|
+
import { Context } from "@deepseek-ai/cordis";
|
|
3
|
+
export declare const name = "tiered-plugin-go";
|
|
4
|
+
export declare function apply(ctx: Context, config: {
|
|
5
|
+
dataFile?: string;
|
|
6
|
+
}): Promise<void>;
|
|
7
|
+
export { Config, inject, tieredManagerFrontend };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
import { Config, acquireCore, inject, registrationOwner, tieredManagerFrontend } from "dsh-tiered-plugin-core";
|
|
2
|
+
import { MenuModel, levelLabel } from "dsh-tiered-plugin-core/model";
|
|
3
|
+
import { ownScope } from "dsh-tiered-plugin-core/shared";
|
|
4
|
+
// packages/dsh-go/src/routing.ts
|
|
5
|
+
/** Route public dshGo registrations; unrelated service operations stay native. */
|
|
6
|
+
function installNativeRouting(ctx, manager) {
|
|
7
|
+
const service = ctx.get("dshGo");
|
|
8
|
+
const groups = /* @__PURE__ */ new Map();
|
|
9
|
+
const originals = /* @__PURE__ */ new Map();
|
|
10
|
+
const feeds = /* @__PURE__ */ new Set();
|
|
11
|
+
if (manager) ctx.effect(() => manager.onInstancesChanged(async () => {
|
|
12
|
+
for (const refresh of feeds) await refresh();
|
|
13
|
+
}));
|
|
14
|
+
const pick = (group, scope) => group.entries.find((entry) => scope.sessionId ? entry.owner.accepts(scope.sessionId) : entry.owner.scope.level === "client");
|
|
15
|
+
const unavailable = () => ({ toast: "此会话未启用该插件" });
|
|
16
|
+
for (const method of [
|
|
17
|
+
"panel",
|
|
18
|
+
"strip",
|
|
19
|
+
"turnNote",
|
|
20
|
+
"on",
|
|
21
|
+
"media",
|
|
22
|
+
"micro",
|
|
23
|
+
"onCapability"
|
|
24
|
+
]) {
|
|
25
|
+
const original = service[method];
|
|
26
|
+
if (!original) continue;
|
|
27
|
+
originals.set(method, original);
|
|
28
|
+
service[method] = function(...args) {
|
|
29
|
+
const caller = this.ctx;
|
|
30
|
+
const owner = registrationOwner(caller);
|
|
31
|
+
if (!owner) return original.apply(this, args);
|
|
32
|
+
const [id, value] = method === "onCapability" ? ["events", args[0]] : args;
|
|
33
|
+
const key = `${owner.package}\0${method}\0${id}`;
|
|
34
|
+
let group = groups.get(key);
|
|
35
|
+
if (!group) {
|
|
36
|
+
group = {
|
|
37
|
+
entries: [],
|
|
38
|
+
actions: {}
|
|
39
|
+
};
|
|
40
|
+
groups.set(key, group);
|
|
41
|
+
}
|
|
42
|
+
const selected = (scope) => pick(group, scope)?.value;
|
|
43
|
+
const data = async (scope, emit, caps) => {
|
|
44
|
+
let current, cancel, live = true, started = false;
|
|
45
|
+
const refresh = async () => {
|
|
46
|
+
const entry = pick(group, scope);
|
|
47
|
+
if (started && current === entry) return;
|
|
48
|
+
current = entry;
|
|
49
|
+
cancel?.();
|
|
50
|
+
cancel = void 0;
|
|
51
|
+
if (started && group.entries.length) service.refresh.call({ ctx: group.entries[0].ctx }, id, scope);
|
|
52
|
+
started = true;
|
|
53
|
+
emit(null);
|
|
54
|
+
const def = entry?.value;
|
|
55
|
+
const fn = typeof def === "function" ? def : def?.data;
|
|
56
|
+
if (!fn) return;
|
|
57
|
+
const stop = await fn(scope, (value) => {
|
|
58
|
+
if (live && current === entry && pick(group, scope) === entry) emit(value);
|
|
59
|
+
}, caps);
|
|
60
|
+
if (live && current === entry) cancel = stop;
|
|
61
|
+
else stop?.();
|
|
62
|
+
};
|
|
63
|
+
feeds.add(refresh);
|
|
64
|
+
try {
|
|
65
|
+
await refresh();
|
|
66
|
+
} catch (error) {
|
|
67
|
+
feeds.delete(refresh);
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
return () => {
|
|
71
|
+
live = false;
|
|
72
|
+
feeds.delete(refresh);
|
|
73
|
+
cancel?.();
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
const mount = () => {
|
|
77
|
+
if (!group.entries.length) {
|
|
78
|
+
group.dispose?.();
|
|
79
|
+
group.dispose = void 0;
|
|
80
|
+
groups.delete(key);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
const actions = new Set(group.entries.flatMap((entry) => Object.keys(entry.value.actions ?? {})));
|
|
84
|
+
for (const key of Object.keys(group.actions)) if (!actions.has(key)) delete group.actions[key];
|
|
85
|
+
for (const action of actions) group.actions[action] ??= (scope, event) => {
|
|
86
|
+
const handler = selected(scope)?.actions?.[action];
|
|
87
|
+
return handler ? handler(scope, event) : unavailable();
|
|
88
|
+
};
|
|
89
|
+
if (group.dispose) return;
|
|
90
|
+
let routed;
|
|
91
|
+
if (method === "panel") routed = {
|
|
92
|
+
view: (scope, caps) => {
|
|
93
|
+
const def = selected(scope);
|
|
94
|
+
return typeof def?.view === "function" ? def.view(scope, caps) : def?.view ?? {
|
|
95
|
+
v: 1,
|
|
96
|
+
type: "text",
|
|
97
|
+
text: "此会话未启用该插件"
|
|
98
|
+
};
|
|
99
|
+
},
|
|
100
|
+
data,
|
|
101
|
+
actions: group.actions
|
|
102
|
+
};
|
|
103
|
+
else if ([
|
|
104
|
+
"strip",
|
|
105
|
+
"turnNote",
|
|
106
|
+
"micro"
|
|
107
|
+
].includes(method)) routed = { data };
|
|
108
|
+
else routed = (scope, event) => {
|
|
109
|
+
const handler = selected(scope);
|
|
110
|
+
if (handler) return handler(scope, event);
|
|
111
|
+
if (method === "media") throw new Error("此会话未启用该插件");
|
|
112
|
+
return method === "onCapability" ? void 0 : unavailable();
|
|
113
|
+
};
|
|
114
|
+
const registration = caller.extend({ effect: ctx.effect.bind(ctx) });
|
|
115
|
+
group.dispose = original.call({ ctx: registration }, ...method === "onCapability" ? [routed] : [id, routed]);
|
|
116
|
+
};
|
|
117
|
+
return caller.effect(() => {
|
|
118
|
+
const entry = {
|
|
119
|
+
ctx: caller,
|
|
120
|
+
owner,
|
|
121
|
+
value
|
|
122
|
+
};
|
|
123
|
+
group.entries.push(entry);
|
|
124
|
+
mount();
|
|
125
|
+
return () => {
|
|
126
|
+
group.entries.splice(group.entries.indexOf(entry), 1);
|
|
127
|
+
mount();
|
|
128
|
+
};
|
|
129
|
+
});
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
ctx.effect(() => () => {
|
|
133
|
+
for (const [method, original] of originals) service[method] = original;
|
|
134
|
+
for (const group of groups.values()) group.dispose?.();
|
|
135
|
+
groups.clear();
|
|
136
|
+
feeds.clear();
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
// packages/dsh-go/src/menu.ts
|
|
140
|
+
const button = (label, id, args = {}) => ({
|
|
141
|
+
label,
|
|
142
|
+
action: {
|
|
143
|
+
id,
|
|
144
|
+
args
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
const buttons = (...items) => ({
|
|
148
|
+
type: "actions",
|
|
149
|
+
items
|
|
150
|
+
});
|
|
151
|
+
const text = (value) => ({
|
|
152
|
+
type: "text",
|
|
153
|
+
text: value
|
|
154
|
+
});
|
|
155
|
+
const pageSize = 5;
|
|
156
|
+
function mountMenu(ctx, manager) {
|
|
157
|
+
const bridge = ctx.get("dshGo");
|
|
158
|
+
const menus = /* @__PURE__ */ new Map();
|
|
159
|
+
const menu = (scope) => {
|
|
160
|
+
const key = scope.sessionId ?? "";
|
|
161
|
+
let value = menus.get(key);
|
|
162
|
+
if (!value) {
|
|
163
|
+
value = {
|
|
164
|
+
model: new MenuModel(manager, scope.sessionId ?? null),
|
|
165
|
+
page: 0,
|
|
166
|
+
scopePage: 0,
|
|
167
|
+
json: "{}",
|
|
168
|
+
notice: "",
|
|
169
|
+
emitters: /* @__PURE__ */ new Set()
|
|
170
|
+
};
|
|
171
|
+
menus.set(key, value);
|
|
172
|
+
}
|
|
173
|
+
return value;
|
|
174
|
+
};
|
|
175
|
+
const changed = (scope, refresh = true) => {
|
|
176
|
+
const state = menu(scope);
|
|
177
|
+
for (const emit of state.emitters) emit({
|
|
178
|
+
form: { json: state.json },
|
|
179
|
+
nav: { scope: JSON.stringify(ownScope(state.model.selection.scope)) }
|
|
180
|
+
});
|
|
181
|
+
if (refresh) bridge.refresh("menu", scope);
|
|
182
|
+
};
|
|
183
|
+
async function view(scope) {
|
|
184
|
+
const state = menu(scope);
|
|
185
|
+
const { model } = state;
|
|
186
|
+
const { scope: target, kind, component } = model.selection;
|
|
187
|
+
const children = [text(`${levelLabel(target)} · ${target.children ? "下级默认" : "本级"}`)];
|
|
188
|
+
const scopes = model.scopes();
|
|
189
|
+
children.push({
|
|
190
|
+
type: "select",
|
|
191
|
+
label: "配置层级",
|
|
192
|
+
bind: "data.nav.scope",
|
|
193
|
+
value: JSON.stringify(ownScope(target)),
|
|
194
|
+
options: scopes.slice(state.scopePage * 24, (state.scopePage + 1) * 24).map((item) => ({
|
|
195
|
+
label: item.label,
|
|
196
|
+
value: JSON.stringify(item.scope)
|
|
197
|
+
})),
|
|
198
|
+
onChange: "scope"
|
|
199
|
+
});
|
|
200
|
+
if (scopes.length > 24) children.push(buttons(button("上一组层级", "scopePage", { value: -1 }), button("下一组层级", "scopePage", { value: 1 })));
|
|
201
|
+
children.push(buttons(button("本级", "children", { value: false }), button("下级", "children", { value: true })));
|
|
202
|
+
children.push(buttons(...[
|
|
203
|
+
"plugin",
|
|
204
|
+
"mcp",
|
|
205
|
+
"skill"
|
|
206
|
+
].map((value, i) => button([
|
|
207
|
+
"插件",
|
|
208
|
+
"MCP",
|
|
209
|
+
"Skill"
|
|
210
|
+
][i], "kind", { value }))));
|
|
211
|
+
if (target.level === "client" && !target.children) {
|
|
212
|
+
const settings = manager.settings();
|
|
213
|
+
children.push(buttons(button(`工作区树继承:${settings.inheritWorkspaceTree ? "开" : "关"}`, "tree"), button(`插件隔离(实验性):${settings.pluginIsolation ? "开" : "关"}`, "isolation")));
|
|
214
|
+
children.push(text("插件隔离重启 DSH 后生效;可能修复冲突,也可能带来新的兼容性问题。"));
|
|
215
|
+
}
|
|
216
|
+
if (target.children) {
|
|
217
|
+
const independent = manager.childSettings(ownScope(target)).independent;
|
|
218
|
+
children.push(text(independent ? "下级默认:独立" : "下级默认:继承"));
|
|
219
|
+
children.push(buttons(button("继承", "policy", { value: false }), button("独立", "policy", { value: true })));
|
|
220
|
+
}
|
|
221
|
+
if (state.notice) children.push(text(state.notice));
|
|
222
|
+
if (model.pending) {
|
|
223
|
+
const plan = model.pending;
|
|
224
|
+
children.push(text([...plan.dependencies.map((item) => `${item.mode === "on" ? "启用" : "关闭"}依赖:${item.name}`), ...plan.unverified.length ? ["这些插件尚未声明自兼容性,确认在本级启用?"] : []].join("\n")));
|
|
225
|
+
children.push(buttons(button("确认执行", "confirm"), button("取消", "cancel")));
|
|
226
|
+
return {
|
|
227
|
+
v: 2,
|
|
228
|
+
type: "stack",
|
|
229
|
+
children
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
if (state.edit) {
|
|
233
|
+
children.push(text(state.edit === "$new-mcp" ? "添加 MCP" : "编辑配置(JSON)"));
|
|
234
|
+
children.push({
|
|
235
|
+
type: "form",
|
|
236
|
+
submit: "save",
|
|
237
|
+
submitLabel: "保存",
|
|
238
|
+
children: [{
|
|
239
|
+
type: "textField",
|
|
240
|
+
label: "配置 JSON",
|
|
241
|
+
bind: "data.form.json",
|
|
242
|
+
multiline: true,
|
|
243
|
+
maxLines: 8,
|
|
244
|
+
maxLength: 2e3
|
|
245
|
+
}]
|
|
246
|
+
});
|
|
247
|
+
children.push(buttons(button("返回", "back")));
|
|
248
|
+
return {
|
|
249
|
+
v: 2,
|
|
250
|
+
type: "stack",
|
|
251
|
+
children
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
if (component) children.push(buttons(button("返回插件列表", "back")));
|
|
255
|
+
const rows = await model.rows();
|
|
256
|
+
state.page = Math.min(state.page, Math.max(0, Math.ceil(rows.length / pageSize) - 1));
|
|
257
|
+
const disabled = target.children && !manager.childSettings(ownScope(target)).independent;
|
|
258
|
+
for (const row of rows.slice(state.page * pageSize, (state.page + 1) * pageSize)) {
|
|
259
|
+
children.push(text(`${row.name} · ${row.own ? row.enabled ? "启用" : "关闭" : "继承"}`));
|
|
260
|
+
if (!disabled) children.push(buttons(...[
|
|
261
|
+
"inherit",
|
|
262
|
+
"on",
|
|
263
|
+
"off"
|
|
264
|
+
].filter((mode) => mode !== "inherit" || target.level !== "client" || target.children).map((mode) => button({
|
|
265
|
+
inherit: "继承",
|
|
266
|
+
on: "启用",
|
|
267
|
+
off: "关闭"
|
|
268
|
+
}[mode], "change", {
|
|
269
|
+
id: row.id,
|
|
270
|
+
mode
|
|
271
|
+
}))));
|
|
272
|
+
if (row.components) children.push(buttons(button("组件", "components", { id: row.id })));
|
|
273
|
+
else if (!disabled && row.own && row.enabled) children.push(buttons(button("设置", "edit", { id: row.id })));
|
|
274
|
+
}
|
|
275
|
+
if (!rows.length) children.push(text("此范围没有可配置的项目"));
|
|
276
|
+
children.push(buttons(button("上一页", "page", { value: -1 }), button(`${state.page + 1} / ${Math.max(1, Math.ceil(rows.length / pageSize))}`, "refresh"), button("下一页", "page", { value: 1 })));
|
|
277
|
+
if (kind === "mcp" && !disabled) children.push(buttons(button("添加 MCP", "add")));
|
|
278
|
+
return {
|
|
279
|
+
v: 2,
|
|
280
|
+
type: "stack",
|
|
281
|
+
children
|
|
282
|
+
};
|
|
283
|
+
}
|
|
284
|
+
const run = (action, deferred = true) => (scope, event) => {
|
|
285
|
+
const result = async () => {
|
|
286
|
+
const state = menu(scope);
|
|
287
|
+
try {
|
|
288
|
+
await action(state, event.value ?? {});
|
|
289
|
+
state.notice = "";
|
|
290
|
+
changed(scope, deferred);
|
|
291
|
+
return deferred ? { toast: "已更新" } : { refresh: true };
|
|
292
|
+
} catch (error) {
|
|
293
|
+
state.notice = String(error);
|
|
294
|
+
changed(scope, deferred);
|
|
295
|
+
return deferred ? { toast: String(error).slice(0, 180) } : { refresh: true };
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
return deferred ? {
|
|
299
|
+
pending: {
|
|
300
|
+
label: "正在处理",
|
|
301
|
+
timeoutMs: 6e4
|
|
302
|
+
},
|
|
303
|
+
result
|
|
304
|
+
} : result();
|
|
305
|
+
};
|
|
306
|
+
bridge.panel("menu", {
|
|
307
|
+
view,
|
|
308
|
+
data(scope, emit) {
|
|
309
|
+
const state = menu(scope);
|
|
310
|
+
state.emitters.add(emit);
|
|
311
|
+
emit({
|
|
312
|
+
form: { json: state.json },
|
|
313
|
+
nav: { scope: JSON.stringify(ownScope(state.model.selection.scope)) }
|
|
314
|
+
});
|
|
315
|
+
return () => {
|
|
316
|
+
state.emitters.delete(emit);
|
|
317
|
+
};
|
|
318
|
+
},
|
|
319
|
+
actions: {
|
|
320
|
+
scope: run((s, v) => {
|
|
321
|
+
s.model.select({
|
|
322
|
+
...s.model.selection,
|
|
323
|
+
scope: JSON.parse(v.value),
|
|
324
|
+
component: void 0
|
|
325
|
+
});
|
|
326
|
+
s.page = 0;
|
|
327
|
+
s.edit = void 0;
|
|
328
|
+
}, false),
|
|
329
|
+
scopePage: run((s, v) => {
|
|
330
|
+
s.scopePage = Math.max(0, Math.min(Math.ceil(s.model.scopes().length / 24) - 1, s.scopePage + v.value));
|
|
331
|
+
}, false),
|
|
332
|
+
children: run((s, v) => {
|
|
333
|
+
s.model.select({
|
|
334
|
+
...s.model.selection,
|
|
335
|
+
scope: {
|
|
336
|
+
...ownScope(s.model.selection.scope),
|
|
337
|
+
children: !!v.value
|
|
338
|
+
}
|
|
339
|
+
});
|
|
340
|
+
s.edit = void 0;
|
|
341
|
+
}),
|
|
342
|
+
kind: run((s, v) => {
|
|
343
|
+
s.model.select({
|
|
344
|
+
...s.model.selection,
|
|
345
|
+
kind: v.value,
|
|
346
|
+
component: void 0
|
|
347
|
+
});
|
|
348
|
+
s.page = 0;
|
|
349
|
+
s.edit = void 0;
|
|
350
|
+
}),
|
|
351
|
+
policy: run((s, v) => s.model.children(!!v.value)),
|
|
352
|
+
tree: run(() => manager.setWorkspaceTreeInheritance(!manager.settings().inheritWorkspaceTree)),
|
|
353
|
+
isolation: run(() => manager.setPluginIsolation(!manager.settings().pluginIsolation)),
|
|
354
|
+
change: run((s, v) => s.model.change(v.id, v.mode)),
|
|
355
|
+
confirm: run((s) => s.model.confirm()),
|
|
356
|
+
cancel: run((s) => {
|
|
357
|
+
s.model.pending = void 0;
|
|
358
|
+
}),
|
|
359
|
+
components: run((s, v) => {
|
|
360
|
+
s.model.select({
|
|
361
|
+
...s.model.selection,
|
|
362
|
+
component: v.id
|
|
363
|
+
});
|
|
364
|
+
s.page = 0;
|
|
365
|
+
}),
|
|
366
|
+
edit: run(async (s, v) => {
|
|
367
|
+
const json = JSON.stringify(await s.model.config(v.id), null, 2);
|
|
368
|
+
if ([...json].length > 2e3 || Buffer.byteLength(JSON.stringify({ values: { "data.form.json": json } })) > 3800) throw new Error("配置超过手机输入限制,请在 Web 菜单编辑");
|
|
369
|
+
s.json = json;
|
|
370
|
+
s.edit = v.id;
|
|
371
|
+
}),
|
|
372
|
+
add: run((s) => {
|
|
373
|
+
s.edit = "$new-mcp";
|
|
374
|
+
s.json = JSON.stringify({
|
|
375
|
+
serverName: "my-server",
|
|
376
|
+
transport: "stdio",
|
|
377
|
+
command: "node",
|
|
378
|
+
args: []
|
|
379
|
+
}, null, 2);
|
|
380
|
+
}),
|
|
381
|
+
save: run(async (s, v) => {
|
|
382
|
+
const json = v.values["data.form.json"];
|
|
383
|
+
if (s.edit === "$new-mcp") await s.model.addMcp(json);
|
|
384
|
+
else await s.model.save(s.edit, json);
|
|
385
|
+
s.edit = void 0;
|
|
386
|
+
}),
|
|
387
|
+
back: run((s) => {
|
|
388
|
+
if (s.edit) s.edit = void 0;
|
|
389
|
+
else s.model.select({
|
|
390
|
+
...s.model.selection,
|
|
391
|
+
component: void 0
|
|
392
|
+
});
|
|
393
|
+
}),
|
|
394
|
+
page: run((s, v) => {
|
|
395
|
+
s.page = Math.max(0, s.page + v.value);
|
|
396
|
+
}),
|
|
397
|
+
refresh: run(() => {})
|
|
398
|
+
}
|
|
399
|
+
});
|
|
400
|
+
ctx.effect(() => () => menus.clear());
|
|
401
|
+
}
|
|
402
|
+
// packages/dsh-go/src/index.ts
|
|
403
|
+
const name = "tiered-plugin-go";
|
|
404
|
+
async function apply(ctx, config) {
|
|
405
|
+
const manager = await acquireCore(ctx, config);
|
|
406
|
+
await manager.adaptService("dshGo", installNativeRouting);
|
|
407
|
+
ctx.inject(["dshGo"], (child) => {
|
|
408
|
+
mountMenu(child, manager);
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
export { Config, apply, inject, name, tieredManagerFrontend };
|
|
412
|
+
|
|
413
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/routing.ts","../src/menu.ts","../src/index.ts"],"sourcesContent":["import type { Context } from '@deepseek-ai/cordis'\nimport { registrationOwner, type RegistrationOwner, type PluginManager } from 'dsh-tiered-plugin-core'\n\ninterface Scope { sessionId?: string }\ntype Callback = (...args: any[]) => any\ntype Definition = Callback | { view: unknown; data?: Callback; actions?: Record<string, Callback> }\ninterface Entry { ctx: Context; owner: RegistrationOwner; value: Definition }\ninterface Group { entries: Entry[]; actions: Record<string, Callback>; dispose?: () => void }\n\n/** Route public dshGo registrations; unrelated service operations stay native. */\nexport function installNativeRouting(ctx: Context, manager?: PluginManager): void {\n const service = ctx.get('dshGo') as any\n const groups = new Map<string, Group>()\n const originals = new Map<string, Callback>()\n const feeds = new Set<() => Promise<void>>()\n if (manager) ctx.effect(() => manager.onInstancesChanged(async () => {\n for (const refresh of feeds) await refresh()\n }))\n const pick = (group: Group, scope: Scope) => group.entries.find(entry => scope.sessionId\n ? entry.owner.accepts(scope.sessionId) : entry.owner.scope.level === 'client')\n const unavailable = () => ({ toast: '此会话未启用该插件' })\n for (const method of ['panel', 'strip', 'turnNote', 'on', 'media', 'micro', 'onCapability']) {\n const original = service[method] as Callback | undefined\n if (!original) continue\n originals.set(method, original)\n service[method] = function (this: { ctx: Context }, ...args: any[]) {\n const caller = this.ctx\n const owner = registrationOwner(caller)\n if (!owner) return original.apply(this, args)\n const [id, value] = method === 'onCapability' ? ['events', args[0]] : args\n const key = `${owner.package}\\0${method}\\0${id}`\n let group = groups.get(key)\n if (!group) { group = { entries: [], actions: {} }; groups.set(key, group) }\n const selected = (scope: Scope) => pick(group!, scope)?.value as any\n const data = async (scope: Scope, emit: Callback, caps: unknown) => {\n let current: Entry | undefined, cancel: (() => void) | undefined, live = true, started = false\n const refresh = async () => {\n const entry = pick(group!, scope)\n if (started && current === entry) return\n current = entry\n cancel?.(); cancel = undefined\n if (started && group!.entries.length) service.refresh.call({ ctx: group!.entries[0]!.ctx }, id, scope)\n started = true\n emit(null)\n const def = entry?.value as any\n const fn = typeof def === 'function' ? def : def?.data\n if (!fn) return\n const stop = await fn(scope, (value: unknown) => {\n if (live && current === entry && pick(group!, scope) === entry) emit(value)\n }, caps)\n if (live && current === entry) cancel = stop\n else stop?.()\n }\n feeds.add(refresh)\n try { await refresh() }\n catch (error) { feeds.delete(refresh); throw error }\n return () => { live = false; feeds.delete(refresh); cancel?.() }\n }\n const mount = () => {\n if (!group!.entries.length) { group!.dispose?.(); group!.dispose = undefined; groups.delete(key); return }\n const actions = new Set(group!.entries.flatMap(entry => Object.keys((entry.value as any).actions ?? {})))\n for (const key of Object.keys(group!.actions)) if (!actions.has(key)) delete group!.actions[key]\n for (const action of actions) group!.actions[action] ??= (scope: Scope, event: unknown) => {\n const handler = selected(scope)?.actions?.[action]\n return handler ? handler(scope, event) : unavailable()\n }\n // Keep one native registration alive. Replacing it ends every session's stream.\n if (group!.dispose) return\n let routed: unknown\n if (method === 'panel') {\n routed = {\n view: (scope: Scope, caps: unknown) => {\n const def = selected(scope)\n return typeof def?.view === 'function' ? def.view(scope, caps) : def?.view\n ?? { v: 1, type: 'text', text: '此会话未启用该插件' }\n }, data,\n actions: group!.actions,\n }\n } else if (['strip', 'turnNote', 'micro'].includes(method)) routed = { data }\n else routed = (scope: Scope, event: unknown) => {\n const handler = selected(scope)\n if (handler) return handler(scope, event)\n if (method === 'media') throw new Error('此会话未启用该插件')\n return method === 'onCapability' ? undefined : unavailable()\n }\n // Preserve the caller's package identity, but own the shared registration in the core.\n const registration = caller.extend({ effect: ctx.effect.bind(ctx) })\n group!.dispose = original.call({ ctx: registration }, ...(method === 'onCapability' ? [routed] : [id, routed]))\n }\n return caller.effect(() => {\n const entry = { ctx: caller, owner, value }; group!.entries.push(entry)\n mount()\n return () => { group!.entries.splice(group!.entries.indexOf(entry), 1); mount() }\n })\n }\n }\n ctx.effect(() => () => {\n for (const [method, original] of originals) service[method] = original\n for (const group of groups.values()) group.dispose?.()\n groups.clear()\n feeds.clear()\n })\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport type { PluginManager } from 'dsh-tiered-plugin-core'\nimport { MenuModel, levelLabel } from 'dsh-tiered-plugin-core/model'\nimport { ownScope, type PluginRow, type ResourceKind, type Scope } from 'dsh-tiered-plugin-core/shared'\n\ninterface GoScope { sessionId?: string }\ntype Json = Record<string, any>\nconst button = (label: string, id: string, args: Json = {}) => ({ label, action: { id, args } })\nconst buttons = (...items: Json[]) => ({ type: 'actions', items })\nconst text = (value: string) => ({ type: 'text', text: value })\nconst pageSize = 5\n\nexport function mountMenu(ctx: Context, manager: PluginManager): void {\n const bridge = ctx.get('dshGo') as any\n const menus = new Map<string, { model: MenuModel; page: number; scopePage: number; edit?: string; json: string; notice: string; emitters: Set<(data: Json) => void> }>()\n const menu = (scope: GoScope) => {\n const key = scope.sessionId ?? ''\n let value = menus.get(key)\n if (!value) { value = { model: new MenuModel(manager, scope.sessionId ?? null), page: 0, scopePage: 0, json: '{}', notice: '', emitters: new Set() }; menus.set(key, value) }\n return value\n }\n const changed = (scope: GoScope, refresh = true) => {\n const state = menu(scope)\n for (const emit of state.emitters) emit({ form: { json: state.json }, nav: { scope: JSON.stringify(ownScope(state.model.selection.scope)) } })\n if (refresh) bridge.refresh('menu', scope)\n }\n async function view(scope: GoScope): Promise<Json> {\n const state = menu(scope)\n const { model } = state\n const { scope: target, kind, component } = model.selection\n const children: Json[] = [text(`${levelLabel(target)} · ${target.children ? '下级默认' : '本级'}`)]\n const scopes = model.scopes()\n children.push({ type: 'select', label: '配置层级', bind: 'data.nav.scope', value: JSON.stringify(ownScope(target)),\n options: scopes.slice(state.scopePage * 24, (state.scopePage + 1) * 24).map(item => ({ label: item.label, value: JSON.stringify(item.scope) })), onChange: 'scope' })\n if (scopes.length > 24) children.push(buttons(button('上一组层级', 'scopePage', { value: -1 }), button('下一组层级', 'scopePage', { value: 1 })))\n children.push(buttons(button('本级', 'children', { value: false }), button('下级', 'children', { value: true })))\n children.push(buttons(...(['plugin', 'mcp', 'skill'] as const).map((value, i) => button(['插件', 'MCP', 'Skill'][i]!, 'kind', { value }))))\n if (target.level === 'client' && !target.children) {\n const settings = manager.settings()\n children.push(buttons(button(`工作区树继承:${settings.inheritWorkspaceTree ? '开' : '关'}`, 'tree'),\n button(`插件隔离(实验性):${settings.pluginIsolation ? '开' : '关'}`, 'isolation')))\n children.push(text('插件隔离重启 DSH 后生效;可能修复冲突,也可能带来新的兼容性问题。'))\n }\n if (target.children) {\n const independent = manager.childSettings(ownScope(target)).independent\n children.push(text(independent ? '下级默认:独立' : '下级默认:继承'))\n children.push(buttons(button('继承', 'policy', { value: false }), button('独立', 'policy', { value: true })))\n }\n if (state.notice) children.push(text(state.notice))\n if (model.pending) {\n const plan = model.pending\n children.push(text([...plan.dependencies.map(item => `${item.mode === 'on' ? '启用' : '关闭'}依赖:${item.name}`),\n ...(plan.unverified.length ? ['这些插件尚未声明自兼容性,确认在本级启用?'] : [])].join('\\n')))\n children.push(buttons(button('确认执行', 'confirm'), button('取消', 'cancel')))\n return { v: 2, type: 'stack', children }\n }\n if (state.edit) {\n children.push(text(state.edit === '$new-mcp' ? '添加 MCP' : '编辑配置(JSON)'))\n children.push({ type: 'form', submit: 'save', submitLabel: '保存', children: [\n { type: 'textField', label: '配置 JSON', bind: 'data.form.json', multiline: true, maxLines: 8, maxLength: 2000 },\n ] })\n children.push(buttons(button('返回', 'back')))\n return { v: 2, type: 'stack', children }\n }\n if (component) children.push(buttons(button('返回插件列表', 'back')))\n const rows = await model.rows()\n state.page = Math.min(state.page, Math.max(0, Math.ceil(rows.length / pageSize) - 1))\n const disabled = target.children && !manager.childSettings(ownScope(target)).independent\n for (const row of rows.slice(state.page * pageSize, (state.page + 1) * pageSize)) {\n children.push(text(`${row.name} · ${row.own ? row.enabled ? '启用' : '关闭' : '继承'}`))\n if (!disabled) children.push(buttons(...(['inherit', 'on', 'off'] as const).filter(mode => mode !== 'inherit' || target.level !== 'client' || target.children)\n .map((mode) => button({ inherit: '继承', on: '启用', off: '关闭' }[mode], 'change', { id: row.id, mode }))))\n if ((row as PluginRow).components) children.push(buttons(button('组件', 'components', { id: row.id })))\n else if (!disabled && row.own && row.enabled) children.push(buttons(button('设置', 'edit', { id: row.id })))\n }\n if (!rows.length) children.push(text('此范围没有可配置的项目'))\n children.push(buttons(button('上一页', 'page', { value: -1 }), button(`${state.page + 1} / ${Math.max(1, Math.ceil(rows.length / pageSize))}`, 'refresh'), button('下一页', 'page', { value: 1 })))\n if (kind === 'mcp' && !disabled) children.push(buttons(button('添加 MCP', 'add')))\n return { v: 2, type: 'stack', children }\n }\n const run = (action: (state: ReturnType<typeof menu>, value: Json) => void | Promise<void>, deferred = true) => (scope: GoScope, event: { value?: Json }) => {\n const result = async () => {\n const state = menu(scope)\n // Immediate inputs refresh through their response, so the client can accept\n // the result before replacing the view that owns the input request.\n try { await action(state, event.value ?? {}); state.notice = ''; changed(scope, deferred); return deferred ? { toast: '已更新' } : { refresh: true } }\n catch (error) { state.notice = String(error); changed(scope, deferred); return deferred ? { toast: String(error).slice(0, 180) } : { refresh: true } }\n }\n return deferred ? { pending: { label: '正在处理', timeoutMs: 60000 }, result } : result()\n }\n bridge.panel('menu', {\n view,\n data(scope: GoScope, emit: (data: Json) => void) {\n const state = menu(scope); state.emitters.add(emit)\n emit({ form: { json: state.json }, nav: { scope: JSON.stringify(ownScope(state.model.selection.scope)) } })\n return () => { state.emitters.delete(emit) }\n },\n actions: {\n scope: run((s, v) => { s.model.select({ ...s.model.selection, scope: JSON.parse(v.value) as Scope, component: undefined }); s.page = 0; s.edit = undefined }, false),\n scopePage: run((s, v) => { s.scopePage = Math.max(0, Math.min(Math.ceil(s.model.scopes().length / 24) - 1, s.scopePage + v.value)) }, false),\n children: run((s, v) => { s.model.select({ ...s.model.selection, scope: { ...ownScope(s.model.selection.scope), children: !!v.value } }); s.edit = undefined }),\n kind: run((s, v) => { s.model.select({ ...s.model.selection, kind: v.value as ResourceKind, component: undefined }); s.page = 0; s.edit = undefined }),\n policy: run((s, v) => s.model.children(!!v.value)),\n tree: run(() => manager.setWorkspaceTreeInheritance(!manager.settings().inheritWorkspaceTree)),\n isolation: run(() => manager.setPluginIsolation(!manager.settings().pluginIsolation)),\n change: run((s, v) => s.model.change(v.id, v.mode)), confirm: run(s => s.model.confirm()), cancel: run(s => { s.model.pending = undefined }),\n components: run((s, v) => { s.model.select({ ...s.model.selection, component: v.id }); s.page = 0 }),\n edit: run(async (s, v) => {\n const json = JSON.stringify(await s.model.config(v.id), null, 2)\n if ([...json].length > 2000 || Buffer.byteLength(JSON.stringify({ values: { 'data.form.json': json } })) > 3800) throw new Error('配置超过手机输入限制,请在 Web 菜单编辑')\n s.json = json; s.edit = v.id\n }),\n add: run(s => { s.edit = '$new-mcp'; s.json = JSON.stringify({ serverName: 'my-server', transport: 'stdio', command: 'node', args: [] }, null, 2) }),\n save: run(async (s, v) => { const json = v.values['data.form.json']; if (s.edit === '$new-mcp') await s.model.addMcp(json); else await s.model.save(s.edit!, json); s.edit = undefined }),\n back: run(s => { if (s.edit) s.edit = undefined; else s.model.select({ ...s.model.selection, component: undefined }) }),\n page: run((s, v) => { s.page = Math.max(0, s.page + v.value) }), refresh: run(() => {}),\n },\n })\n ctx.effect(() => () => menus.clear())\n}\n","import type { Context } from '@deepseek-ai/cordis'\nimport { acquireCore } from 'dsh-tiered-plugin-core'\nimport { installNativeRouting } from './routing.ts'\nimport { mountMenu } from './menu.ts'\n\nexport { Config, inject, tieredManagerFrontend } from 'dsh-tiered-plugin-core'\nexport const name = 'tiered-plugin-go'\nexport async function apply(ctx: Context, config: { dataFile?: string }): Promise<void> {\n const manager = await acquireCore(ctx, config)\n await manager.adaptService('dshGo', installNativeRouting)\n ctx.inject(['dshGo'], child => {\n mountMenu(child, manager)\n })\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,81 @@
|
|
|
1
1
|
{
|
|
2
|
+
"type": "module",
|
|
3
|
+
"license": "MIT",
|
|
4
|
+
"engines": {
|
|
5
|
+
"node": "^22.19.0 || >=24.0.0"
|
|
6
|
+
},
|
|
7
|
+
"repository": {
|
|
8
|
+
"url": "git+https://github.com/kazari-qwp/dsh-tiered-plugin-menu.git",
|
|
9
|
+
"type": "git",
|
|
10
|
+
"directory": "packages/dsh-go"
|
|
11
|
+
},
|
|
12
|
+
"homepage": "https://github.com/kazari-qwp/dsh-tiered-plugin-menu#readme",
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/kazari-qwp/dsh-tiered-plugin-menu/issues"
|
|
15
|
+
},
|
|
16
|
+
"main": "./dist/index.js",
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"default": "./dist/index.js"
|
|
22
|
+
},
|
|
23
|
+
"./package.json": "./package.json"
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"cordis.patch.yml",
|
|
28
|
+
"README.md",
|
|
29
|
+
"LICENSE"
|
|
30
|
+
],
|
|
31
|
+
"dsh": {
|
|
32
|
+
"bundle": {
|
|
33
|
+
"patch": "./cordis.patch.yml"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
2
36
|
"name": "dsh-tiered-plugin-go",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
37
|
+
"version": "0.1.0",
|
|
38
|
+
"description": "DSH 分级插件菜单的手机适配:独立配置插件、MCP 和 Skill。",
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"dsh-tiered-plugin-core": "^0.8.0"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"@deepseek-ai/cordis": "4.1.0"
|
|
44
|
+
},
|
|
45
|
+
"dshGo": {
|
|
46
|
+
"v": 1,
|
|
47
|
+
"title": {
|
|
48
|
+
"zh": "分级配置",
|
|
49
|
+
"en": "Tiered settings"
|
|
50
|
+
},
|
|
51
|
+
"icon": "settings",
|
|
52
|
+
"contributes": {
|
|
53
|
+
"panels": [
|
|
54
|
+
{
|
|
55
|
+
"id": "menu",
|
|
56
|
+
"title": {
|
|
57
|
+
"zh": "分级配置",
|
|
58
|
+
"en": "Tiered settings"
|
|
59
|
+
},
|
|
60
|
+
"icon": "settings",
|
|
61
|
+
"placement": [
|
|
62
|
+
"session.tab",
|
|
63
|
+
"features",
|
|
64
|
+
"chat.panel"
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
]
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
"keywords": [
|
|
71
|
+
"dsh-plugin",
|
|
72
|
+
"deepseek-harness",
|
|
73
|
+
"dsh",
|
|
74
|
+
"plugins",
|
|
75
|
+
"workspace",
|
|
76
|
+
"session",
|
|
77
|
+
"mcp",
|
|
78
|
+
"skills",
|
|
79
|
+
"dsh-go"
|
|
80
|
+
]
|
|
81
|
+
}
|