@michengai/dsh-codex-ui 0.2.107 → 0.2.110
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +26 -0
- package/CHANGELOG.zh-CN.md +26 -0
- package/lib/client.js +200 -54
- package/lib/index.mjs +24 -17
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,32 @@
|
|
|
4
4
|
|
|
5
5
|
This changelog records recent releases of DSH Codex UI and its one-click installer. Earlier changes remain available in the [Git history](https://github.com/MichengAI/dsh-codex-ui/commits/main).
|
|
6
6
|
|
|
7
|
+
## 0.2.110 - 2026-09-08
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- Distinguished standalone DSH Web installation failures from Desktop errors, directing users to stop and restart the current Web host instead of quitting DSH Desktop.
|
|
12
|
+
- Added localized recovery guidance for locked plugin files, pnpm store conflicts, and otherwise unrecognized DSH Web installation failures.
|
|
13
|
+
|
|
14
|
+
### Tests
|
|
15
|
+
|
|
16
|
+
- Added regression coverage for Web-specific installer errors and their Simplified Chinese and English localization.
|
|
17
|
+
|
|
18
|
+
## suite-installer-v0.1.27 - 2026-09-07
|
|
19
|
+
|
|
20
|
+
- Updated the bundled Codex UI to `0.2.108`, including group rename/delete menus and aligned group counts; refreshed exact member versions from the official npm registry.
|
|
21
|
+
|
|
22
|
+
## 0.2.108 - 2026-09-07
|
|
23
|
+
|
|
24
|
+
- Added rename and delete actions to each custom workspace group; the Projects header now keeps only the create-group button. Renaming preserves group membership, ordering, and expansion.
|
|
25
|
+
- Aligned custom-group and Ungrouped counts, kept long names from crowding menu buttons, and improved keyboard focus recovery after renaming.
|
|
26
|
+
- Prevented IME confirmation from submitting new groups and kept rejected names from interfering with preference synchronization.
|
|
27
|
+
- Made case-insensitive name checks independent of system locale while preserving legacy stored group names and memberships.
|
|
28
|
+
|
|
29
|
+
## suite-installer-v0.1.26 - 2026-09-07
|
|
30
|
+
|
|
31
|
+
- Refreshed direct member pins from the official npm registry, including IM Connect `0.1.37`, which withdraws its unfinished proactive delivery feature.
|
|
32
|
+
|
|
7
33
|
## suite-installer-v0.1.25 - 2026-09-07
|
|
8
34
|
|
|
9
35
|
- Updated the bundled Codex UI to `0.2.107` and refreshed direct member versions from the official npm registry for reproducible installation.
|
package/CHANGELOG.zh-CN.md
CHANGED
|
@@ -4,6 +4,32 @@
|
|
|
4
4
|
|
|
5
5
|
本日志记录 DSH Codex UI 及其一键安装器的最近发布;更早的变更可查看 [Git 提交历史](https://github.com/MichengAI/dsh-codex-ui/commits/main)。
|
|
6
6
|
|
|
7
|
+
## 0.2.110 - 2026-09-08
|
|
8
|
+
|
|
9
|
+
### 修复
|
|
10
|
+
|
|
11
|
+
- 区分独立 DSH Web 与 Desktop 的插件安装失败:Web 环境将提示停止并重启当前 Web 宿主,不再错误要求退出 DSH Desktop。
|
|
12
|
+
- 为被占用的插件文件、pnpm 仓库不一致和未识别的 DSH Web 安装失败提供本地化恢复指引。
|
|
13
|
+
|
|
14
|
+
### 测试
|
|
15
|
+
|
|
16
|
+
- 新增 Web 专属安装错误及其简体中文、英文文案的回归覆盖。
|
|
17
|
+
|
|
18
|
+
## suite-installer-v0.1.27 - 2026-09-07
|
|
19
|
+
|
|
20
|
+
- 将套件中的 Codex UI 更新至 `0.2.108`,包含分组重命名、删除菜单和数量对齐优化;从官方 npm 刷新并锁定成员版本。
|
|
21
|
+
|
|
22
|
+
## 0.2.108 - 2026-09-07
|
|
23
|
+
|
|
24
|
+
- 为每个自定义工作区分组新增重命名和删除菜单;项目标题栏仅保留新增分组按钮。重命名保留项目归属、排序和展开状态。
|
|
25
|
+
- 对齐自定义分组与“未分组”的数量,避免长名称挤出菜单按钮,并完善重命名后的键盘焦点恢复。
|
|
26
|
+
- 防止新建分组时输入法选词误触发提交,修复名称校验失败影响偏好同步的问题。
|
|
27
|
+
- 统一不依赖系统语言环境的大小写判重规则,同时兼容保留旧分组名称和成员数据。
|
|
28
|
+
|
|
29
|
+
## suite-installer-v0.1.26 - 2026-09-07
|
|
30
|
+
|
|
31
|
+
- 从官方 npm 刷新直装成员版本,包含 IM Connect `0.1.37`,该版本已撤回未完成的主动投递功能。
|
|
32
|
+
|
|
7
33
|
## suite-installer-v0.1.25 - 2026-09-07
|
|
8
34
|
|
|
9
35
|
- 将套件中的 Codex UI 更新至 `0.2.107`,并从官方 npm 刷新直装成员版本,保证安装可复现。
|
package/lib/client.js
CHANGED
|
@@ -863,8 +863,8 @@ window.__ModuleLoader__.load({
|
|
|
863
863
|
this.code = code;
|
|
864
864
|
}
|
|
865
865
|
};
|
|
866
|
-
/**
|
|
867
|
-
function
|
|
866
|
+
/** 校验结构和归属;存储兼容模式保留旧 locale 下合法的大小写变体名称。 */
|
|
867
|
+
function parseGroups(value, preserveCaseVariants) {
|
|
868
868
|
if (!Array.isArray(value) || value.length > 100) return void 0;
|
|
869
869
|
const groupIds = /* @__PURE__ */ new Set();
|
|
870
870
|
const groupTitles = /* @__PURE__ */ new Set();
|
|
@@ -876,13 +876,14 @@ window.__ModuleLoader__.load({
|
|
|
876
876
|
const id = typeof group.id === "string" ? group.id.trim() : "";
|
|
877
877
|
const title = typeof group.title === "string" ? group.title.trim() : "";
|
|
878
878
|
if (id === "" || id.length > 128 || title === "" || title.length > 80) return void 0;
|
|
879
|
-
|
|
879
|
+
const titleKey = preserveCaseVariants ? title : title.toLowerCase();
|
|
880
|
+
if (groupIds.has(id) || groupTitles.has(titleKey)) return void 0;
|
|
880
881
|
if (!Array.isArray(group.workspaceIds) || group.workspaceIds.length > 1e3) return void 0;
|
|
881
882
|
const normalizedIds = [...new Set(group.workspaceIds)];
|
|
882
883
|
if (!normalizedIds.every((workspaceId) => typeof workspaceId === "string" && workspaceId.trim() !== "" && workspaceId.length <= 256)) return void 0;
|
|
883
884
|
if (normalizedIds.some((workspaceId) => workspaceIds.has(workspaceId))) return void 0;
|
|
884
885
|
groupIds.add(id);
|
|
885
|
-
groupTitles.add(
|
|
886
|
+
groupTitles.add(titleKey);
|
|
886
887
|
normalizedIds.forEach((workspaceId) => workspaceIds.add(workspaceId));
|
|
887
888
|
groups.push({
|
|
888
889
|
id,
|
|
@@ -892,15 +893,30 @@ window.__ModuleLoader__.load({
|
|
|
892
893
|
}
|
|
893
894
|
return groups;
|
|
894
895
|
}
|
|
896
|
+
/** 旧数据可往返保存且不改名;新名称的大小写判重由创建、重命名操作执行。 */
|
|
897
|
+
function parseStoredWorkspaceGroups(value) {
|
|
898
|
+
return parseGroups(value, true);
|
|
899
|
+
}
|
|
895
900
|
/** 新建空分组;项目只有被显式移动后才会进入其中。 */
|
|
896
901
|
function createWorkspaceGroup(groups, group) {
|
|
897
|
-
|
|
902
|
+
if (groups.some((existing) => existing.title.toLowerCase() === group.title.trim().toLowerCase())) throw new WorkspaceGroupError("group-invalid");
|
|
903
|
+
const next = parseStoredWorkspaceGroups([...groups, {
|
|
898
904
|
...group,
|
|
899
905
|
workspaceIds: []
|
|
900
906
|
}]);
|
|
901
907
|
if (next === void 0) throw new WorkspaceGroupError("group-invalid");
|
|
902
908
|
return next;
|
|
903
909
|
}
|
|
910
|
+
/** 仅更改名称,保留分组标识、成员及其顺序。 */
|
|
911
|
+
function renameWorkspaceGroup(groups, groupId, title) {
|
|
912
|
+
if (!groups.some((group) => group.id === groupId)) throw new WorkspaceGroupError("group-missing");
|
|
913
|
+
const normalizedTitle = title.trim();
|
|
914
|
+
if (normalizedTitle === "" || normalizedTitle.length > 80 || groups.some((group) => group.id !== groupId && group.title.toLowerCase() === normalizedTitle.toLowerCase())) throw new WorkspaceGroupError("group-invalid");
|
|
915
|
+
return groups.map((group) => group.id === groupId ? {
|
|
916
|
+
...group,
|
|
917
|
+
title: normalizedTitle
|
|
918
|
+
} : group);
|
|
919
|
+
}
|
|
904
920
|
/** 将项目放入指定分组;未传分组时退回未分组区。 */
|
|
905
921
|
function assignWorkspaceToGroup(groups, workspaceId, groupId) {
|
|
906
922
|
if (workspaceId.trim() === "" || workspaceId.length > 256) throw new WorkspaceGroupError("workspace-invalid");
|
|
@@ -1029,7 +1045,7 @@ window.__ModuleLoader__.load({
|
|
|
1029
1045
|
if (payload === null || typeof payload !== "object") throw new Error("置顶偏好响应格式无效。");
|
|
1030
1046
|
const record = payload;
|
|
1031
1047
|
const workspaceGroupsSupported = Object.prototype.hasOwnProperty.call(record, "workspaceGroups");
|
|
1032
|
-
const workspaceGroups = workspaceGroupsSupported ?
|
|
1048
|
+
const workspaceGroups = workspaceGroupsSupported ? parseStoredWorkspaceGroups(record.workspaceGroups) : [];
|
|
1033
1049
|
if (typeof record.exists !== "boolean" || !Array.isArray(record.pinnedWorkspaceIds) || !record.pinnedWorkspaceIds.every((id) => typeof id === "string") || workspaceGroups === void 0) throw new Error("置顶偏好响应格式无效。");
|
|
1034
1050
|
return {
|
|
1035
1051
|
exists: record.exists,
|
|
@@ -1039,7 +1055,7 @@ window.__ModuleLoader__.load({
|
|
|
1039
1055
|
};
|
|
1040
1056
|
}
|
|
1041
1057
|
async function writeHostWorkspacePreferences(pinnedWorkspaceIds, workspaceGroups, fetcher = fetch) {
|
|
1042
|
-
const groups =
|
|
1058
|
+
const groups = parseStoredWorkspaceGroups([...workspaceGroups]);
|
|
1043
1059
|
if (groups === void 0) throw new Error("工作区分组数据无效。");
|
|
1044
1060
|
const response = await fetcher(WORKSPACE_PREFERENCES_ENDPOINT, {
|
|
1045
1061
|
method: "PUT",
|
|
@@ -1100,7 +1116,7 @@ window.__ModuleLoader__.load({
|
|
|
1100
1116
|
pendingHostSync: false
|
|
1101
1117
|
};
|
|
1102
1118
|
const record = value;
|
|
1103
|
-
const workspaceGroups = record.version === 1 ?
|
|
1119
|
+
const workspaceGroups = record.version === 1 ? parseStoredWorkspaceGroups(record.workspaceGroups) : void 0;
|
|
1104
1120
|
if (workspaceGroups === void 0 || typeof record.pendingHostSync !== "boolean") return {
|
|
1105
1121
|
workspaceGroups: [],
|
|
1106
1122
|
pendingHostSync: false
|
|
@@ -1118,7 +1134,7 @@ window.__ModuleLoader__.load({
|
|
|
1118
1134
|
}
|
|
1119
1135
|
function saveWorkspaceGroupsCache(storage, groups, pendingHostSync) {
|
|
1120
1136
|
if (storage === void 0) return;
|
|
1121
|
-
const workspaceGroups =
|
|
1137
|
+
const workspaceGroups = parseStoredWorkspaceGroups([...groups]);
|
|
1122
1138
|
if (workspaceGroups === void 0) return;
|
|
1123
1139
|
try {
|
|
1124
1140
|
storage.setItem(WORKSPACE_GROUPS_STORAGE_KEY, JSON.stringify({
|
|
@@ -1939,7 +1955,10 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1939
1955
|
};
|
|
1940
1956
|
const INSTALL_ERROR_KEYS = [
|
|
1941
1957
|
[/没有进入当前 Profile|did not enter this profile/i, "about.installUnchanged"],
|
|
1958
|
+
[/pnpm 仓库不一致.*停止当前 DSH Web|pnpm store do not match.*stop the current DSH Web/i, "about.installStoreMismatchWeb"],
|
|
1959
|
+
[/停止当前 DSH Web|stop the current DSH Web/i, "about.installExitWeb"],
|
|
1942
1960
|
[/完全退出桌面端|无法覆盖正在运行的插件文件|running plugin files|quit DSH Desktop/i, "about.installExitDesktop"],
|
|
1961
|
+
[/DSH Web 终端输出|DSH Web terminal/i, "about.installWebFailed"],
|
|
1943
1962
|
[/pnpm 仓库不一致|pnpm store do not match/i, "about.installStoreMismatch"],
|
|
1944
1963
|
[/构建脚本策略|build-script policy/i, "about.installBuildPolicy"],
|
|
1945
1964
|
[/找不到 pnpm|pnpm (?:is )?not (?:available|found)/i, "about.installPnpmMissing"],
|
|
@@ -2199,6 +2218,11 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2199
2218
|
.dcu-wb-section+.dcu-wb-section{margin-top:12px}
|
|
2200
2219
|
.dcu-wb-section-head{position:relative;display:flex;align-items:center;min-height:24px;padding:0;border-radius:6px}.dcu-wb-section-head:hover .dcu-wb-actions{display:flex}.dcu-wb-section-label{position:relative;display:flex;align-items:center;gap:4px;flex:1;min-width:0;min-height:24px;border:0;padding:2px 4px 2px 12px;background:transparent;color:var(--dcu-sidebar-tertiary);font:13px/20px var(--dcu-font,inherit);font-weight:400;letter-spacing:0;text-align:left;cursor:pointer}.dcu-wb-section-caret{display:grid;place-items:center;flex:none;width:12px;height:12px;color:currentColor;opacity:0;transform:rotate(0deg);transform-origin:50% 50%;transition:opacity 120ms ease,transform 160ms ease}.dcu-wb-section-head .dcu-wb-section-caret{position:absolute;left:0;top:6px}.dcu-wb-section-caret svg{display:block}.dcu-wb-section-head:hover .dcu-wb-section-caret,.dcu-wb-section-label:focus-visible .dcu-wb-section-caret{opacity:.78}.dcu-wb-section-label[aria-expanded=true] .dcu-wb-section-caret{transform:rotate(90deg)}.dcu-wb-section-body{display:block}.dcu-wb-section-body[data-open=false]{display:none}.dcu-wb-section-body>div{min-height:0}.dcu-wb-section-body[data-open=true]>div{animation:dcu-wb-section-in 140ms cubic-bezier(.16,1,.3,1)}@keyframes dcu-wb-section-in{from{opacity:0;transform:translateY(-3px)}to{opacity:1;transform:none}}@media (prefers-reduced-motion:reduce){.dcu-wb-section-caret{transition:none}.dcu-wb-section-body[data-open=true]>div{animation:none}}
|
|
2201
2220
|
.dcu-wb-project{position:relative;min-width:0}
|
|
2221
|
+
.dcu-wb-collection-head .dcu-wb-more{opacity:0;pointer-events:none}
|
|
2222
|
+
.dcu-wb-collection-head:hover .dcu-wb-more,.dcu-wb-collection-head:focus-within .dcu-wb-more,.dcu-wb-collection-head .dcu-wb-more[aria-expanded=true]{opacity:1;pointer-events:auto}
|
|
2223
|
+
@media (pointer:coarse){.dcu-wb-collection-head .dcu-wb-more{opacity:1;pointer-events:auto}}
|
|
2224
|
+
.dcu-wb-collection-title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
2225
|
+
.dcu-wb-collection-actions{flex-shrink:0;width:20px}
|
|
2202
2226
|
.dcu-wb-collections{display:grid;min-width:0;gap:4px}.dcu-wb-collection,.dcu-wb-ungrouped{position:relative;min-width:0;overflow:visible}.dcu-wb-collection-head{display:flex;align-items:center;min-height:28px;padding:0 4px;border-radius:6px;transition:background 120ms ease}.dcu-wb-collection-head:hover,.dcu-wb-collection-head:focus-within,.dcu-wb-collection-head.dcu-wb-group-drop{background:var(--dcu-sidebar-hover)}.dcu-wb-collection-head.dcu-wb-group-drop{outline:1px solid var(--dsw-alias-state-business-primary)}.dcu-wb-collection-head[draggable=true],.dcu-wb-collection-head[draggable=true] .dcu-wb-collection-label{cursor:grab}.dcu-wb-collection-head[draggable=true]:active,.dcu-wb-collection-head[draggable=true]:active .dcu-wb-collection-label{cursor:grabbing}.dcu-wb-collection-label{display:flex;align-items:center;gap:5px;min-width:0;flex:1;border:0;padding:4px;background:transparent;color:var(--dcu-sidebar-primary);font:13px/20px var(--dcu-font,inherit);text-align:left;cursor:pointer}.dcu-wb-collection-label .dcu-wb-section-caret{position:static;order:-1;opacity:.78}.dcu-wb-collection-label[aria-expanded=true] .dcu-wb-section-caret{transform:rotate(90deg)}.dcu-wb-collection-count{margin-left:auto;color:var(--dcu-sidebar-secondary);font-variant-numeric:tabular-nums}.dcu-wb-collection-body{position:relative;min-width:0;padding-left:12px}.dcu-wb-collection-body::before{content:"";position:absolute;left:31px;top:0;bottom:8px;width:1px;background:var(--dcu-sidebar-border)}.dcu-wb-group-member{position:relative}.dcu-wb-group-member.dcu-wb-drop::before,.dcu-wb-collection.dcu-wb-group-order-drop::before,.dcu-wb-ungrouped.dcu-wb-group-order-drop::before{content:"";position:absolute;z-index:2;left:7px;right:8px;top:-8px;height:8px;pointer-events:none;background:radial-gradient(circle at 4px 50%,transparent 1.75px,var(--dsw-alias-state-business-primary) 2px 3.75px,transparent 4px),linear-gradient(var(--dsw-alias-state-business-primary),var(--dsw-alias-state-business-primary)) 10px 50%/calc(100% - 10px) 2px no-repeat}.dcu-wb-group-member.dcu-wb-drop-after::before{top:auto;bottom:-8px}.dcu-wb-collection-body .dcu-wb-project-head{padding-left:12px}
|
|
2203
2227
|
.dcu-wb-collection.dcu-wb-workspace-move-drop,.dcu-wb-ungrouped.dcu-wb-workspace-move-drop{border-radius:8px;background:color-mix(in srgb,var(--dsw-alias-state-business-primary) 9%,transparent);outline:2px solid var(--dsw-alias-state-business-primary);outline-offset:-2px}
|
|
2204
2228
|
.dcu-wb-project-head,.dcu-wb-session{position:relative;display:flex;align-items:center;gap:6px;width:100%;min-width:0;border-radius:10px;padding:0 8px;color:var(--dcu-sidebar-primary);cursor:pointer}
|
|
@@ -2305,10 +2329,10 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2305
2329
|
setPinnedWorkspaceIdsState(next);
|
|
2306
2330
|
};
|
|
2307
2331
|
const setWorkspaceGroups = (update) => {
|
|
2308
|
-
pinnedHostDirtyRef.current = true;
|
|
2309
|
-
workspaceGroupsPendingHostSyncRef.current = true;
|
|
2310
2332
|
const current = workspaceGroupsRef.current;
|
|
2311
2333
|
const next = typeof update === "function" ? update(current) : update;
|
|
2334
|
+
pinnedHostDirtyRef.current = true;
|
|
2335
|
+
workspaceGroupsPendingHostSyncRef.current = true;
|
|
2312
2336
|
workspaceGroupsRef.current = next;
|
|
2313
2337
|
setWorkspaceGroupsState(next);
|
|
2314
2338
|
};
|
|
@@ -2353,7 +2377,12 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2353
2377
|
const [createGroupOpen, setCreateGroupOpen] = (0, react.useState)(false);
|
|
2354
2378
|
const [groupTitleDraft, setGroupTitleDraft] = (0, react.useState)("");
|
|
2355
2379
|
const [deleteGroupId, setDeleteGroupId] = (0, react.useState)();
|
|
2356
|
-
const [
|
|
2380
|
+
const [groupMenuId, setGroupMenuId] = (0, react.useState)();
|
|
2381
|
+
const [renameGroupId, setRenameGroupId] = (0, react.useState)();
|
|
2382
|
+
const [renameGroupDraft, setRenameGroupDraft] = (0, react.useState)("");
|
|
2383
|
+
const [renameGroupError, setRenameGroupError] = (0, react.useState)();
|
|
2384
|
+
const groupActionTriggerRef = (0, react.useRef)();
|
|
2385
|
+
const projectsSectionButtonRef = (0, react.useRef)(null);
|
|
2357
2386
|
(0, react.useEffect)(() => {
|
|
2358
2387
|
writeTreeExpansionState(storage$1(), WORKSPACE_EXPANSION_STORAGE_KEY, expanded);
|
|
2359
2388
|
}, [expanded]);
|
|
@@ -2611,6 +2640,28 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
2611
2640
|
setError(userErrorText(reason, t));
|
|
2612
2641
|
}
|
|
2613
2642
|
};
|
|
2643
|
+
const closeRenameGroup = () => {
|
|
2644
|
+
setRenameGroupId(void 0);
|
|
2645
|
+
setRenameGroupDraft("");
|
|
2646
|
+
setRenameGroupError(void 0);
|
|
2647
|
+
const trigger = groupActionTriggerRef.current;
|
|
2648
|
+
const focusTarget = trigger?.isConnected ? trigger : projectsSectionButtonRef.current;
|
|
2649
|
+
groupActionTriggerRef.current = void 0;
|
|
2650
|
+
focusTarget?.focus();
|
|
2651
|
+
};
|
|
2652
|
+
const submitRenameGroup = () => {
|
|
2653
|
+
if (renameGroupId === void 0 || renameGroupDraft.trim() === "") return;
|
|
2654
|
+
if (workspaceGroupsRef.current.find((group) => group.id === renameGroupId)?.title === renameGroupDraft.trim()) {
|
|
2655
|
+
closeRenameGroup();
|
|
2656
|
+
return;
|
|
2657
|
+
}
|
|
2658
|
+
try {
|
|
2659
|
+
setWorkspaceGroups((current) => renameWorkspaceGroup(current, renameGroupId, renameGroupDraft));
|
|
2660
|
+
closeRenameGroup();
|
|
2661
|
+
} catch (reason) {
|
|
2662
|
+
setRenameGroupError(userErrorText(reason, t));
|
|
2663
|
+
}
|
|
2664
|
+
};
|
|
2614
2665
|
const sectionOpen = (id) => expanded[`section:${id}`] ?? true;
|
|
2615
2666
|
const toggleSection = (id) => {
|
|
2616
2667
|
setExpanded((current) => ({
|
|
@@ -3234,7 +3285,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3234
3285
|
setWorkspaceDropTarget(void 0);
|
|
3235
3286
|
setWorkspaceGroups((current) => current.find((candidate) => candidate.workspaceIds.includes(dragged))?.id === groupId ? moveWorkspaceGroupMember(current, dragged, groupId) : assignWorkspaceToGroup(current, dragged, groupId));
|
|
3236
3287
|
},
|
|
3237
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3288
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3238
3289
|
className: `dcu-wb-collection-head${workspaceGroupDragId === groupId ? " dcu-wb-dragging" : ""}`,
|
|
3239
3290
|
draggable: true,
|
|
3240
3291
|
onDragStart: (event) => {
|
|
@@ -3252,7 +3303,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3252
3303
|
setWorkspaceGroupDragId(void 0);
|
|
3253
3304
|
setWorkspaceGroupDropTarget(void 0);
|
|
3254
3305
|
},
|
|
3255
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3306
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3256
3307
|
type: "button",
|
|
3257
3308
|
className: "dcu-wb-collection-label",
|
|
3258
3309
|
"aria-expanded": isExpanded,
|
|
@@ -3277,13 +3328,74 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3277
3328
|
})
|
|
3278
3329
|
})
|
|
3279
3330
|
}),
|
|
3280
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3331
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3332
|
+
className: "dcu-wb-collection-title",
|
|
3333
|
+
children: group.title
|
|
3334
|
+
}),
|
|
3281
3335
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3282
3336
|
className: "dcu-wb-collection-count",
|
|
3283
3337
|
children: members.length
|
|
3284
3338
|
})
|
|
3285
3339
|
]
|
|
3286
|
-
})
|
|
3340
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3341
|
+
className: "dcu-wb-collection-actions",
|
|
3342
|
+
onClick: (event) => {
|
|
3343
|
+
event.stopPropagation();
|
|
3344
|
+
},
|
|
3345
|
+
onDragStart: (event) => {
|
|
3346
|
+
event.preventDefault();
|
|
3347
|
+
event.stopPropagation();
|
|
3348
|
+
},
|
|
3349
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
3350
|
+
open: groupMenuId === groupId,
|
|
3351
|
+
onClose: () => {
|
|
3352
|
+
setGroupMenuId(void 0);
|
|
3353
|
+
},
|
|
3354
|
+
items: [
|
|
3355
|
+
{
|
|
3356
|
+
id: "rename",
|
|
3357
|
+
label: t("workspace.renameGroup"),
|
|
3358
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutline16, { size: 16 })
|
|
3359
|
+
},
|
|
3360
|
+
{
|
|
3361
|
+
type: "separator",
|
|
3362
|
+
id: "group-delete-separator"
|
|
3363
|
+
},
|
|
3364
|
+
{
|
|
3365
|
+
id: "delete",
|
|
3366
|
+
label: t("workspace.deleteGroupAction"),
|
|
3367
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, { size: 16 }),
|
|
3368
|
+
danger: true
|
|
3369
|
+
}
|
|
3370
|
+
],
|
|
3371
|
+
onSelect: (action) => {
|
|
3372
|
+
setGroupMenuId(void 0);
|
|
3373
|
+
if (action === "rename") {
|
|
3374
|
+
setRenameGroupId(groupId);
|
|
3375
|
+
setRenameGroupDraft(group.title);
|
|
3376
|
+
setRenameGroupError(void 0);
|
|
3377
|
+
}
|
|
3378
|
+
if (action === "delete") setDeleteGroupId(groupId);
|
|
3379
|
+
},
|
|
3380
|
+
portal: true,
|
|
3381
|
+
dense: true,
|
|
3382
|
+
compact: true,
|
|
3383
|
+
anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3384
|
+
type: "button",
|
|
3385
|
+
className: "dcu-wb-more",
|
|
3386
|
+
draggable: false,
|
|
3387
|
+
"aria-haspopup": "menu",
|
|
3388
|
+
"aria-expanded": groupMenuId === groupId,
|
|
3389
|
+
"aria-label": t("workspace.groupActions", { name: group.title }),
|
|
3390
|
+
title: t("workspace.groupActions", { name: group.title }),
|
|
3391
|
+
onClick: (event) => {
|
|
3392
|
+
groupActionTriggerRef.current = event.currentTarget;
|
|
3393
|
+
setGroupMenuId((current) => current === groupId ? void 0 : groupId);
|
|
3394
|
+
},
|
|
3395
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutline16, { size: 16 })
|
|
3396
|
+
})
|
|
3397
|
+
})
|
|
3398
|
+
})]
|
|
3287
3399
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(DisclosureBody, {
|
|
3288
3400
|
className: "dcu-wb-collection-body",
|
|
3289
3401
|
open: isExpanded,
|
|
@@ -3397,9 +3509,9 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3397
3509
|
setWorkspaceGroups((current) => assignWorkspaceToGroup(current, dragged));
|
|
3398
3510
|
run("workspace-order", () => insertWorkspaceBefore(dragged));
|
|
3399
3511
|
},
|
|
3400
|
-
children: [/* @__PURE__ */ (0, react_jsx_runtime.
|
|
3512
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3401
3513
|
className: "dcu-wb-collection-head",
|
|
3402
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3514
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3403
3515
|
type: "button",
|
|
3404
3516
|
className: "dcu-wb-collection-label",
|
|
3405
3517
|
"aria-expanded": ungroupedExpanded,
|
|
@@ -3430,7 +3542,10 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3430
3542
|
children: ungroupedGroups.length
|
|
3431
3543
|
})
|
|
3432
3544
|
]
|
|
3433
|
-
})
|
|
3545
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3546
|
+
className: "dcu-wb-collection-actions",
|
|
3547
|
+
"aria-hidden": "true"
|
|
3548
|
+
})]
|
|
3434
3549
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DisclosureBody, {
|
|
3435
3550
|
className: "dcu-wb-collection-body",
|
|
3436
3551
|
open: ungroupedExpanded,
|
|
@@ -3611,6 +3726,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3611
3726
|
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
3612
3727
|
type: "button",
|
|
3613
3728
|
className: "dcu-wb-section-label",
|
|
3729
|
+
ref: projectsSectionButtonRef,
|
|
3614
3730
|
"aria-expanded": sectionOpen("projects"),
|
|
3615
3731
|
onClick: () => {
|
|
3616
3732
|
toggleSection("projects");
|
|
@@ -3632,9 +3748,9 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3632
3748
|
})
|
|
3633
3749
|
})
|
|
3634
3750
|
})]
|
|
3635
|
-
}), /* @__PURE__ */ (0, react_jsx_runtime.
|
|
3751
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
3636
3752
|
className: "dcu-wb-actions",
|
|
3637
|
-
children:
|
|
3753
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3638
3754
|
type: "button",
|
|
3639
3755
|
className: "dcu-wb-more",
|
|
3640
3756
|
"aria-label": t("workspace.createGroup"),
|
|
@@ -3646,36 +3762,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3646
3762
|
setCreateGroupOpen(true);
|
|
3647
3763
|
},
|
|
3648
3764
|
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutline16, { size: 16 })
|
|
3649
|
-
})
|
|
3650
|
-
open: groupMenuOpen,
|
|
3651
|
-
onClose: () => {
|
|
3652
|
-
setGroupMenuOpen(false);
|
|
3653
|
-
},
|
|
3654
|
-
items: workspaceGroups.map((group) => ({
|
|
3655
|
-
id: group.id,
|
|
3656
|
-
label: t("workspace.deleteGroup", { name: group.title }),
|
|
3657
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutline16, { size: 16 }),
|
|
3658
|
-
danger: true
|
|
3659
|
-
})),
|
|
3660
|
-
onSelect: (id) => {
|
|
3661
|
-
setDeleteGroupId(id);
|
|
3662
|
-
setGroupMenuOpen(false);
|
|
3663
|
-
},
|
|
3664
|
-
portal: true,
|
|
3665
|
-
dense: true,
|
|
3666
|
-
compact: true,
|
|
3667
|
-
anchor: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
3668
|
-
type: "button",
|
|
3669
|
-
className: "dcu-wb-more",
|
|
3670
|
-
"aria-label": t("workspace.manageGroups"),
|
|
3671
|
-
title: t("workspace.manageGroups"),
|
|
3672
|
-
onClick: (event) => {
|
|
3673
|
-
event.stopPropagation();
|
|
3674
|
-
setGroupMenuOpen((current) => !current);
|
|
3675
|
-
},
|
|
3676
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutline16, { size: 16 })
|
|
3677
|
-
})
|
|
3678
|
-
})]
|
|
3765
|
+
})
|
|
3679
3766
|
})]
|
|
3680
3767
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
3681
3768
|
className: "dcu-wb-section-body",
|
|
@@ -3881,6 +3968,57 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3881
3968
|
setPinnedWorkspaceIds((ids) => togglePinnedWorkspace(ids, id));
|
|
3882
3969
|
}
|
|
3883
3970
|
}),
|
|
3971
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
3972
|
+
open: renameGroupId !== void 0,
|
|
3973
|
+
onClose: closeRenameGroup,
|
|
3974
|
+
closeLabel: t("sessions.close"),
|
|
3975
|
+
title: t("workspace.renameGroup"),
|
|
3976
|
+
footer: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
3977
|
+
className: "dcu-wb-rename-actions",
|
|
3978
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
3979
|
+
variant: "outline",
|
|
3980
|
+
onClick: closeRenameGroup,
|
|
3981
|
+
children: t("sessions.cancel")
|
|
3982
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
|
|
3983
|
+
variant: "primary",
|
|
3984
|
+
disabled: renameGroupDraft.trim() === "",
|
|
3985
|
+
onClick: submitRenameGroup,
|
|
3986
|
+
children: t("sessions.save")
|
|
3987
|
+
})]
|
|
3988
|
+
}),
|
|
3989
|
+
children: [
|
|
3990
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
|
|
3991
|
+
htmlFor: "dcu-workspace-group-name",
|
|
3992
|
+
children: t("workspace.groupName")
|
|
3993
|
+
}),
|
|
3994
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
3995
|
+
id: "dcu-workspace-group-name",
|
|
3996
|
+
className: "dcu-wb-rename-input",
|
|
3997
|
+
"aria-label": t("workspace.groupName"),
|
|
3998
|
+
maxLength: 80,
|
|
3999
|
+
value: renameGroupDraft,
|
|
4000
|
+
autoFocus: true,
|
|
4001
|
+
onFocus: (event) => {
|
|
4002
|
+
event.target.select();
|
|
4003
|
+
},
|
|
4004
|
+
onChange: (event) => {
|
|
4005
|
+
setRenameGroupDraft(event.target.value);
|
|
4006
|
+
setRenameGroupError(void 0);
|
|
4007
|
+
},
|
|
4008
|
+
onKeyDown: (event) => {
|
|
4009
|
+
if (event.key === "Enter" && !event.nativeEvent.isComposing && event.keyCode !== 229) {
|
|
4010
|
+
event.preventDefault();
|
|
4011
|
+
submitRenameGroup();
|
|
4012
|
+
}
|
|
4013
|
+
}
|
|
4014
|
+
}),
|
|
4015
|
+
renameGroupError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
4016
|
+
className: "dcu-wb-error",
|
|
4017
|
+
role: "alert",
|
|
4018
|
+
children: t("sessions.failed", { message: renameGroupError })
|
|
4019
|
+
})
|
|
4020
|
+
]
|
|
4021
|
+
}),
|
|
3884
4022
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_deepseek_ai_dsh_client_ui_primitives.Modal, {
|
|
3885
4023
|
open: createGroupOpen,
|
|
3886
4024
|
onClose: () => {
|
|
@@ -3918,7 +4056,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3918
4056
|
setError(void 0);
|
|
3919
4057
|
},
|
|
3920
4058
|
onKeyDown: (event) => {
|
|
3921
|
-
if (event.key === "Enter") {
|
|
4059
|
+
if (event.key === "Enter" && !event.nativeEvent.isComposing && event.keyCode !== 229) {
|
|
3922
4060
|
event.preventDefault();
|
|
3923
4061
|
submitCreateGroup();
|
|
3924
4062
|
}
|
|
@@ -6580,7 +6718,8 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
6580
6718
|
"workspace.deleteGroup": "删除分组“{name}”",
|
|
6581
6719
|
"workspace.deleteGroupAction": "删除分组",
|
|
6582
6720
|
"workspace.deleteGroupDescription": "删除分组只会将其中项目移至未分组,不会删除项目或会话。",
|
|
6583
|
-
"workspace.
|
|
6721
|
+
"workspace.groupActions": "分组“{name}”的操作",
|
|
6722
|
+
"workspace.renameGroup": "重命名分组",
|
|
6584
6723
|
"workspace.recent": "最近",
|
|
6585
6724
|
"workspace.recentEmpty": "无聊天",
|
|
6586
6725
|
"workspace.noChat": "没有聊天",
|
|
@@ -6687,6 +6826,9 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
6687
6826
|
"about.installUnchanged": "安装命令已结束,但插件没有进入当前 Profile。请重试。",
|
|
6688
6827
|
"about.installExitDesktop": "请先完全退出 DSH Desktop,再重新打开后更新。",
|
|
6689
6828
|
"about.installStoreMismatch": "插件目录与 pnpm 仓库不一致。请完全退出 DSH Desktop 后再更新。",
|
|
6829
|
+
"about.installExitWeb": "无法覆盖正在运行的插件文件。请停止当前 DSH Web 后,在终端更新插件,再重新启动 DSH Web。",
|
|
6830
|
+
"about.installStoreMismatchWeb": "插件目录与 pnpm 仓库不一致。请停止当前 DSH Web 后重试;仍失败时重新安装该 Profile 的依赖。",
|
|
6831
|
+
"about.installWebFailed": "插件更新失败。请查看 DSH Web 终端输出后重试。",
|
|
6690
6832
|
"about.installBuildPolicy": "插件依赖的 pnpm 构建脚本策略尚未确认,请更新 Profile 配置后重试。",
|
|
6691
6833
|
"about.installPnpmMissing": "当前环境找不到 pnpm,请安装 pnpm 并重启 DSH 后重试。",
|
|
6692
6834
|
"about.installTimeout": "插件安装超时,请检查网络后重试。",
|
|
@@ -6780,7 +6922,8 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
6780
6922
|
"workspace.deleteGroup": "Delete group {name}",
|
|
6781
6923
|
"workspace.deleteGroupAction": "Delete group",
|
|
6782
6924
|
"workspace.deleteGroupDescription": "Deleting this group moves its projects to Ungrouped. It does not delete projects or conversations.",
|
|
6783
|
-
"workspace.
|
|
6925
|
+
"workspace.groupActions": "Actions for group {name}",
|
|
6926
|
+
"workspace.renameGroup": "Rename group",
|
|
6784
6927
|
"workspace.recent": "Recents",
|
|
6785
6928
|
"workspace.recentEmpty": "No chats",
|
|
6786
6929
|
"workspace.noChat": "No chats",
|
|
@@ -6889,6 +7032,9 @@ html[data-dcu-official-turn-navigator-supported=true] .dcu-turn-navigator,html:h
|
|
|
6889
7032
|
"about.installUnchanged": "The install command finished, but the plugin did not enter this profile. Try again.",
|
|
6890
7033
|
"about.installExitDesktop": "Quit DSH Desktop completely, reopen it, and try the update again.",
|
|
6891
7034
|
"about.installStoreMismatch": "The plugin directory and pnpm store do not match. Quit DSH Desktop completely and try again.",
|
|
7035
|
+
"about.installExitWeb": "Running plugin files cannot be replaced. Stop the current DSH Web host, update the plugin from a terminal, then restart DSH Web.",
|
|
7036
|
+
"about.installStoreMismatchWeb": "The plugin directory and pnpm store do not match. Stop the current DSH Web host and try again; if it persists, reinstall this Profile's dependencies.",
|
|
7037
|
+
"about.installWebFailed": "Plugin update failed. Check the DSH Web terminal output and try again.",
|
|
6892
7038
|
"about.installBuildPolicy": "The pnpm build-script policy for this plugin is not configured. Update the Profile configuration and try again.",
|
|
6893
7039
|
"about.installPnpmMissing": "pnpm is not available. Install pnpm, restart DSH, and try again.",
|
|
6894
7040
|
"about.installTimeout": "Plugin installation timed out. Check the network and try again.",
|
package/lib/index.mjs
CHANGED
|
@@ -515,13 +515,14 @@ async function waitUntilPluginMounted(packageName, version, runtime, timeoutMs =
|
|
|
515
515
|
}
|
|
516
516
|
throw pluginUnchangedError();
|
|
517
517
|
}
|
|
518
|
-
function pluginCommandError(stderr) {
|
|
518
|
+
function pluginCommandError(stderr, environmentKind = "desktop") {
|
|
519
519
|
const detail = stderr.replace(/\s+/g, " ").trim();
|
|
520
|
-
|
|
521
|
-
if (/
|
|
520
|
+
const isWeb = environmentKind === "cli";
|
|
521
|
+
if (/EPERM|EBUSY|EACCES|unable to unlink|ERR_PNPM_LOCKED|Lock/i.test(detail)) return /* @__PURE__ */ new Error(isWeb ? "无法覆盖正在运行的插件文件。请停止当前 DSH Web 后,在终端更新插件,再重新启动 DSH Web。" : "无法覆盖正在运行的插件文件。请先完全退出桌面端,再重新打开后更新。");
|
|
522
|
+
if (/UNEXPECTED_STORE|Unexpected store location/i.test(detail)) return /* @__PURE__ */ new Error(isWeb ? "插件目录与 pnpm 仓库不一致。请停止当前 DSH Web 后重试;仍失败时重新安装该 Profile 的依赖。" : "插件目录和 pnpm 仓库不一致。请完全退出桌面端后再更新。");
|
|
522
523
|
if (/ERR_PNPM_IGNORED_BUILDS|Ignored build scripts/i.test(detail)) return /* @__PURE__ */ new Error("插件依赖的 pnpm 构建脚本策略尚未确认。请更新 Profile 的 allowBuilds 配置后重试。");
|
|
523
524
|
if (/pnpm not found|未找到 pnpm/i.test(detail)) return /* @__PURE__ */ new Error("当前环境找不到 pnpm。请确认已安装 pnpm 后重启 DSH 再试。");
|
|
524
|
-
return /* @__PURE__ */ new Error("无法在应用运行时更新插件。请先完全退出桌面端,再重新打开后更新。");
|
|
525
|
+
return /* @__PURE__ */ new Error(isWeb ? "插件更新失败。请查看 DSH Web 终端输出后重试。" : "无法在应用运行时更新插件。请先完全退出桌面端,再重新打开后更新。");
|
|
525
526
|
}
|
|
526
527
|
/**
|
|
527
528
|
* 图形界面或桌面启动往往没有 shell PATH。把 pnpm 常见安装目录补进去,
|
|
@@ -606,7 +607,7 @@ function disposeDependencyInstaller() {
|
|
|
606
607
|
for (const child of activePluginChildren) terminatePluginChild(child);
|
|
607
608
|
for (const handle of activeDesktopPluginHandles) handle.cancel();
|
|
608
609
|
}
|
|
609
|
-
function monitorPluginChild(child, timeoutMs = PLUGIN_INSTALL_TIMEOUT_MS) {
|
|
610
|
+
function monitorPluginChild(child, timeoutMs = PLUGIN_INSTALL_TIMEOUT_MS, environmentKind = "cli") {
|
|
610
611
|
return new Promise((resolvePromise, reject) => {
|
|
611
612
|
activePluginChildren.add(child);
|
|
612
613
|
let output = "";
|
|
@@ -629,7 +630,7 @@ function monitorPluginChild(child, timeoutMs = PLUGIN_INSTALL_TIMEOUT_MS) {
|
|
|
629
630
|
finish(/* @__PURE__ */ new Error("无法启动 DSH 插件安装命令。请确认 Node.js 与 pnpm 可用后重试。"));
|
|
630
631
|
});
|
|
631
632
|
child.once("exit", (code) => {
|
|
632
|
-
finish(code === 0 ? void 0 : pluginCommandError(output));
|
|
633
|
+
finish(code === 0 ? void 0 : pluginCommandError(output, environmentKind));
|
|
633
634
|
});
|
|
634
635
|
const timeout = setTimeout(() => {
|
|
635
636
|
terminatePluginChild(child);
|
|
@@ -666,9 +667,9 @@ function monitorDesktopPlugin(handle, timeoutMs = PLUGIN_INSTALL_TIMEOUT_MS) {
|
|
|
666
667
|
finish(/* @__PURE__ */ new Error("无法读取 DSH Desktop 插件安装输出。"));
|
|
667
668
|
});
|
|
668
669
|
handle.done.then((outcome) => {
|
|
669
|
-
finish(outcome.exitCode === 0 && outcome.signal === null ? void 0 : pluginCommandError(output));
|
|
670
|
+
finish(outcome.exitCode === 0 && outcome.signal === null ? void 0 : pluginCommandError(output, "desktop"));
|
|
670
671
|
}, () => {
|
|
671
|
-
finish(pluginCommandError(output));
|
|
672
|
+
finish(pluginCommandError(output, "desktop"));
|
|
672
673
|
});
|
|
673
674
|
const timeout = setTimeout(() => {
|
|
674
675
|
handle.cancel();
|
|
@@ -697,7 +698,7 @@ function runDshPlugin(args, runtime = resolveDependencyRuntime(), timeoutMs = PL
|
|
|
697
698
|
"pipe",
|
|
698
699
|
"pipe"
|
|
699
700
|
]
|
|
700
|
-
}), timeoutMs);
|
|
701
|
+
}), timeoutMs, runtime.environmentKind);
|
|
701
702
|
}
|
|
702
703
|
/** 并发安装互斥:pnpm 锁文件竞争会触发 EPERM/EBUSY,同一时间只允许一个安装进程。 */
|
|
703
704
|
let installing = false;
|
|
@@ -1446,8 +1447,8 @@ async function moveSessionToWorkspace(services, sessionId, targetWorkspaceId, op
|
|
|
1446
1447
|
movingSessions.delete(sessionId);
|
|
1447
1448
|
}
|
|
1448
1449
|
}
|
|
1449
|
-
/**
|
|
1450
|
-
function
|
|
1450
|
+
/** 校验结构和归属;存储兼容模式保留旧 locale 下合法的大小写变体名称。 */
|
|
1451
|
+
function parseGroups(value, preserveCaseVariants) {
|
|
1451
1452
|
if (!Array.isArray(value) || value.length > 100) return void 0;
|
|
1452
1453
|
const groupIds = /* @__PURE__ */ new Set();
|
|
1453
1454
|
const groupTitles = /* @__PURE__ */ new Set();
|
|
@@ -1459,13 +1460,14 @@ function parseWorkspaceGroups(value) {
|
|
|
1459
1460
|
const id = typeof group.id === "string" ? group.id.trim() : "";
|
|
1460
1461
|
const title = typeof group.title === "string" ? group.title.trim() : "";
|
|
1461
1462
|
if (id === "" || id.length > 128 || title === "" || title.length > 80) return void 0;
|
|
1462
|
-
|
|
1463
|
+
const titleKey = preserveCaseVariants ? title : title.toLowerCase();
|
|
1464
|
+
if (groupIds.has(id) || groupTitles.has(titleKey)) return void 0;
|
|
1463
1465
|
if (!Array.isArray(group.workspaceIds) || group.workspaceIds.length > 1e3) return void 0;
|
|
1464
1466
|
const normalizedIds = [...new Set(group.workspaceIds)];
|
|
1465
1467
|
if (!normalizedIds.every((workspaceId) => typeof workspaceId === "string" && workspaceId.trim() !== "" && workspaceId.length <= 256)) return void 0;
|
|
1466
1468
|
if (normalizedIds.some((workspaceId) => workspaceIds.has(workspaceId))) return void 0;
|
|
1467
1469
|
groupIds.add(id);
|
|
1468
|
-
groupTitles.add(
|
|
1470
|
+
groupTitles.add(titleKey);
|
|
1469
1471
|
normalizedIds.forEach((workspaceId) => workspaceIds.add(workspaceId));
|
|
1470
1472
|
groups.push({
|
|
1471
1473
|
id,
|
|
@@ -1475,6 +1477,10 @@ function parseWorkspaceGroups(value) {
|
|
|
1475
1477
|
}
|
|
1476
1478
|
return groups;
|
|
1477
1479
|
}
|
|
1480
|
+
/** 旧数据可往返保存且不改名;新名称的大小写判重由创建、重命名操作执行。 */
|
|
1481
|
+
function parseStoredWorkspaceGroups(value) {
|
|
1482
|
+
return parseGroups(value, true);
|
|
1483
|
+
}
|
|
1478
1484
|
//#endregion
|
|
1479
1485
|
//#region src/workspace-preferences.ts
|
|
1480
1486
|
const WORKSPACE_PREFERENCES_FILE = ".dsh-codex-ui-preferences.json";
|
|
@@ -1499,7 +1505,7 @@ function parseWorkspacePreferences(value) {
|
|
|
1499
1505
|
workspaceGroups: []
|
|
1500
1506
|
};
|
|
1501
1507
|
if (record.version !== 2) return void 0;
|
|
1502
|
-
const workspaceGroups =
|
|
1508
|
+
const workspaceGroups = parseStoredWorkspaceGroups(record.workspaceGroups);
|
|
1503
1509
|
return workspaceGroups === void 0 ? void 0 : {
|
|
1504
1510
|
version: 2,
|
|
1505
1511
|
pinnedWorkspaceIds,
|
|
@@ -1531,7 +1537,7 @@ let writeQueue = Promise.resolve();
|
|
|
1531
1537
|
/** 串行、原子保存,避免快速拖动排序产生乱序或半截 JSON。 */
|
|
1532
1538
|
function writeWorkspacePreferences(pinnedWorkspaceIds, workspaceGroups = [], path = workspacePreferencesPath()) {
|
|
1533
1539
|
const normalized = parsePinnedWorkspaceIds([...pinnedWorkspaceIds]);
|
|
1534
|
-
const normalizedGroups =
|
|
1540
|
+
const normalizedGroups = parseStoredWorkspaceGroups([...workspaceGroups]);
|
|
1535
1541
|
if (normalized === void 0 || normalizedGroups === void 0) return Promise.reject(/* @__PURE__ */ new Error("工作区偏好数据无效。"));
|
|
1536
1542
|
const task = writeQueue.catch(() => void 0).then(async () => {
|
|
1537
1543
|
await mkdir(dirname(path), { recursive: true });
|
|
@@ -1817,8 +1823,9 @@ function apply(ctx) {
|
|
|
1817
1823
|
const record = body !== null && typeof body === "object" ? body : void 0;
|
|
1818
1824
|
const pinnedWorkspaceIds = record === void 0 ? void 0 : parsePinnedWorkspaceIds(record.pinnedWorkspaceIds);
|
|
1819
1825
|
const existing = await readWorkspacePreferences();
|
|
1820
|
-
const workspaceGroups = record === void 0 ? void 0 : "workspaceGroups" in record ?
|
|
1821
|
-
|
|
1826
|
+
const workspaceGroups = record === void 0 ? void 0 : "workspaceGroups" in record ? parseStoredWorkspaceGroups(record.workspaceGroups) : existing.workspaceGroups;
|
|
1827
|
+
const introducesTitleConflict = workspaceGroups?.some((group) => !existing.workspaceGroups.some((previous) => previous.id === group.id && previous.title === group.title) && workspaceGroups.some((other) => other.id !== group.id && other.title.toLowerCase() === group.title.toLowerCase())) === true;
|
|
1828
|
+
if (pinnedWorkspaceIds === void 0 || workspaceGroups === void 0 || introducesTitleConflict) {
|
|
1822
1829
|
response.writeHead(400, {
|
|
1823
1830
|
"content-type": "application/json; charset=utf-8",
|
|
1824
1831
|
"cache-control": "no-store"
|