dsh-jiuling-remote-mobile 1.0.24 → 1.0.26
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/lib/client.js +140 -2
- package/lib/index.js +23 -3
- package/package.json +1 -1
package/lib/client.js
CHANGED
|
@@ -526,6 +526,52 @@ window.__ModuleLoader__.load({
|
|
|
526
526
|
};
|
|
527
527
|
}
|
|
528
528
|
|
|
529
|
+
/**
|
|
530
|
+
* 按工作区筛**预设名单**(与 `pickWorkspaceGroups` 同构)。
|
|
531
|
+
*
|
|
532
|
+
* 用户报障:「模型列表能够快速切换回来了,但是预设列表没有切换」——
|
|
533
|
+
* 模型能切是因为它走了 `pickWorkspaceGroups`,预设没切是因为宿主
|
|
534
|
+
* `mergePresets` 只是把两份并起来、前端没人再筛一次。
|
|
535
|
+
*
|
|
536
|
+
* 判据与模型**完全同一条**(`isRemoteSession`):会话在电脑工作区 ⇒ 只留
|
|
537
|
+
* 电脑那几条;否则只留本地那几条,并把被同 id 覆盖掉的本地项还原回来。
|
|
538
|
+
*
|
|
539
|
+
* ⚠️ **一条都不剩时原样返回**:电脑那边预设全坏了、或者宿主还没把
|
|
540
|
+
* `desktop` 标记打上(老版本宿主)时,宁可多显示几条,也别把菜单变成空的
|
|
541
|
+
* —— 空菜单用户连「默认」都选不回来。
|
|
542
|
+
*
|
|
543
|
+
* @param value - `{presets, localPresets?}`(宿主 `mergePresets` 的产物)。
|
|
544
|
+
* @param isRemote - 这个会话是不是跑在电脑上。
|
|
545
|
+
* @returns 筛过的 `{presets}`(`value` 不合法时原样返回)。
|
|
546
|
+
*/
|
|
547
|
+
function pickWorkspacePresets(value, isRemote) {
|
|
548
|
+
if (!value || !Array.isArray(value.presets)) return value;
|
|
549
|
+
const all = value.presets;
|
|
550
|
+
// ⚠️ 宿主没打标记(老版本宿主 / 还没合并过)⇒ 无从判断,原样返回。
|
|
551
|
+
let tagged = false;
|
|
552
|
+
for (let at = 0; at < all.length; at += 1) {
|
|
553
|
+
if (all[at] && all[at].desktop === true) { tagged = true; break; }
|
|
554
|
+
}
|
|
555
|
+
if (!tagged) return value;
|
|
556
|
+
if (isRemote === true) {
|
|
557
|
+
const desktopOnly = all.filter(function (preset) { return preset.desktop === true; });
|
|
558
|
+
if (desktopOnly.length === 0) return value;
|
|
559
|
+
return Object.assign({}, value, { presets: desktopOnly });
|
|
560
|
+
}
|
|
561
|
+
const kept = all.filter(function (preset) { return preset.desktop !== true; });
|
|
562
|
+
// 还原被电脑同 id 覆盖掉的本地预设(见宿主 `mergePresets`)。
|
|
563
|
+
const local = Array.isArray(value.localPresets) ? value.localPresets : [];
|
|
564
|
+
if (local.length > 0) {
|
|
565
|
+
const have = {};
|
|
566
|
+
for (let kt = 0; kt < kept.length; kt += 1) have[kept[kt].id] = true;
|
|
567
|
+
for (let lt = 0; lt < local.length; lt += 1) {
|
|
568
|
+
if (have[local[lt].id] !== true) kept.push(local[lt]);
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
if (kept.length === 0) return value;
|
|
572
|
+
return Object.assign({}, value, { presets: kept });
|
|
573
|
+
}
|
|
574
|
+
|
|
529
575
|
/**
|
|
530
576
|
* 从共享的 catalog 原值里取「手机本地的组」(宿主 `mergeCatalog` 带的)。
|
|
531
577
|
*
|
|
@@ -786,6 +832,85 @@ window.__ModuleLoader__.load({
|
|
|
786
832
|
};
|
|
787
833
|
}
|
|
788
834
|
|
|
835
|
+
/**
|
|
836
|
+
* 把「按工作区筛预设名单」接到官方 RPC 上。
|
|
837
|
+
*
|
|
838
|
+
* ⚠️⚠️ **为什么必须在前端拦,而不能像模型那样只靠宿主。**
|
|
839
|
+
*
|
|
840
|
+
* 官方的预设名单来自 `readRoster(ctx)` → `ctx.remote.agentPresets.list()`
|
|
841
|
+
* (`dsh-client-ui-agent-preset/lib/client.js:1081`),落到宿主就是
|
|
842
|
+
* `remoteExportList()` —— 这个方法**一个参数都不收**
|
|
843
|
+
* (`dsh-agent-preset-registry/lib/index.js:592`),宿主侧**拿不到会话**,
|
|
844
|
+
* 所以「远程会话看电脑的、本地会话看手机的」在宿主侧表达不出来。
|
|
845
|
+
*
|
|
846
|
+
* 宿主那边(`mergePresets`)只能把两份并起来并打 `desktop: true` 标记,
|
|
847
|
+
* 与模型目录的 `mergeCatalog` 完全同构。**筛这一步必须在能看到会话的地方做。**
|
|
848
|
+
*
|
|
849
|
+
* 还有一条更硬的理由:`seat.load()` 只在 `settings/document-updated` 与
|
|
850
|
+
* `connection/reset` 时重跑(`dsh-client-ui-agent-preset/lib/client.js:1595`),
|
|
851
|
+
* **切工作区根本不会重新请求 roster** —— 所以就算宿主按会话筛好了,
|
|
852
|
+
* 前端缓存里那份旧的也不会变。只能在**读结果**的地方筛。
|
|
853
|
+
*
|
|
854
|
+
* @param ctx - client 根上下文。
|
|
855
|
+
* @param cwdOf - `sessionId → cwd` 的同步读取函数。
|
|
856
|
+
* @returns 撤销函数。
|
|
857
|
+
*/
|
|
858
|
+
function patchAgentPresets(ctx, cwdOf) {
|
|
859
|
+
var remote = ctx.remote;
|
|
860
|
+
if (remote === undefined || remote === null) return function () {};
|
|
861
|
+
var presets = remote.agentPresets;
|
|
862
|
+
if (presets === undefined || presets === null) return function () {};
|
|
863
|
+
if (typeof presets.list !== 'function') return function () {};
|
|
864
|
+
|
|
865
|
+
/**
|
|
866
|
+
* 「当前主视图会话」的 id —— 与官方 `installWorkspaceShortcuts` 的
|
|
867
|
+
* `current()` 同一条判据(`dsh-client-ui-workspace/lib/client.js:106`):
|
|
868
|
+
* `retainedBy.mainView > 0`。
|
|
869
|
+
*
|
|
870
|
+
* @returns 会话 id;找不到时 `undefined`。
|
|
871
|
+
*/
|
|
872
|
+
var currentSessionId = function () {
|
|
873
|
+
var sessions = ctx.sessions;
|
|
874
|
+
if (sessions === undefined || sessions === null) return undefined;
|
|
875
|
+
var list = sessions.list;
|
|
876
|
+
if (list === undefined || list === null || typeof list.getSnapshot !== 'function') return undefined;
|
|
877
|
+
var snapshot = list.getSnapshot();
|
|
878
|
+
if (snapshot === undefined || snapshot === null) return undefined;
|
|
879
|
+
var byId = snapshot.byId;
|
|
880
|
+
if (byId === undefined || byId === null) return undefined;
|
|
881
|
+
var ids = Object.keys(byId);
|
|
882
|
+
for (var at = 0; at < ids.length; at += 1) {
|
|
883
|
+
var row = byId[ids[at]];
|
|
884
|
+
if (!row || !row.retainedBy) continue;
|
|
885
|
+
if ((row.retainedBy.mainView || 0) > 0) return ids[at];
|
|
886
|
+
}
|
|
887
|
+
return undefined;
|
|
888
|
+
};
|
|
889
|
+
|
|
890
|
+
var hadOwn = Object.prototype.hasOwnProperty.call(presets, 'list');
|
|
891
|
+
var previous = presets.list;
|
|
892
|
+
var call = previous.bind(presets);
|
|
893
|
+
presets.list = function () {
|
|
894
|
+
return call.apply(null, arguments).then(function (result) {
|
|
895
|
+
// ⚠️ 失败回执原样透传:`readRoster` 靠 `result.ok` 判断,
|
|
896
|
+
// 也靠 `error.code === 'gateway/invocation-unavailable'` 兜底,
|
|
897
|
+
// 动它会让预设菜单变成错误态。
|
|
898
|
+
if (!result || result.ok !== true || !result.value) return result;
|
|
899
|
+
var sessionId = currentSessionId();
|
|
900
|
+
var isRemote = sessionId === undefined
|
|
901
|
+
? false
|
|
902
|
+
: isRemoteSession(sessionId, cwdOf);
|
|
903
|
+
var picked = pickWorkspacePresets(result.value, isRemote);
|
|
904
|
+
if (picked === result.value) return result;
|
|
905
|
+
return Object.assign({}, result, { value: picked });
|
|
906
|
+
});
|
|
907
|
+
};
|
|
908
|
+
return function () {
|
|
909
|
+
if (hadOwn) presets.list = previous;
|
|
910
|
+
else delete presets.list;
|
|
911
|
+
};
|
|
912
|
+
}
|
|
913
|
+
|
|
789
914
|
/**
|
|
790
915
|
* 造一个 `sessionId → cwd` 的**同步**读取函数。
|
|
791
916
|
*
|
|
@@ -2040,8 +2165,15 @@ window.__ModuleLoader__.load({
|
|
|
2040
2165
|
}
|
|
2041
2166
|
//#endregion
|
|
2042
2167
|
|
|
2043
|
-
/**
|
|
2044
|
-
|
|
2168
|
+
/**
|
|
2169
|
+
* 需要宿主提供的服务:slot 注册表、工作区浏览与导航、会话数据。
|
|
2170
|
+
*
|
|
2171
|
+
* ⚠️ `remote` / `remote.agentPresets` 是**预设名单**那条路要用的:
|
|
2172
|
+
* 官方 `dsh-client-ui-agent-preset` 自己也 inject 了这两个
|
|
2173
|
+
* (见其 `lib/client.js:1527` 的 inject 数组)。不加的话 `ctx.remote`
|
|
2174
|
+
* 属性访问会拿到 `undefined`,`patchAgentPresets` 直接静默跳过。
|
|
2175
|
+
*/
|
|
2176
|
+
const inject = ['slots', 'uiWorkspace', 'sessions', 'workspaces', 'remote', 'remote.agentPresets'];
|
|
2045
2177
|
|
|
2046
2178
|
/**
|
|
2047
2179
|
* Client 插件主体:注册「手机 / 电脑」双页签的目录选择对话框 + 订阅流式帧。
|
|
@@ -2127,6 +2259,12 @@ window.__ModuleLoader__.load({
|
|
|
2127
2259
|
'dsh-remote-mobile: workspace-scoped model catalog',
|
|
2128
2260
|
);
|
|
2129
2261
|
|
|
2262
|
+
// 把「按工作区筛预设名单」接到官方 RPC 上。
|
|
2263
|
+
ctx.effect(
|
|
2264
|
+
() => patchAgentPresets(ctx, makeCwdOf(ctx)),
|
|
2265
|
+
'dsh-remote-mobile: workspace-scoped agent presets',
|
|
2266
|
+
);
|
|
2267
|
+
|
|
2130
2268
|
// 负 priority:single slot 取 entries[0],entries 按 priority 升序 ⇒ 最先渲染。
|
|
2131
2269
|
const register = (name) =>
|
|
2132
2270
|
ctx.slots.register(
|
package/lib/index.js
CHANGED
|
@@ -1209,17 +1209,37 @@ export function apply(ctx) {
|
|
|
1209
1209
|
/**
|
|
1210
1210
|
* 把电脑的预设并进手机本地的预设名单(同 id 以电脑为准)。
|
|
1211
1211
|
*
|
|
1212
|
+
* ⚠️ **与 `mergeCatalog` 同构,必须给电脑那几条打 `desktop: true`。**
|
|
1213
|
+
*
|
|
1214
|
+
* `remoteExportList()` 是**全局 RPC**(`dsh-agent-preset-registry/lib/index.js:592`
|
|
1215
|
+
* 的 `async remoteExportList()` 连一个参数都不收),宿主侧**拿不到当前会话**,
|
|
1216
|
+
* 所以「远程会话看电脑的、本地会话看手机的」在这一层表达不出来 ——
|
|
1217
|
+
* 与模型目录完全同一个限制(见 `mergeCatalog` 的注释)。
|
|
1218
|
+
*
|
|
1219
|
+
* 折中做法也照抄模型目录那一套:这里把两份**并起来**并打标记,
|
|
1220
|
+
* 由前端按「当前会话的工作区是不是电脑镜像目录」再筛一次
|
|
1221
|
+
* (见 client.js 的 `pickWorkspacePresets`)。
|
|
1222
|
+
*
|
|
1223
|
+
* 不打标记的后果就是用户报的:「模型列表能够快速切换回来了,但是预设列表
|
|
1224
|
+
* 没有切换」—— 预设一直是两份合并的全集,切到哪个工作区都一样。
|
|
1225
|
+
*
|
|
1226
|
+
* ⚠️ **`localPresets` 必须一起带上**:同 id 以电脑为准 ⇒ 本地那一条被丢掉了,
|
|
1227
|
+
* 而本地工作区要能把它还原回来(前端只靠 `presets` 做不到,那条已经不在里面)。
|
|
1228
|
+
* 这个字段是本插件加的,官方 `presetOptions()` 只读 `id` / `name` /
|
|
1229
|
+
* `description` / `broken`(`dsh-client-ui-agent-preset/lib/client.js:1138`),
|
|
1230
|
+
* 多带一个不会影响渲染。
|
|
1231
|
+
*
|
|
1212
1232
|
* @param local - 手机本地的 `{presets}`。
|
|
1213
1233
|
* @param desktop - 电脑的 `{presets}`。
|
|
1214
|
-
* @returns
|
|
1234
|
+
* @returns 合并后的名单(额外带 `localPresets`)。
|
|
1215
1235
|
*/
|
|
1216
1236
|
function mergePresets(local, desktop) {
|
|
1217
|
-
const presets =
|
|
1237
|
+
const presets = (desktop?.presets ?? []).map((preset) => ({ ...preset, desktop: true }));
|
|
1218
1238
|
const seen = new Set(presets.map((preset) => preset.id));
|
|
1219
1239
|
for (const preset of local?.presets ?? []) {
|
|
1220
1240
|
if (!seen.has(preset.id)) presets.push(preset);
|
|
1221
1241
|
}
|
|
1222
|
-
return { ...local, presets };
|
|
1242
|
+
return { ...local, presets, localPresets: local?.presets ?? [] };
|
|
1223
1243
|
}
|
|
1224
1244
|
|
|
1225
1245
|
/** 往所有浏览器订阅者推一条 SSE。 */
|