@michengai/dsh-codex-ui 0.2.59 → 0.2.61
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/dist/client.js +395 -60
- package/dist/index.mjs +119 -39
- package/package.json +6 -6
package/dist/client.js
CHANGED
|
@@ -262,6 +262,7 @@ window.__ModuleLoader__.load({
|
|
|
262
262
|
//#endregion
|
|
263
263
|
//#region src/client/session-manager.ts
|
|
264
264
|
const SESSION_PINS_STORAGE_KEY = "dsh.session-pins.v1";
|
|
265
|
+
const SESSION_SECTION_PINS_STORAGE_KEY = "dsh-codex-ui.pinned-section-sessions.v1";
|
|
265
266
|
const SESSION_UNREAD_STORAGE_KEY = "dsh.session-unread.v1";
|
|
266
267
|
function normalizeSessionIds(ids) {
|
|
267
268
|
return [...new Set(ids.filter((id) => id.trim() !== ""))];
|
|
@@ -294,6 +295,15 @@ window.__ModuleLoader__.load({
|
|
|
294
295
|
url.searchParams.set("session", sessionId);
|
|
295
296
|
return url.toString();
|
|
296
297
|
}
|
|
298
|
+
/** 把会话插入置顶列表的指定位置;省略锚点时追加到末尾。 */
|
|
299
|
+
function insertSessionId(ids, id, beforeId) {
|
|
300
|
+
const next = ids.filter((item) => item !== id);
|
|
301
|
+
if (beforeId === void 0) return [...next, id];
|
|
302
|
+
if (beforeId === id) return ids.includes(id) ? [...ids] : [...next, id];
|
|
303
|
+
const index = next.indexOf(beforeId);
|
|
304
|
+
next.splice(index < 0 ? next.length : index, 0, id);
|
|
305
|
+
return next;
|
|
306
|
+
}
|
|
297
307
|
//#endregion
|
|
298
308
|
//#region src/client/session-tree.tsx
|
|
299
309
|
function PinIcon() {
|
|
@@ -430,19 +440,33 @@ window.__ModuleLoader__.load({
|
|
|
430
440
|
function pointerMenuRect(x, y) {
|
|
431
441
|
return new DOMRect(x, y, 0, 0);
|
|
432
442
|
}
|
|
433
|
-
function SessionRow({ id, title, selected, menuOpen, pinned, unread, running, t, menuItems, onOpen, onMenuChange, onSelectAction, onPin, onArchive, onHover, onLeave, onContextMenu, menuPoint }) {
|
|
443
|
+
function SessionRow({ id, title, selected, menuOpen, pinned, unread, running, t, menuItems, onOpen, onMenuChange, onSelectAction, onPin, onArchive, onHover, onLeave, onContextMenu, menuPoint, subtitle, flat, draggable, dropActive, onDragStart, onDragEnd, onDragOver, onDrop }) {
|
|
434
444
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
435
|
-
className: `dcu-wb-session${selected ? " dcu-wb-selected" : ""}${menuOpen ? " dcu-wb-menu-open" : ""}`,
|
|
445
|
+
className: `dcu-wb-session${selected ? " dcu-wb-selected" : ""}${menuOpen ? " dcu-wb-menu-open" : ""}${dropActive === true ? " dcu-wb-drop" : ""}${flat === true ? " dcu-wb-session-flat" : ""}`,
|
|
436
446
|
role: "treeitem",
|
|
437
447
|
"aria-selected": selected,
|
|
448
|
+
draggable,
|
|
449
|
+
onDragStart,
|
|
450
|
+
onDragEnd,
|
|
451
|
+
onDragOver,
|
|
452
|
+
onDrop,
|
|
438
453
|
onClick: onOpen,
|
|
439
454
|
onContextMenu,
|
|
440
455
|
onMouseEnter: onHover,
|
|
441
456
|
onMouseLeave: onLeave,
|
|
442
457
|
children: [
|
|
443
|
-
/* @__PURE__ */ (0, react_jsx_runtime.
|
|
458
|
+
subtitle !== void 0 && subtitle !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
459
|
+
className: "dcu-wb-session-copy",
|
|
460
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
461
|
+
className: "dcu-wb-session-title",
|
|
462
|
+
children: title.split(/\r?\n/)[0] ?? title
|
|
463
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
464
|
+
className: "dcu-wb-session-sub",
|
|
465
|
+
children: subtitle
|
|
466
|
+
})]
|
|
467
|
+
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
444
468
|
className: "dcu-wb-session-title",
|
|
445
|
-
children: title
|
|
469
|
+
children: title.split(/\r?\n/)[0] ?? title
|
|
446
470
|
}),
|
|
447
471
|
pinned && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
448
472
|
className: "dcu-wb-pin",
|
|
@@ -1097,6 +1121,65 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1097
1121
|
return item === void 0 ? [] : [item];
|
|
1098
1122
|
});
|
|
1099
1123
|
}
|
|
1124
|
+
/** 置顶区的会话按拖入顺序展示;不因父项目已置顶而隐藏。 */
|
|
1125
|
+
function standalonePinnedSessionIds(pinnedSessionIds) {
|
|
1126
|
+
return [...pinnedSessionIds];
|
|
1127
|
+
}
|
|
1128
|
+
/** 置顶区已有会话时,不再同时展示任何项目文件夹,避免旧置顶项目叠成两条。 */
|
|
1129
|
+
function workspaceIdsHiddenByPinnedSessions(workspaces, pinnedSessionIds) {
|
|
1130
|
+
if (pinnedSessionIds.length === 0) return [];
|
|
1131
|
+
return workspaces.map((workspace) => String(workspace.workspaceId));
|
|
1132
|
+
}
|
|
1133
|
+
const SESSION_DRAG_TYPE = "application/x-dcu-session";
|
|
1134
|
+
const WORKSPACE_DRAG_TYPE = "application/x-dcu-workspace";
|
|
1135
|
+
const SESSION_DRAG_PREFIX = "dcu-session:";
|
|
1136
|
+
const WORKSPACE_DRAG_PREFIX = "dcu-workspace:";
|
|
1137
|
+
function dragTypes(data) {
|
|
1138
|
+
return data === void 0 ? [] : Array.from(data.types);
|
|
1139
|
+
}
|
|
1140
|
+
function textPayload(data) {
|
|
1141
|
+
try {
|
|
1142
|
+
return data?.getData("text/plain") ?? "";
|
|
1143
|
+
} catch {
|
|
1144
|
+
return "";
|
|
1145
|
+
}
|
|
1146
|
+
}
|
|
1147
|
+
/** 拖过置顶区时用来决定是否 preventDefault;只看 types,不读数据。 */
|
|
1148
|
+
function isSidebarItemDrag(data) {
|
|
1149
|
+
const types = dragTypes(data);
|
|
1150
|
+
return types.includes("application/x-dcu-session") || types.includes("application/x-dcu-workspace") || types.includes("text/plain");
|
|
1151
|
+
}
|
|
1152
|
+
/** 写入会话拖拽载荷;drop 时以这个为准,不依赖尚未刷新的 React 状态。 */
|
|
1153
|
+
function writeSessionDrag(data, sessionId, title) {
|
|
1154
|
+
data.effectAllowed = "move";
|
|
1155
|
+
data.setData("text/plain", `${SESSION_DRAG_PREFIX}${sessionId}`);
|
|
1156
|
+
data.setData(SESSION_DRAG_TYPE, sessionId);
|
|
1157
|
+
}
|
|
1158
|
+
function writeWorkspaceDrag(data, workspaceId, title) {
|
|
1159
|
+
data.effectAllowed = "move";
|
|
1160
|
+
data.setData("text/plain", `${WORKSPACE_DRAG_PREFIX}${workspaceId}`);
|
|
1161
|
+
data.setData(WORKSPACE_DRAG_TYPE, workspaceId);
|
|
1162
|
+
}
|
|
1163
|
+
function readSessionDrag(data, fallback) {
|
|
1164
|
+
try {
|
|
1165
|
+
const typed = data?.getData(SESSION_DRAG_TYPE);
|
|
1166
|
+
if (typed !== void 0 && typed.trim() !== "") return typed;
|
|
1167
|
+
} catch {}
|
|
1168
|
+
const text = textPayload(data);
|
|
1169
|
+
if (text.startsWith(SESSION_DRAG_PREFIX)) return text.slice(12);
|
|
1170
|
+
return fallback !== void 0 && fallback.trim() !== "" ? fallback : void 0;
|
|
1171
|
+
}
|
|
1172
|
+
/** 会话拖拽优先;有会话载荷时不得再把父项目置顶。 */
|
|
1173
|
+
function readWorkspaceDrag(data, fallback) {
|
|
1174
|
+
if (readSessionDrag(data) !== void 0) return void 0;
|
|
1175
|
+
try {
|
|
1176
|
+
const typed = data?.getData(WORKSPACE_DRAG_TYPE);
|
|
1177
|
+
if (typed !== void 0 && typed.trim() !== "") return typed;
|
|
1178
|
+
} catch {}
|
|
1179
|
+
const text = textPayload(data);
|
|
1180
|
+
if (text.startsWith(WORKSPACE_DRAG_PREFIX)) return text.slice(14);
|
|
1181
|
+
return fallback !== void 0 && fallback.trim() !== "" ? fallback : void 0;
|
|
1182
|
+
}
|
|
1100
1183
|
//#endregion
|
|
1101
1184
|
//#region src/client/CodexWorkspaceBrowser.tsx
|
|
1102
1185
|
const stylesheet$4 = `
|
|
@@ -1111,13 +1194,13 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1111
1194
|
.dcu-wb-project-head:hover,.dcu-wb-project-head.dcu-wb-menu-open,.dcu-wb-session:hover,.dcu-wb-session.dcu-wb-selected,.dcu-wb-session.dcu-wb-menu-open{background:var(--dcu-sidebar-hover)}.dcu-wb-project-head+.dcu-wb-session,.dcu-wb-project-head+.dcu-wb-nochat{margin-top:4px}.dcu-wb-session+.dcu-wb-session{margin-top:2px}
|
|
1112
1195
|
.dcu-wb-project-head[draggable=true],.dcu-wb-session[draggable=true]{cursor:grab}
|
|
1113
1196
|
.dcu-wb-project-head[draggable=true]:active,.dcu-wb-session[draggable=true]:active{cursor:grabbing}
|
|
1114
|
-
.dcu-wb-section,.dcu-wb-section:focus,.dcu-wb-section:focus-visible,.dcu-wb-project-head:focus,.dcu-wb-session:focus{outline:0}.dcu-wb-pin-end{position:relative;height:8px}.dcu-wb-project-head.dcu-wb-drop::before,.dcu-wb-session.dcu-wb-drop::before,.dcu-wb-pin-end.dcu-wb-drop::before,.dcu-wb-
|
|
1197
|
+
.dcu-wb-section,.dcu-wb-section:focus,.dcu-wb-section:focus-visible,.dcu-wb-project-head:focus,.dcu-wb-session:focus{outline:0}.dcu-wb-pin-end,.dcu-wb-pin-start{position:relative;height:8px}.dcu-wb-project-head.dcu-wb-drop::before,.dcu-wb-session.dcu-wb-drop::before,.dcu-wb-pin-end.dcu-wb-drop::before,.dcu-wb-pin-start.dcu-wb-drop::before{content:"";position:absolute;left:8px;right:8px;top:-4px;height:8px;pointer-events:none;background:radial-gradient(circle at 4px 50%,var(--dsw-alias-state-business-primary) 3.25px,transparent 3.45px),linear-gradient(var(--dsw-alias-state-business-primary),var(--dsw-alias-state-business-primary)) 10px 50%/calc(100% - 10px) 2px no-repeat}.dcu-wb-project-head.dcu-wb-drop-after::before,.dcu-wb-session.dcu-wb-drop-after::before{top:auto;bottom:-4px}.dcu-wb-dragging{opacity:.28}.dcu-wb-drag-ghost{position:fixed;top:-120px;left:-240px;z-index:10040;max-width:220px;height:32px;padding:0 10px;border:1px solid var(--dcu-sidebar-border);border-radius:8px;background:var(--dcu-sidebar-hover);color:var(--dcu-sidebar-primary);font:13px/32px var(--dcu-font,inherit);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;pointer-events:none}
|
|
1115
1198
|
.dcu-wb-folder{display:grid;place-items:center;flex:none;width:16px;height:20px;color:var(--dcu-sidebar-icon)}.dcu-wb-brand{display:block;width:16px;height:16px}
|
|
1116
1199
|
.dcu-wb-project-current .dcu-wb-folder{color:var(--dsw-alias-state-business-primary)}
|
|
1117
1200
|
.dcu-wb-project-title,.dcu-wb-session-title{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;line-height:20px}
|
|
1118
1201
|
.dcu-wb-project-title{flex:1;font-weight:550;color:var(--dcu-sidebar-primary)}
|
|
1119
1202
|
.dcu-wb-session{position:relative;min-height:32px;gap:0;padding-left:28px}
|
|
1120
|
-
.dcu-wb-session-title{flex:1;margin-left:0}
|
|
1203
|
+
.dcu-wb-session-title{flex:1;margin-left:0}.dcu-wb-session-copy{flex:1;min-width:0;display:flex;flex-direction:column;justify-content:center}.dcu-wb-session-sub{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dcu-sidebar-tertiary);font-size:12px;line-height:16px}.dcu-wb-session-flat,.dcu-wb-session-top{padding-left:8px}
|
|
1121
1204
|
.dcu-wb-pin{display:grid;place-items:center;flex:none;width:16px;height:20px;margin-left:6px;color:var(--dcu-sidebar-tertiary)}
|
|
1122
1205
|
.dcu-wb-pin svg,.dcu-wb-quick-pin svg{width:13px;height:13px;fill:none;stroke:currentColor;stroke-linecap:round;stroke-linejoin:round;stroke-width:1.4}
|
|
1123
1206
|
.dcu-wb-actions{display:none;align-items:center;gap:8px;flex:none}
|
|
@@ -1162,6 +1245,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1162
1245
|
const [expanded, setExpanded] = (0, react.useState)({});
|
|
1163
1246
|
const [pinnedWorkspaceIds, setPinnedWorkspaceIds] = (0, react.useState)(() => readPinnedWorkspaceIds(storage$1()));
|
|
1164
1247
|
const [pinnedSessionIds, setPinnedSessionIds] = (0, react.useState)(() => readSessionIds(storage$1(), SESSION_PINS_STORAGE_KEY));
|
|
1248
|
+
const [sectionSessionIds, setSectionSessionIds] = (0, react.useState)(() => readSessionIds(storage$1(), SESSION_SECTION_PINS_STORAGE_KEY));
|
|
1165
1249
|
const [unreadSessionIds, setUnreadSessionIds] = (0, react.useState)(() => readSessionIds(storage$1(), SESSION_UNREAD_STORAGE_KEY));
|
|
1166
1250
|
const [menu, setMenu] = (0, react.useState)();
|
|
1167
1251
|
const [renameTarget, setRenameTarget] = (0, react.useState)();
|
|
@@ -1176,6 +1260,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1176
1260
|
const [error, setError] = (0, react.useState)();
|
|
1177
1261
|
const [workspaceDragId, setWorkspaceDragId] = (0, react.useState)();
|
|
1178
1262
|
const [workspaceDropId, setWorkspaceDropId] = (0, react.useState)();
|
|
1263
|
+
const [workspaceDropAfter, setWorkspaceDropAfter] = (0, react.useState)(false);
|
|
1179
1264
|
const [headerMenu, setHeaderMenu] = (0, react.useState)();
|
|
1180
1265
|
const headerMenuRef = (0, react.useRef)();
|
|
1181
1266
|
headerMenuRef.current = headerMenu;
|
|
@@ -1189,6 +1274,13 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1189
1274
|
(0, react.useEffect)(() => {
|
|
1190
1275
|
writeSessionIds(storage$1(), SESSION_PINS_STORAGE_KEY, pinnedSessionIds);
|
|
1191
1276
|
}, [pinnedSessionIds]);
|
|
1277
|
+
(0, react.useEffect)(() => {
|
|
1278
|
+
writeSessionIds(storage$1(), SESSION_SECTION_PINS_STORAGE_KEY, sectionSessionIds);
|
|
1279
|
+
}, [sectionSessionIds]);
|
|
1280
|
+
(0, react.useEffect)(() => {
|
|
1281
|
+
if (sectionSessionIds.length === 0) return;
|
|
1282
|
+
setPinnedWorkspaceIds((ids) => ids.length === 0 ? ids : []);
|
|
1283
|
+
}, [sectionSessionIds]);
|
|
1192
1284
|
(0, react.useEffect)(() => {
|
|
1193
1285
|
writeSessionIds(storage$1(), SESSION_UNREAD_STORAGE_KEY, unreadSessionIds);
|
|
1194
1286
|
}, [unreadSessionIds]);
|
|
@@ -1275,11 +1367,14 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1275
1367
|
sessions.current,
|
|
1276
1368
|
menu
|
|
1277
1369
|
]);
|
|
1278
|
-
const
|
|
1279
|
-
const
|
|
1370
|
+
const pinSectionSessions = standalonePinnedSessionIds(sectionSessionIds);
|
|
1371
|
+
const hiddenPinnedWorkspaceIds = new Set(workspaceIdsHiddenByPinnedSessions(groups.items, pinSectionSessions));
|
|
1372
|
+
const projectPinned = (id) => pinnedWorkspaceIds.includes(String(id)) && !hiddenPinnedWorkspaceIds.has(String(id));
|
|
1373
|
+
const pinnedGroups = orderByIds(groups.items, pinnedWorkspaceIds, (workspace) => String(workspace.workspaceId)).filter((workspace) => !hiddenPinnedWorkspaceIds.has(String(workspace.workspaceId)));
|
|
1280
1374
|
const regularGroups = groups.items.filter((workspace) => !projectPinned(workspace.workspaceId));
|
|
1375
|
+
const pinDragActive = workspaceDragId !== void 0 || sessionDrag !== void 0;
|
|
1281
1376
|
const assignedIds = workspaces.items.flatMap((workspace) => workspace.sessionIds.map((id) => String(id)));
|
|
1282
|
-
const recentIds = ungroupedSessionIds(sessions.ids ?? Object.keys(sessions.byId), sessions.byId, assignedIds, workspaces.archivedSessionIds).sort((left, right) => (sessions.byId[right]?.updatedAt ?? 0) - (sessions.byId[left]?.updatedAt ?? 0));
|
|
1377
|
+
const recentIds = ungroupedSessionIds(sessions.ids ?? Object.keys(sessions.byId), sessions.byId, assignedIds, workspaces.archivedSessionIds).filter((id) => !pinSectionSessions.includes(id)).sort((left, right) => (sessions.byId[right]?.updatedAt ?? 0) - (sessions.byId[left]?.updatedAt ?? 0));
|
|
1283
1378
|
const run = async (key, action) => {
|
|
1284
1379
|
setBusy(key);
|
|
1285
1380
|
setError(void 0);
|
|
@@ -1317,6 +1412,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1317
1412
|
if (target.kind === "session") {
|
|
1318
1413
|
await deleteSession(target.id);
|
|
1319
1414
|
setPinnedSessionIds((ids) => ids.filter((id) => id !== target.id));
|
|
1415
|
+
setSectionSessionIds((ids) => ids.filter((id) => id !== target.id));
|
|
1320
1416
|
setUnreadSessionIds((ids) => ids.filter((id) => id !== target.id));
|
|
1321
1417
|
} else {
|
|
1322
1418
|
await deleteWorkspace(target.id);
|
|
@@ -1331,10 +1427,10 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1331
1427
|
await (0, _deepseek_ai_dsh_client_ui_primitives.writeClipboard)(value);
|
|
1332
1428
|
});
|
|
1333
1429
|
};
|
|
1334
|
-
const toggleGroup = (
|
|
1430
|
+
const toggleGroup = (key, defaultOpen = true) => {
|
|
1335
1431
|
setExpanded((current) => ({
|
|
1336
1432
|
...current,
|
|
1337
|
-
[
|
|
1433
|
+
[key]: !(current[key] ?? defaultOpen)
|
|
1338
1434
|
}));
|
|
1339
1435
|
};
|
|
1340
1436
|
const sectionOpen = (id) => expanded[`section:${id}`] ?? true;
|
|
@@ -1385,8 +1481,14 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1385
1481
|
const pinWorkspaceAt = (id, beforeId) => {
|
|
1386
1482
|
setPinnedWorkspaceIds((ids) => insertPinnedWorkspace(ids, id, beforeId));
|
|
1387
1483
|
};
|
|
1484
|
+
const pinSessionAt = (id, beforeId) => {
|
|
1485
|
+
setSectionSessionIds((ids) => insertSessionId(ids, id, beforeId));
|
|
1486
|
+
setPinnedWorkspaceIds((ids) => ids.length === 0 ? ids : []);
|
|
1487
|
+
};
|
|
1388
1488
|
const renderGroup = (workspace, zone) => {
|
|
1389
|
-
const
|
|
1489
|
+
const expandKey = zone === "pinned" ? `pin:${workspace.workspaceId}` : String(workspace.workspaceId);
|
|
1490
|
+
const isExpanded = expanded[expandKey] ?? zone !== "pinned";
|
|
1491
|
+
const shownIds = workspace.visibleIds.filter((id) => !pinSectionSessions.includes(id));
|
|
1390
1492
|
const menuOpen = menu?.type === "workspace" && menu.id === workspace.workspaceId;
|
|
1391
1493
|
const menuAt = menuOpen && menu.x !== void 0 && menu.y !== void 0 ? {
|
|
1392
1494
|
x: menu.x,
|
|
@@ -1396,27 +1498,43 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1396
1498
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1397
1499
|
className: `dcu-wb-project${isCurrentWorkspace ? " dcu-wb-project-current" : ""}`,
|
|
1398
1500
|
onDragOver: (event) => {
|
|
1399
|
-
if (workspaceDragId === void 0) return;
|
|
1501
|
+
if (workspaceDragId === void 0 && !isSidebarItemDrag(event.dataTransfer) && !(zone === "pinned" && sessionDrag !== void 0)) return;
|
|
1400
1502
|
event.preventDefault();
|
|
1401
1503
|
event.stopPropagation();
|
|
1504
|
+
event.dataTransfer.dropEffect = "move";
|
|
1402
1505
|
const after = event.clientY > event.currentTarget.getBoundingClientRect().top + event.currentTarget.getBoundingClientRect().height / 2;
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1506
|
+
const id = String(workspace.workspaceId);
|
|
1507
|
+
const ids = (zone === "pinned" ? pinnedGroups : regularGroups).map((item) => String(item.workspaceId));
|
|
1508
|
+
const last = ids.length > 0 && ids[ids.length - 1] === id;
|
|
1509
|
+
if (zone === "pinned" && after && last) {
|
|
1510
|
+
setPinSlot("end");
|
|
1511
|
+
setWorkspaceDropId(void 0);
|
|
1512
|
+
setWorkspaceDropAfter(false);
|
|
1407
1513
|
} else {
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1514
|
+
setPinSlot(zone === "pinned" ? id : void 0);
|
|
1515
|
+
setWorkspaceDropId(id);
|
|
1516
|
+
setWorkspaceDropAfter(after);
|
|
1411
1517
|
}
|
|
1412
1518
|
},
|
|
1413
1519
|
onDrop: (event) => {
|
|
1414
1520
|
event.preventDefault();
|
|
1415
1521
|
event.stopPropagation();
|
|
1416
|
-
const
|
|
1522
|
+
const droppedSession = readSessionDrag(event.dataTransfer, sessionDrag?.sessionId);
|
|
1523
|
+
if (zone === "pinned" && droppedSession !== void 0) {
|
|
1524
|
+
setSessionDrag(void 0);
|
|
1525
|
+
setSessionDropId(void 0);
|
|
1526
|
+
setWorkspaceDragId(void 0);
|
|
1527
|
+
setWorkspaceDropId(void 0);
|
|
1528
|
+
setWorkspaceDropAfter(false);
|
|
1529
|
+
setPinSlot(void 0);
|
|
1530
|
+
pinSessionAt(droppedSession);
|
|
1531
|
+
return;
|
|
1532
|
+
}
|
|
1533
|
+
const dragged = readWorkspaceDrag(event.dataTransfer, workspaceDragId);
|
|
1417
1534
|
const after = event.clientY > event.currentTarget.getBoundingClientRect().top + event.currentTarget.getBoundingClientRect().height / 2;
|
|
1418
1535
|
setWorkspaceDragId(void 0);
|
|
1419
1536
|
setWorkspaceDropId(void 0);
|
|
1537
|
+
setWorkspaceDropAfter(false);
|
|
1420
1538
|
setPinSlot(void 0);
|
|
1421
1539
|
if (dragged === void 0) return;
|
|
1422
1540
|
if (zone === "pinned") {
|
|
@@ -1431,14 +1549,15 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1431
1549
|
},
|
|
1432
1550
|
children: [
|
|
1433
1551
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
1434
|
-
className: `dcu-wb-project-head${menuOpen ? " dcu-wb-menu-open" : ""}${workspaceDropId === workspace.workspaceId ? " dcu-wb-drop" : ""}`,
|
|
1552
|
+
className: `dcu-wb-project-head${menuOpen ? " dcu-wb-menu-open" : ""}${workspaceDropId === workspace.workspaceId ? workspaceDropAfter ? " dcu-wb-drop dcu-wb-drop-after" : " dcu-wb-drop" : ""}${workspaceDragId === String(workspace.workspaceId) ? " dcu-wb-dragging" : ""}`,
|
|
1435
1553
|
role: "treeitem",
|
|
1436
1554
|
"aria-expanded": isExpanded,
|
|
1437
1555
|
tabIndex: 0,
|
|
1438
1556
|
draggable: true,
|
|
1439
1557
|
onDragStart: (event) => {
|
|
1440
|
-
event.
|
|
1441
|
-
|
|
1558
|
+
event.stopPropagation();
|
|
1559
|
+
setSessionDrag(void 0);
|
|
1560
|
+
writeWorkspaceDrag(event.dataTransfer, String(workspace.workspaceId), workspace.title);
|
|
1442
1561
|
const preview = document.createElement("div");
|
|
1443
1562
|
preview.className = "dcu-wb-drag-ghost";
|
|
1444
1563
|
preview.textContent = workspace.title;
|
|
@@ -1452,10 +1571,11 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1452
1571
|
onDragEnd: () => {
|
|
1453
1572
|
setWorkspaceDragId(void 0);
|
|
1454
1573
|
setWorkspaceDropId(void 0);
|
|
1574
|
+
setWorkspaceDropAfter(false);
|
|
1455
1575
|
setPinSlot(void 0);
|
|
1456
1576
|
},
|
|
1457
1577
|
onClick: () => {
|
|
1458
|
-
toggleGroup(
|
|
1578
|
+
if (zone !== "pinned") toggleGroup(expandKey, true);
|
|
1459
1579
|
},
|
|
1460
1580
|
onContextMenu: (event) => {
|
|
1461
1581
|
event.preventDefault();
|
|
@@ -1484,7 +1604,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1484
1604
|
onKeyDown: (event) => {
|
|
1485
1605
|
if (event.key === "Enter" || event.key === " ") {
|
|
1486
1606
|
event.preventDefault();
|
|
1487
|
-
toggleGroup(
|
|
1607
|
+
if (zone !== "pinned") toggleGroup(expandKey, true);
|
|
1488
1608
|
}
|
|
1489
1609
|
},
|
|
1490
1610
|
children: [
|
|
@@ -1507,7 +1627,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1507
1627
|
top: box.top
|
|
1508
1628
|
}, { immediate: true });
|
|
1509
1629
|
},
|
|
1510
|
-
children: isExpanded ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderOpenOutline16, { size: 16 }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderClose16, { size: 16 })
|
|
1630
|
+
children: zone !== "pinned" && isExpanded ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderOpenOutline16, { size: 16 }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderClose16, { size: 16 })
|
|
1511
1631
|
}),
|
|
1512
1632
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1513
1633
|
className: "dcu-wb-project-title",
|
|
@@ -1577,11 +1697,11 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1577
1697
|
})
|
|
1578
1698
|
]
|
|
1579
1699
|
}),
|
|
1580
|
-
isExpanded &&
|
|
1700
|
+
zone !== "pinned" && isExpanded && shownIds.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1581
1701
|
className: "dcu-wb-nochat",
|
|
1582
1702
|
children: t("workspace.noChat")
|
|
1583
1703
|
}),
|
|
1584
|
-
isExpanded &&
|
|
1704
|
+
zone !== "pinned" && isExpanded && shownIds.map((id) => {
|
|
1585
1705
|
const session = sessions.byId[id];
|
|
1586
1706
|
if (session === void 0) return null;
|
|
1587
1707
|
const path = session.cwd ?? workspace.path;
|
|
@@ -1598,7 +1718,16 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1598
1718
|
draggable: true,
|
|
1599
1719
|
onDragStart: (event) => {
|
|
1600
1720
|
event.stopPropagation();
|
|
1601
|
-
|
|
1721
|
+
setWorkspaceDragId(void 0);
|
|
1722
|
+
writeSessionDrag(event.dataTransfer, id, session.displayTitle);
|
|
1723
|
+
const preview = document.createElement("div");
|
|
1724
|
+
preview.className = "dcu-wb-drag-ghost";
|
|
1725
|
+
preview.textContent = session.displayTitle;
|
|
1726
|
+
document.body.appendChild(preview);
|
|
1727
|
+
event.dataTransfer.setDragImage(preview, 16, 18);
|
|
1728
|
+
window.requestAnimationFrame(() => {
|
|
1729
|
+
preview.remove();
|
|
1730
|
+
});
|
|
1602
1731
|
setSessionDrag({
|
|
1603
1732
|
sessionId: id,
|
|
1604
1733
|
workspaceId: workspace.workspaceId
|
|
@@ -1657,7 +1786,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1657
1786
|
children: [
|
|
1658
1787
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1659
1788
|
className: "dcu-wb-session-title",
|
|
1660
|
-
children: session.displayTitle
|
|
1789
|
+
children: session.displayTitle.split(/\r?\n/)[0] ?? session.displayTitle
|
|
1661
1790
|
}),
|
|
1662
1791
|
pinnedSessionIds.includes(id) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
1663
1792
|
className: "dcu-wb-pin",
|
|
@@ -1788,20 +1917,28 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1788
1917
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
1789
1918
|
className: "dcu-wb-section",
|
|
1790
1919
|
"aria-label": t("workspace.pinned"),
|
|
1791
|
-
"data-pin-over": workspaceDragId !== void 0 && pinSlot === "header",
|
|
1792
1920
|
onDragOver: (event) => {
|
|
1793
|
-
if (
|
|
1921
|
+
if (!pinDragActive && !isSidebarItemDrag(event.dataTransfer)) return;
|
|
1794
1922
|
event.preventDefault();
|
|
1923
|
+
event.dataTransfer.dropEffect = "move";
|
|
1795
1924
|
if (event.target === event.currentTarget || event.target instanceof Element && event.target.closest(".dcu-wb-section-head") !== null) setPinSlot("header");
|
|
1796
1925
|
},
|
|
1797
1926
|
onDrop: (event) => {
|
|
1798
1927
|
event.preventDefault();
|
|
1799
|
-
const
|
|
1928
|
+
const draggedSession = readSessionDrag(event.dataTransfer, sessionDrag?.sessionId);
|
|
1929
|
+
const draggedWorkspace = readWorkspaceDrag(event.dataTransfer, workspaceDragId);
|
|
1800
1930
|
const slot = pinSlot;
|
|
1801
1931
|
setWorkspaceDragId(void 0);
|
|
1802
1932
|
setWorkspaceDropId(void 0);
|
|
1933
|
+
setWorkspaceDropAfter(false);
|
|
1934
|
+
setSessionDrag(void 0);
|
|
1935
|
+
setSessionDropId(void 0);
|
|
1803
1936
|
setPinSlot(void 0);
|
|
1804
|
-
if (
|
|
1937
|
+
if (draggedSession !== void 0) {
|
|
1938
|
+
pinSessionAt(draggedSession, slot === "header" ? pinSectionSessions[0] : slot === "end" || slot === void 0 || !pinSectionSessions.includes(slot) ? void 0 : slot);
|
|
1939
|
+
return;
|
|
1940
|
+
}
|
|
1941
|
+
if (draggedWorkspace !== void 0) pinWorkspaceAt(draggedWorkspace, slot === "header" ? pinnedGroups[0] === void 0 ? void 0 : String(pinnedGroups[0].workspaceId) : slot === "end" || slot === void 0 || pinSectionSessions.includes(slot) ? void 0 : slot);
|
|
1805
1942
|
},
|
|
1806
1943
|
onDragLeave: (event) => {
|
|
1807
1944
|
if (event.currentTarget.contains(event.relatedTarget)) return;
|
|
@@ -1837,18 +1974,171 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1837
1974
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1838
1975
|
className: "dcu-wb-section-body",
|
|
1839
1976
|
"data-open": sectionOpen("pinned"),
|
|
1840
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1977
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
|
|
1978
|
+
(pinDragActive || pinSlot === "header") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1979
|
+
className: `dcu-wb-pin-start${pinSlot === "header" ? " dcu-wb-drop" : ""}`,
|
|
1980
|
+
onDragOver: (event) => {
|
|
1981
|
+
if (!pinDragActive && !isSidebarItemDrag(event.dataTransfer)) return;
|
|
1982
|
+
event.preventDefault();
|
|
1983
|
+
event.stopPropagation();
|
|
1984
|
+
event.dataTransfer.dropEffect = "move";
|
|
1985
|
+
setPinSlot("header");
|
|
1986
|
+
setWorkspaceDropId(void 0);
|
|
1987
|
+
setWorkspaceDropAfter(false);
|
|
1988
|
+
}
|
|
1989
|
+
}),
|
|
1990
|
+
pinSectionSessions.length === 0 && pinnedGroups.length === 0 && pinSlot !== "header" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
1991
|
+
className: "dcu-wb-empty",
|
|
1992
|
+
children: t("workspace.pinnedEmpty")
|
|
1993
|
+
}),
|
|
1994
|
+
pinSectionSessions.map((id) => {
|
|
1995
|
+
const session = sessions.byId[id];
|
|
1996
|
+
if (session === void 0) return null;
|
|
1997
|
+
const title = session.displayTitle;
|
|
1998
|
+
const workspace = groups.items.find((item) => item.visibleIds.includes(id));
|
|
1999
|
+
const path = session.cwd ?? workspace?.path;
|
|
2000
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionRow, {
|
|
2001
|
+
id,
|
|
2002
|
+
title,
|
|
2003
|
+
flat: true,
|
|
2004
|
+
selected: sessions.current === id,
|
|
2005
|
+
menuOpen: menu?.type === "session" && menu.id === id,
|
|
2006
|
+
pinned: true,
|
|
2007
|
+
unread: unreadSessionIds.includes(id),
|
|
2008
|
+
running: session.running === true,
|
|
2009
|
+
t,
|
|
2010
|
+
menuItems: sessionMenu(id, title, path),
|
|
2011
|
+
menuPoint: menu?.type === "session" && menu.id === id && menu.x !== void 0 && menu.y !== void 0 ? {
|
|
2012
|
+
x: menu.x,
|
|
2013
|
+
y: menu.y
|
|
2014
|
+
} : void 0,
|
|
2015
|
+
draggable: true,
|
|
2016
|
+
dropActive: sessionDropId === id,
|
|
2017
|
+
onDragStart: (event) => {
|
|
2018
|
+
event.stopPropagation();
|
|
2019
|
+
setWorkspaceDragId(void 0);
|
|
2020
|
+
writeSessionDrag(event.dataTransfer, id, title);
|
|
2021
|
+
const preview = document.createElement("div");
|
|
2022
|
+
preview.className = "dcu-wb-drag-ghost";
|
|
2023
|
+
preview.textContent = title;
|
|
2024
|
+
document.body.appendChild(preview);
|
|
2025
|
+
event.dataTransfer.setDragImage(preview, 16, 18);
|
|
2026
|
+
window.requestAnimationFrame(() => {
|
|
2027
|
+
preview.remove();
|
|
2028
|
+
});
|
|
2029
|
+
setSessionDrag({
|
|
2030
|
+
sessionId: id,
|
|
2031
|
+
workspaceId: workspace?.workspaceId ?? ""
|
|
2032
|
+
});
|
|
2033
|
+
},
|
|
2034
|
+
onDragEnd: () => {
|
|
2035
|
+
setSessionDrag(void 0);
|
|
2036
|
+
setSessionDropId(void 0);
|
|
2037
|
+
setPinSlot(void 0);
|
|
2038
|
+
},
|
|
2039
|
+
onDragOver: (event) => {
|
|
2040
|
+
if (sessionDrag === void 0) return;
|
|
2041
|
+
event.preventDefault();
|
|
2042
|
+
event.stopPropagation();
|
|
2043
|
+
setSessionDropId(id);
|
|
2044
|
+
setPinSlot(id);
|
|
2045
|
+
},
|
|
2046
|
+
onDrop: (event) => {
|
|
2047
|
+
event.preventDefault();
|
|
2048
|
+
event.stopPropagation();
|
|
2049
|
+
const draggedSession = readSessionDrag(event.dataTransfer, sessionDrag?.sessionId);
|
|
2050
|
+
const after = event.clientY > event.currentTarget.getBoundingClientRect().top + event.currentTarget.getBoundingClientRect().height / 2;
|
|
2051
|
+
setSessionDrag(void 0);
|
|
2052
|
+
setSessionDropId(void 0);
|
|
2053
|
+
setPinSlot(void 0);
|
|
2054
|
+
if (draggedSession === void 0) return;
|
|
2055
|
+
pinSessionAt(draggedSession, dropBeforeId(pinSectionSessions, id, after));
|
|
2056
|
+
},
|
|
2057
|
+
onOpen: () => {
|
|
2058
|
+
setUnreadSessionIds((ids) => ids.filter((item) => item !== id));
|
|
2059
|
+
openSession(id);
|
|
2060
|
+
},
|
|
2061
|
+
onMenuChange: (open) => {
|
|
2062
|
+
setMenu(open ? {
|
|
2063
|
+
id,
|
|
2064
|
+
type: "session"
|
|
2065
|
+
} : void 0);
|
|
2066
|
+
},
|
|
2067
|
+
onPin: () => {
|
|
2068
|
+
setSectionSessionIds((ids) => ids.filter((item) => item !== id));
|
|
2069
|
+
},
|
|
2070
|
+
onArchive: () => {
|
|
2071
|
+
run("archive", () => archiveSession(id));
|
|
2072
|
+
},
|
|
2073
|
+
onHover: (event) => {
|
|
2074
|
+
const box = hoverCardAnchor(event.currentTarget.getBoundingClientRect());
|
|
2075
|
+
showTip({
|
|
2076
|
+
kind: "session",
|
|
2077
|
+
id,
|
|
2078
|
+
title,
|
|
2079
|
+
project: workspace?.title,
|
|
2080
|
+
path,
|
|
2081
|
+
time: formatHoverTime(session.updatedAt),
|
|
2082
|
+
left: box.left,
|
|
2083
|
+
top: box.top
|
|
2084
|
+
});
|
|
2085
|
+
},
|
|
2086
|
+
onLeave: hideTip,
|
|
2087
|
+
onContextMenu: (event) => {
|
|
2088
|
+
event.preventDefault();
|
|
2089
|
+
event.stopPropagation();
|
|
2090
|
+
dismissTip();
|
|
2091
|
+
setMenu({
|
|
2092
|
+
id,
|
|
2093
|
+
type: "session",
|
|
2094
|
+
x: event.clientX,
|
|
2095
|
+
y: event.clientY
|
|
2096
|
+
});
|
|
2097
|
+
},
|
|
2098
|
+
onSelectAction: (action) => {
|
|
2099
|
+
if (busy !== void 0) return;
|
|
2100
|
+
if (action === "rename") beginRename("session", id, title);
|
|
2101
|
+
if (action === "pin") {
|
|
2102
|
+
setSectionSessionIds((ids) => ids.filter((item) => item !== id));
|
|
2103
|
+
setMenu(void 0);
|
|
2104
|
+
}
|
|
2105
|
+
if (action === "unread") {
|
|
2106
|
+
setUnreadSessionIds((ids) => toggleSessionId(ids, id));
|
|
2107
|
+
setMenu(void 0);
|
|
2108
|
+
}
|
|
2109
|
+
if (action === "archive") run("archive", () => archiveSession(id));
|
|
2110
|
+
if (action === "delete") {
|
|
2111
|
+
setDeleteTarget({
|
|
2112
|
+
id,
|
|
2113
|
+
kind: "session",
|
|
2114
|
+
title
|
|
2115
|
+
});
|
|
2116
|
+
setError(void 0);
|
|
2117
|
+
setMenu(void 0);
|
|
2118
|
+
}
|
|
2119
|
+
if (action === "fork") run("fork", () => forkSession(id));
|
|
2120
|
+
if (action === "openPath" && path !== void 0) run("open-path", () => openPath(path));
|
|
2121
|
+
if (action === "copyPath") copy(path);
|
|
2122
|
+
if (action === "copyTitle") copy(title);
|
|
2123
|
+
if (action === "copyId") copy(id);
|
|
2124
|
+
if (action === "copyLink") copy(sessionDeepLink(browserBase(), id));
|
|
2125
|
+
}
|
|
2126
|
+
}, id);
|
|
2127
|
+
}),
|
|
2128
|
+
pinnedGroups.map((workspace) => renderGroup(workspace, "pinned")),
|
|
2129
|
+
pinDragActive && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2130
|
+
className: `dcu-wb-pin-end${pinSlot === "end" ? " dcu-wb-drop" : ""}`,
|
|
2131
|
+
onDragOver: (event) => {
|
|
2132
|
+
if (!pinDragActive && !isSidebarItemDrag(event.dataTransfer)) return;
|
|
2133
|
+
event.preventDefault();
|
|
2134
|
+
event.stopPropagation();
|
|
2135
|
+
event.dataTransfer.dropEffect = "move";
|
|
2136
|
+
setPinSlot("end");
|
|
2137
|
+
setWorkspaceDropId(void 0);
|
|
2138
|
+
setWorkspaceDropAfter(false);
|
|
2139
|
+
}
|
|
2140
|
+
})
|
|
2141
|
+
] })
|
|
1852
2142
|
})]
|
|
1853
2143
|
}),
|
|
1854
2144
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
@@ -1954,6 +2244,29 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
1954
2244
|
running: session.running === true,
|
|
1955
2245
|
t,
|
|
1956
2246
|
menuItems: sessionMenu(id, title, session.cwd),
|
|
2247
|
+
draggable: true,
|
|
2248
|
+
onDragStart: (event) => {
|
|
2249
|
+
event.stopPropagation();
|
|
2250
|
+
setWorkspaceDragId(void 0);
|
|
2251
|
+
writeSessionDrag(event.dataTransfer, id, title);
|
|
2252
|
+
const preview = document.createElement("div");
|
|
2253
|
+
preview.className = "dcu-wb-drag-ghost";
|
|
2254
|
+
preview.textContent = title;
|
|
2255
|
+
document.body.appendChild(preview);
|
|
2256
|
+
event.dataTransfer.setDragImage(preview, 16, 18);
|
|
2257
|
+
window.requestAnimationFrame(() => {
|
|
2258
|
+
preview.remove();
|
|
2259
|
+
});
|
|
2260
|
+
setSessionDrag({
|
|
2261
|
+
sessionId: id,
|
|
2262
|
+
workspaceId: ""
|
|
2263
|
+
});
|
|
2264
|
+
},
|
|
2265
|
+
onDragEnd: () => {
|
|
2266
|
+
setSessionDrag(void 0);
|
|
2267
|
+
setSessionDropId(void 0);
|
|
2268
|
+
setPinSlot(void 0);
|
|
2269
|
+
},
|
|
1957
2270
|
menuPoint: menu?.type === "session" && menu.id === id && menu.x !== void 0 && menu.y !== void 0 ? {
|
|
1958
2271
|
x: menu.x,
|
|
1959
2272
|
y: menu.y
|
|
@@ -3417,10 +3730,12 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3417
3730
|
});
|
|
3418
3731
|
}
|
|
3419
3732
|
CodexSidebar.displayName = "michengai-codex-ui";
|
|
3733
|
+
//#endregion
|
|
3734
|
+
//#region src/dependencies.ts
|
|
3420
3735
|
const MANAGED_DEPENDENCIES = [
|
|
3421
3736
|
{
|
|
3422
|
-
id: "
|
|
3423
|
-
packageName: "@
|
|
3737
|
+
id: "dsh",
|
|
3738
|
+
packageName: "@deepseek-ai/dsh"
|
|
3424
3739
|
},
|
|
3425
3740
|
{
|
|
3426
3741
|
id: "ui",
|
|
@@ -3469,31 +3784,48 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3469
3784
|
const [installing, setInstalling] = (0, react.useState)();
|
|
3470
3785
|
const [message, setMessage] = (0, react.useState)();
|
|
3471
3786
|
const alive = (0, react.useRef)(true);
|
|
3787
|
+
const root = (0, react.useRef)(null);
|
|
3788
|
+
const stateRef = (0, react.useRef)("loading");
|
|
3789
|
+
const requestId = (0, react.useRef)(0);
|
|
3790
|
+
stateRef.current = state;
|
|
3472
3791
|
(0, react.useEffect)(() => () => {
|
|
3473
3792
|
alive.current = false;
|
|
3474
3793
|
}, []);
|
|
3475
3794
|
const load = (0, react.useCallback)(async (signal) => {
|
|
3476
|
-
|
|
3795
|
+
const currentRequest = ++requestId.current;
|
|
3796
|
+
if (stateRef.current !== "ready") setState("loading");
|
|
3477
3797
|
try {
|
|
3478
3798
|
const response = await fetch(endpoint, {
|
|
3479
3799
|
cache: "no-store",
|
|
3480
3800
|
signal
|
|
3481
3801
|
});
|
|
3482
3802
|
const payload = await response.json();
|
|
3483
|
-
if (signal?.aborted) return;
|
|
3803
|
+
if (signal?.aborted || currentRequest !== requestId.current) return;
|
|
3484
3804
|
if (!response.ok || !Array.isArray(payload.dependencies) || !payload.dependencies.every(isDependencyStatus)) throw new Error();
|
|
3485
3805
|
setDependencies(payload.dependencies);
|
|
3486
3806
|
setState("ready");
|
|
3487
3807
|
} catch (error) {
|
|
3488
|
-
if (signal?.aborted || error instanceof DOMException && error.name === "AbortError") return;
|
|
3489
|
-
setState("failed");
|
|
3808
|
+
if (signal?.aborted || error instanceof DOMException && error.name === "AbortError" || currentRequest !== requestId.current) return;
|
|
3809
|
+
if (stateRef.current !== "ready") setState("failed");
|
|
3490
3810
|
}
|
|
3491
3811
|
}, []);
|
|
3492
3812
|
(0, react.useEffect)(() => {
|
|
3813
|
+
const node = root.current;
|
|
3493
3814
|
const controller = new AbortController();
|
|
3494
|
-
|
|
3815
|
+
const refresh = () => {
|
|
3816
|
+
load(controller.signal);
|
|
3817
|
+
};
|
|
3818
|
+
refresh();
|
|
3819
|
+
if (node === null || typeof IntersectionObserver === "undefined") return () => {
|
|
3820
|
+
controller.abort();
|
|
3821
|
+
};
|
|
3822
|
+
const observer = new IntersectionObserver((entries) => {
|
|
3823
|
+
if (entries.some((entry) => entry.isIntersecting)) refresh();
|
|
3824
|
+
}, { threshold: .2 });
|
|
3825
|
+
observer.observe(node);
|
|
3495
3826
|
return () => {
|
|
3496
3827
|
controller.abort();
|
|
3828
|
+
observer.disconnect();
|
|
3497
3829
|
};
|
|
3498
3830
|
}, [load]);
|
|
3499
3831
|
const install = async (id) => {
|
|
@@ -3522,6 +3854,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3522
3854
|
};
|
|
3523
3855
|
const title = (id) => t(`about.dependency.${id}`);
|
|
3524
3856
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
|
|
3857
|
+
ref: root,
|
|
3525
3858
|
className: "dcu-about",
|
|
3526
3859
|
"aria-label": t("about.nav"),
|
|
3527
3860
|
children: [
|
|
@@ -3711,7 +4044,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3711
4044
|
"search.actions": "快捷操作",
|
|
3712
4045
|
"workspace.label": "工作区会话",
|
|
3713
4046
|
"workspace.pinned": "置顶",
|
|
3714
|
-
"workspace.pinnedEmpty": "
|
|
4047
|
+
"workspace.pinnedEmpty": "拖动项目或会话到此处置顶",
|
|
3715
4048
|
"workspace.projects": "项目",
|
|
3716
4049
|
"workspace.recent": "最近",
|
|
3717
4050
|
"workspace.recentEmpty": "无聊天",
|
|
@@ -3782,7 +4115,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3782
4115
|
"about.feature.conversation": "保留原生消息、工具调用、输入、权限和模型选择,仅调整容器视觉",
|
|
3783
4116
|
"about.feature.navigator": "当前会话提供轮次缩略导航,可快速跳转至每一次用户提问",
|
|
3784
4117
|
"about.dependencies": "配套管理插件",
|
|
3785
|
-
"about.dependenciesDescription": "
|
|
4118
|
+
"about.dependenciesDescription": "每个配套插件都单独安装和更新,互不影响。可分别检查 Codex UI、专家、技能、归档、IM、定时任务和第三方插件市场。",
|
|
3786
4119
|
"about.loading": "正在读取依赖安装状态…",
|
|
3787
4120
|
"about.statusFailed": "暂时无法读取依赖安装状态。",
|
|
3788
4121
|
"about.installed": "已安装",
|
|
@@ -3792,7 +4125,8 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3792
4125
|
"about.update": "更新",
|
|
3793
4126
|
"about.installing": "安装中",
|
|
3794
4127
|
"about.installFailed": "依赖安装失败,请稍后重试。",
|
|
3795
|
-
"about.restartRequired": "
|
|
4128
|
+
"about.restartRequired": "正在热更新插件,窗口会自动刷新。",
|
|
4129
|
+
"about.dependency.dsh": "DeepSeek Harness",
|
|
3796
4130
|
"about.dependency.suite": "Codex 套件",
|
|
3797
4131
|
"about.dependency.ui": "Codex UI",
|
|
3798
4132
|
"about.dependency.experts": "专家管理",
|
|
@@ -3842,7 +4176,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3842
4176
|
"workspace.pin": "Pin project",
|
|
3843
4177
|
"workspace.unpin": "Unpin",
|
|
3844
4178
|
"workspace.pinned": "Pinned",
|
|
3845
|
-
"workspace.pinnedEmpty": "Drag a project here to pin it",
|
|
4179
|
+
"workspace.pinnedEmpty": "Drag a project or chat here to pin it",
|
|
3846
4180
|
"workspace.openPath": "Open in file explorer",
|
|
3847
4181
|
"workspace.delete": "Delete project",
|
|
3848
4182
|
"workspace.deleteDescription": "This removes “{name}” from the project list. The folder and conversation records remain.",
|
|
@@ -3904,7 +4238,7 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3904
4238
|
"about.feature.conversation": "Keeps native messages, tool calls, composer, permissions, and model selection while refining the container visuals",
|
|
3905
4239
|
"about.feature.navigator": "Navigate directly to each user prompt with the current conversation turn navigator",
|
|
3906
4240
|
"about.dependencies": "Companion management plugins",
|
|
3907
|
-
"about.dependenciesDescription": "
|
|
4241
|
+
"about.dependenciesDescription": "Each companion plugin is installed and updated separately. Check Codex UI, expert, skill, archive, IM, scheduled-task, and marketplace plugins on their own.",
|
|
3908
4242
|
"about.loading": "Loading dependency status…",
|
|
3909
4243
|
"about.statusFailed": "Dependency status is temporarily unavailable.",
|
|
3910
4244
|
"about.installed": "Installed",
|
|
@@ -3914,7 +4248,8 @@ header [data-dcu-title-folder] svg,header [data-dcu-title-more] svg{display:bloc
|
|
|
3914
4248
|
"about.update": "Update",
|
|
3915
4249
|
"about.installing": "Installing",
|
|
3916
4250
|
"about.installFailed": "Dependency installation failed. Try again later.",
|
|
3917
|
-
"about.restartRequired": "
|
|
4251
|
+
"about.restartRequired": "Updating plugins now. The window will refresh automatically.",
|
|
4252
|
+
"about.dependency.dsh": "DeepSeek Harness",
|
|
3918
4253
|
"about.dependency.suite": "Codex suite",
|
|
3919
4254
|
"about.dependency.ui": "Codex UI",
|
|
3920
4255
|
"about.dependency.experts": "Expert management",
|
package/dist/index.mjs
CHANGED
|
@@ -15,8 +15,8 @@ const SUITE_MEMBER_PACKAGES = [
|
|
|
15
15
|
];
|
|
16
16
|
const MANAGED_DEPENDENCIES = [
|
|
17
17
|
{
|
|
18
|
-
id: "
|
|
19
|
-
packageName:
|
|
18
|
+
id: "dsh",
|
|
19
|
+
packageName: "@deepseek-ai/dsh"
|
|
20
20
|
},
|
|
21
21
|
{
|
|
22
22
|
id: "ui",
|
|
@@ -52,6 +52,8 @@ function managedDependency(id) {
|
|
|
52
52
|
}
|
|
53
53
|
//#endregion
|
|
54
54
|
//#region src/dependency-manager.ts
|
|
55
|
+
const PROFILE_PENDING_UPDATES_FILE = ".dsh-pending-updates.json";
|
|
56
|
+
const APPLY_PLUGIN_UPDATES_IPC = "apply-plugin-updates";
|
|
55
57
|
function profileDirectory() {
|
|
56
58
|
if (process.env.DSH_PROFILE_DIR !== void 0) return process.env.DSH_PROFILE_DIR;
|
|
57
59
|
return resolve(homedir(), ".dsh", "profiles", "web");
|
|
@@ -59,50 +61,60 @@ function profileDirectory() {
|
|
|
59
61
|
async function declaredPluginNames() {
|
|
60
62
|
try {
|
|
61
63
|
const manifest = JSON.parse(await readFile(resolve(profileDirectory(), "package.json"), "utf8"));
|
|
62
|
-
return Object.keys({
|
|
64
|
+
return [.../* @__PURE__ */ new Set([...Object.keys({
|
|
63
65
|
...manifest.devDependencies,
|
|
64
66
|
...manifest.dependencies
|
|
65
|
-
});
|
|
67
|
+
}), ...manifest.dsh?.profile?.bundles ?? []])];
|
|
66
68
|
} catch (error) {
|
|
67
69
|
if (error.code === "ENOENT") return [];
|
|
68
70
|
throw error;
|
|
69
71
|
}
|
|
70
72
|
}
|
|
71
|
-
/**
|
|
73
|
+
/** 单独更新子插件时先卸套件,避免两套 patch 冲突。 */
|
|
72
74
|
function pluginsToRemoveBeforeInstall(declared, installing) {
|
|
73
|
-
if (installing
|
|
74
|
-
return SUITE_MEMBER_PACKAGES.filter((name) => declared.includes(name));
|
|
75
|
+
if (SUITE_MEMBER_PACKAGES.includes(installing) && declared.includes("@michengai/dsh-codex-suite")) return [SUITE_PACKAGE];
|
|
76
|
+
if (installing === "@michengai/dsh-codex-suite") return SUITE_MEMBER_PACKAGES.filter((name) => declared.includes(name));
|
|
77
|
+
return [];
|
|
75
78
|
}
|
|
76
|
-
/**
|
|
77
|
-
function resolveDshPluginTarget(installing,
|
|
78
|
-
if (installing !== "@michengai/dsh-codex-suite" && SUITE_MEMBER_PACKAGES.includes(installing) && declared.includes("@michengai/dsh-codex-suite")) return SUITE_PACKAGE;
|
|
79
|
+
/** 点击哪个包就更新哪个包,不再把子插件重定向到套件。 */
|
|
80
|
+
function resolveDshPluginTarget(installing, _declared = []) {
|
|
79
81
|
return installing;
|
|
80
82
|
}
|
|
83
|
+
function isOfficialRuntimePackage(packageName) {
|
|
84
|
+
return packageName === "@deepseek-ai/dsh" || packageName.startsWith("@deepseek-ai/dsh-");
|
|
85
|
+
}
|
|
86
|
+
function packageLookupRoots(packageName) {
|
|
87
|
+
if (isOfficialRuntimePackage(packageName) && process.env.DSH_RUNTIME_DIR !== void 0 && process.env.DSH_RUNTIME_DIR !== "") return [process.env.DSH_RUNTIME_DIR, profileDirectory()];
|
|
88
|
+
return [profileDirectory()];
|
|
89
|
+
}
|
|
81
90
|
async function installedPackageVersion(packageName) {
|
|
82
|
-
try {
|
|
83
|
-
const manifest = JSON.parse(await readFile(resolve(
|
|
84
|
-
|
|
91
|
+
for (const root of packageLookupRoots(packageName)) try {
|
|
92
|
+
const manifest = JSON.parse(await readFile(resolve(root, "node_modules", ...packageName.split("/"), "package.json"), "utf8"));
|
|
93
|
+
if (typeof manifest.version === "string" && manifest.version !== "") return manifest.version;
|
|
85
94
|
} catch (error) {
|
|
86
|
-
if (error.code
|
|
87
|
-
throw error;
|
|
95
|
+
if (error.code !== "ENOENT") throw error;
|
|
88
96
|
}
|
|
89
97
|
}
|
|
90
|
-
/**
|
|
98
|
+
/** 磁盘有包且仍在 profile 声明里,才算已安装。卸载后残留的 node_modules 不算。 */
|
|
91
99
|
function isManagedPackageInstalled(input) {
|
|
92
|
-
return input.installedVersion !== void 0 && input.installedVersion !== "";
|
|
100
|
+
return input.declared && input.installedVersion !== void 0 && input.installedVersion !== "";
|
|
93
101
|
}
|
|
94
102
|
/** npm latest 查询缓存有效期:避免每次打开“关于”页都打 7 个 registry 请求。 */
|
|
95
103
|
const LATEST_CACHE_TTL_MS = 3e5;
|
|
96
104
|
const latestCache = /* @__PURE__ */ new Map();
|
|
97
|
-
|
|
98
|
-
|
|
105
|
+
function cacheKey(packageName, tag) {
|
|
106
|
+
return packageName + "@" + tag;
|
|
107
|
+
}
|
|
108
|
+
async function npmTaggedVersion(packageName, tag) {
|
|
109
|
+
const key = cacheKey(packageName, tag);
|
|
110
|
+
const hit = latestCache.get(key);
|
|
99
111
|
if (hit !== void 0 && Date.now() - hit.at < LATEST_CACHE_TTL_MS) return hit.version;
|
|
100
112
|
try {
|
|
101
|
-
const response = await fetch(`https://registry.npmjs.org/${encodeURIComponent(packageName)}
|
|
113
|
+
const response = await fetch(`https://registry.npmjs.org/${encodeURIComponent(packageName)}/${tag}`, { signal: AbortSignal.timeout(5e3) });
|
|
102
114
|
if (!response.ok) return void 0;
|
|
103
115
|
const manifest = await response.json();
|
|
104
116
|
if (typeof manifest.version !== "string") return void 0;
|
|
105
|
-
latestCache.set(
|
|
117
|
+
latestCache.set(key, {
|
|
106
118
|
version: manifest.version,
|
|
107
119
|
at: Date.now()
|
|
108
120
|
});
|
|
@@ -111,6 +123,10 @@ async function npmLatestVersion(packageName) {
|
|
|
111
123
|
return;
|
|
112
124
|
}
|
|
113
125
|
}
|
|
126
|
+
async function npmLatestVersion(packageName) {
|
|
127
|
+
if (isOfficialRuntimePackage(packageName)) return await npmTaggedVersion(packageName, "next") ?? await npmTaggedVersion(packageName, "latest");
|
|
128
|
+
return npmTaggedVersion(packageName, "latest");
|
|
129
|
+
}
|
|
114
130
|
function escapeRegExp(value) {
|
|
115
131
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
116
132
|
}
|
|
@@ -156,17 +172,29 @@ function versionParts(version) {
|
|
|
156
172
|
Number(match[3])
|
|
157
173
|
];
|
|
158
174
|
}
|
|
175
|
+
function prereleaseRank(version) {
|
|
176
|
+
const match = /-rc\.(\d+)/i.exec(version);
|
|
177
|
+
return match === null ? Number.POSITIVE_INFINITY : Number(match[1]);
|
|
178
|
+
}
|
|
159
179
|
function newerVersion(installed, latest) {
|
|
160
180
|
const current = versionParts(installed);
|
|
161
181
|
const candidate = versionParts(latest);
|
|
162
182
|
if (current === void 0 || candidate === void 0) return false;
|
|
163
|
-
|
|
183
|
+
if (candidate[0] !== current[0]) return candidate[0] > current[0];
|
|
184
|
+
if (candidate[1] !== current[1]) return candidate[1] > current[1];
|
|
185
|
+
if (candidate[2] !== current[2]) return candidate[2] > current[2];
|
|
186
|
+
return prereleaseRank(latest) > prereleaseRank(installed);
|
|
164
187
|
}
|
|
165
188
|
/** 返回 Web profile 中固定管理插件的实际安装版本与 npm latest 状态。 */
|
|
166
189
|
async function dependencyStatuses() {
|
|
190
|
+
const declaredNames = await declaredPluginNames();
|
|
167
191
|
return Promise.all(MANAGED_DEPENDENCIES.map(async (dependency) => {
|
|
168
192
|
const version = await installedPackageVersion(dependency.packageName);
|
|
169
|
-
|
|
193
|
+
const declared = isOfficialRuntimePackage(dependency.packageName) || declaredNames.includes(dependency.packageName);
|
|
194
|
+
if (version === void 0 || !isManagedPackageInstalled({
|
|
195
|
+
installedVersion: version,
|
|
196
|
+
declared
|
|
197
|
+
})) return {
|
|
170
198
|
...dependency,
|
|
171
199
|
installed: false,
|
|
172
200
|
updateAvailable: false
|
|
@@ -190,12 +218,55 @@ function resolveDshCliEntry(entry = process.argv[1], cwd = process.cwd()) {
|
|
|
190
218
|
if (entry.startsWith("file:")) return fileURLToPath(entry);
|
|
191
219
|
return resolve(cwd, entry);
|
|
192
220
|
}
|
|
221
|
+
function requestDesktopHotUpdate(send = process.send) {
|
|
222
|
+
if (typeof send !== "function") return false;
|
|
223
|
+
send(APPLY_PLUGIN_UPDATES_IPC);
|
|
224
|
+
return true;
|
|
225
|
+
}
|
|
226
|
+
function isRestartableInstallError(error) {
|
|
227
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
228
|
+
return /完全退出桌面端|正在运行的插件|pnpm 仓库不一致/.test(message);
|
|
229
|
+
}
|
|
230
|
+
async function recordPendingUpdate(packageName, version) {
|
|
231
|
+
const pendingPath = resolve(profileDirectory(), PROFILE_PENDING_UPDATES_FILE);
|
|
232
|
+
let packages = [];
|
|
233
|
+
try {
|
|
234
|
+
const parsed = JSON.parse(await readFile(pendingPath, "utf8"));
|
|
235
|
+
if (Array.isArray(parsed.packages)) packages = parsed.packages.flatMap((item) => {
|
|
236
|
+
if (item === null || typeof item !== "object") return [];
|
|
237
|
+
const record = item;
|
|
238
|
+
if (typeof record.packageName !== "string" || typeof record.version !== "string") return [];
|
|
239
|
+
return [{
|
|
240
|
+
packageName: record.packageName,
|
|
241
|
+
version: record.version
|
|
242
|
+
}];
|
|
243
|
+
});
|
|
244
|
+
} catch (error) {
|
|
245
|
+
if (error.code !== "ENOENT") throw error;
|
|
246
|
+
}
|
|
247
|
+
packages = packages.filter((item) => item.packageName !== packageName);
|
|
248
|
+
packages.push({
|
|
249
|
+
packageName,
|
|
250
|
+
version
|
|
251
|
+
});
|
|
252
|
+
await writeFile(pendingPath, `${JSON.stringify({ packages }, void 0, 2)}\n`, "utf8");
|
|
253
|
+
}
|
|
254
|
+
async function recordDeclaredVersion(packageName, version) {
|
|
255
|
+
const manifestPath = resolve(profileDirectory(), "package.json");
|
|
256
|
+
const manifest = JSON.parse(await readFile(manifestPath, "utf8"));
|
|
257
|
+
manifest.dependencies = {
|
|
258
|
+
...manifest.dependencies,
|
|
259
|
+
[packageName]: version
|
|
260
|
+
};
|
|
261
|
+
await writeFile(manifestPath, `${JSON.stringify(manifest, void 0, 2)}\n`, "utf8");
|
|
262
|
+
}
|
|
193
263
|
function pluginCommandError(stderr) {
|
|
194
264
|
const detail = stderr.replace(/\s+/g, " ").trim();
|
|
195
265
|
if (detail.includes("minimumReleaseAge") || detail.includes("Release age")) return /* @__PURE__ */ new Error("更新被 pnpm 发布时间保护拦截。请确认已写入当前版本白名单后重试。");
|
|
196
|
-
if (
|
|
197
|
-
if (
|
|
198
|
-
return /* @__PURE__ */ new Error("
|
|
266
|
+
if (/EPERM|EBUSY|EACCES|unable to unlink|ERR_PNPM_LOCKED|Lock/i.test(detail)) return /* @__PURE__ */ new Error("无法覆盖正在运行的插件文件。请先完全退出桌面端,再重新打开后更新。");
|
|
267
|
+
if (/UNEXPECTED_STORE|Unexpected store location/i.test(detail)) return /* @__PURE__ */ new Error("插件目录和 pnpm 仓库不一致。请完全退出桌面端后再更新。");
|
|
268
|
+
if (/pnpm not found/i.test(detail)) return /* @__PURE__ */ new Error("当前环境找不到 pnpm。请从桌面端启动后再更新。");
|
|
269
|
+
return /* @__PURE__ */ new Error("无法在应用运行时更新插件。请先完全退出桌面端,再重新打开后更新。");
|
|
199
270
|
}
|
|
200
271
|
/**
|
|
201
272
|
* 复用启动当前服务的 DSH CLI:它会通过 pnpm 从 npm 安装或更新,并自动维护
|
|
@@ -220,19 +291,21 @@ function runDshPlugin(args) {
|
|
|
220
291
|
windowsHide: true,
|
|
221
292
|
stdio: [
|
|
222
293
|
"ignore",
|
|
223
|
-
"
|
|
294
|
+
"pipe",
|
|
224
295
|
"pipe"
|
|
225
296
|
]
|
|
226
297
|
});
|
|
227
|
-
let
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
}
|
|
298
|
+
let output = "";
|
|
299
|
+
const collect = (chunk) => {
|
|
300
|
+
output += String(chunk);
|
|
301
|
+
};
|
|
302
|
+
child.stdout?.on("data", collect);
|
|
303
|
+
child.stderr?.on("data", collect);
|
|
231
304
|
child.once("error", () => {
|
|
232
305
|
reject(/* @__PURE__ */ new Error("无法启动 DSH 插件安装命令。请确认 Node.js 与 pnpm 可用后重试。"));
|
|
233
306
|
});
|
|
234
307
|
child.once("exit", (code) => {
|
|
235
|
-
code === 0 ? resolvePromise() : reject(pluginCommandError(
|
|
308
|
+
code === 0 ? resolvePromise() : reject(pluginCommandError(output));
|
|
236
309
|
});
|
|
237
310
|
});
|
|
238
311
|
}
|
|
@@ -260,13 +333,20 @@ async function installDependencyLocked(id) {
|
|
|
260
333
|
const remove = pluginsToRemoveBeforeInstall(declared, target);
|
|
261
334
|
if (remove.length > 0) await runDshPlugin(["remove", ...remove]);
|
|
262
335
|
await ensureLatestReleaseAllowed(target, targetVersion);
|
|
263
|
-
await
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
336
|
+
if (!isOfficialRuntimePackage(target)) await recordDeclaredVersion(target, targetVersion);
|
|
337
|
+
await recordPendingUpdate(target, targetVersion);
|
|
338
|
+
if (requestDesktopHotUpdate()) return dependencyStatuses();
|
|
339
|
+
try {
|
|
340
|
+
await runDshPlugin([
|
|
341
|
+
"add",
|
|
342
|
+
`${target}@${targetVersion}`,
|
|
343
|
+
"--registry=https://registry.npmjs.org/"
|
|
344
|
+
]);
|
|
345
|
+
} catch (error) {
|
|
346
|
+
if (isRestartableInstallError(error)) return dependencyStatuses();
|
|
347
|
+
throw error;
|
|
348
|
+
}
|
|
349
|
+
if (await installedPackageVersion(target) !== targetVersion) return dependencyStatuses();
|
|
270
350
|
return dependencyStatuses();
|
|
271
351
|
}
|
|
272
352
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@michengai/dsh-codex-ui",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.61",
|
|
4
4
|
"description": "以 Codex 风格重构 DSH Web 侧栏的独立客户端插件",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"publishConfig": {
|
|
@@ -51,6 +51,10 @@
|
|
|
51
51
|
"platform": "web"
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
|
+
"scripts": {
|
|
55
|
+
"build": "tsc --noEmit && tsdown",
|
|
56
|
+
"test": "tsx tests/permission-i18n.assert.ts && tsx tests/hover-tip.assert.ts && tsx tests/companion-slots.assert.ts && tsx tests/channel-api.assert.ts && tsx tests/schedule-sessions.assert.ts && tsx tests/session-tree.assert.ts && tsx tests/pinned-sessions.assert.ts && tsx tests/session-manager.assert.ts && tsx tests/workspace-browser.assert.ts && tsx tests/sidebar-search.assert.ts && tsx tests/settings-navigation.assert.ts && tsx tests/settings-nav-icons.assert.ts && tsx tests/locales.assert.ts && vitest run tests/client-runtime.integration.spec.ts && tsx tests/settings-integration.assert.ts && tsx tests/about-dependencies.assert.ts && tsx tests/dependency-manager.assert.ts && tsx tests/conversation-bubbles.assert.ts && tsx tests/conversation-header.assert.ts && tsx tests/conversation-visuals.assert.ts && tsdown && tsx tests/client-bundle.assert.ts && tsx tests/codex-suite.assert.ts"
|
|
57
|
+
},
|
|
54
58
|
"peerDependencies": {
|
|
55
59
|
"@deepseek-ai/cordis": ">=4.0.1 <5.0.0",
|
|
56
60
|
"@deepseek-ai/dsh-client-locale": ">=0.1.0-rc.0 <0.2.0",
|
|
@@ -96,9 +100,5 @@
|
|
|
96
100
|
"tsx": "^4.22.4",
|
|
97
101
|
"typescript": "^6.0.3",
|
|
98
102
|
"vitest": "^4.1.8"
|
|
99
|
-
},
|
|
100
|
-
"scripts": {
|
|
101
|
-
"build": "tsc --noEmit && tsdown",
|
|
102
|
-
"test": "tsx tests/permission-i18n.assert.ts && tsx tests/hover-tip.assert.ts && tsx tests/companion-slots.assert.ts && tsx tests/channel-api.assert.ts && tsx tests/schedule-sessions.assert.ts && tsx tests/session-tree.assert.ts && tsx tests/pinned-sessions.assert.ts && tsx tests/session-manager.assert.ts && tsx tests/workspace-browser.assert.ts && tsx tests/sidebar-search.assert.ts && tsx tests/settings-navigation.assert.ts && tsx tests/settings-nav-icons.assert.ts && tsx tests/locales.assert.ts && vitest run tests/client-runtime.integration.spec.ts && tsx tests/settings-integration.assert.ts && tsx tests/about-dependencies.assert.ts && tsx tests/dependency-manager.assert.ts && tsx tests/conversation-bubbles.assert.ts && tsx tests/conversation-header.assert.ts && tsx tests/conversation-visuals.assert.ts && tsdown && tsx tests/client-bundle.assert.ts && tsx tests/codex-suite.assert.ts"
|
|
103
103
|
}
|
|
104
|
-
}
|
|
104
|
+
}
|