@huanlin/dsh-plugin-ya-workspace-sidebar 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +208 -79
- package/lib/client.js.map +1 -1
- package/lib/types/client/contract.d.ts +6 -0
- package/lib/types/client/model.d.ts +18 -6
- package/lib/types/client/navigation.d.ts +30 -3
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +23 -16
package/lib/client.js
CHANGED
|
@@ -1203,7 +1203,45 @@ window.__ModuleLoader__.load({
|
|
|
1203
1203
|
* pre-split client runtime: reuse-or-create Workspace connection, the
|
|
1204
1204
|
* explicit/current/recent New Session fallback, archived-current clearing,
|
|
1205
1205
|
* boot auto-selection, and the directory-picking wire calls.
|
|
1206
|
+
*
|
|
1207
|
+
* dsh 0.1.7-rc.1 moved the Session selection out of the Session Controller
|
|
1208
|
+
* (`SessionListState.current` / `ISessions.open` / `ISessions.clear` are gone)
|
|
1209
|
+
* into this service: a retained `mainReference` plus a persisted selection
|
|
1210
|
+
* store (`dsh.sessions.current`). This port mirrors the shipped
|
|
1211
|
+
* `UiWorkspaceService` selection mechanics.
|
|
1206
1212
|
*/
|
|
1213
|
+
/** Persisted selection store (the official `dsh.sessions.current` key). */
|
|
1214
|
+
var SelectionStore = class {
|
|
1215
|
+
key;
|
|
1216
|
+
listeners = /* @__PURE__ */ new Set();
|
|
1217
|
+
value;
|
|
1218
|
+
constructor(key = "dsh.sessions.current") {
|
|
1219
|
+
this.key = key;
|
|
1220
|
+
this.value = this.read();
|
|
1221
|
+
}
|
|
1222
|
+
getSnapshot = () => this.value;
|
|
1223
|
+
subscribe = (listener) => {
|
|
1224
|
+
this.listeners.add(listener);
|
|
1225
|
+
return () => {
|
|
1226
|
+
this.listeners.delete(listener);
|
|
1227
|
+
};
|
|
1228
|
+
};
|
|
1229
|
+
set = (value) => {
|
|
1230
|
+
this.value = value;
|
|
1231
|
+
try {
|
|
1232
|
+
globalThis.localStorage?.setItem(this.key, JSON.stringify(value));
|
|
1233
|
+
} catch {}
|
|
1234
|
+
for (const listener of [...this.listeners]) listener();
|
|
1235
|
+
};
|
|
1236
|
+
read() {
|
|
1237
|
+
try {
|
|
1238
|
+
const raw = globalThis.localStorage?.getItem(this.key);
|
|
1239
|
+
return raw === null || raw === void 0 ? {} : JSON.parse(raw);
|
|
1240
|
+
} catch {
|
|
1241
|
+
return {};
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
};
|
|
1207
1245
|
/** Implements Workspace navigation and directory UI operations. */
|
|
1208
1246
|
var YaWorkspaceNavigation = class extends _deepseek_ai_cordis.Service {
|
|
1209
1247
|
directoryPicker;
|
|
@@ -1211,6 +1249,8 @@ window.__ModuleLoader__.load({
|
|
|
1211
1249
|
sessions;
|
|
1212
1250
|
connecting = /* @__PURE__ */ new Map();
|
|
1213
1251
|
lifetime = new AbortController();
|
|
1252
|
+
selection = new SelectionStore();
|
|
1253
|
+
mainReference;
|
|
1214
1254
|
/**
|
|
1215
1255
|
* @param ctx - Client root Context.
|
|
1216
1256
|
* @param directoryPicker - the directory-picking Remote namespace.
|
|
@@ -1224,61 +1264,95 @@ window.__ModuleLoader__.load({
|
|
|
1224
1264
|
this.sessions = sessions;
|
|
1225
1265
|
ctx.effect(() => this.watchNavigation(), "ya-workspace-sidebar: Workspace navigation policy");
|
|
1226
1266
|
}
|
|
1267
|
+
/** The Session currently shown in the main view, or undefined. */
|
|
1268
|
+
get currentSessionId() {
|
|
1269
|
+
return this.mainReference?.sessionId;
|
|
1270
|
+
}
|
|
1271
|
+
/** Observe the current selection (the sidebar's blank-row filter and highlight). */
|
|
1272
|
+
subscribeSelection(listener) {
|
|
1273
|
+
return this.selection.subscribe(listener);
|
|
1274
|
+
}
|
|
1227
1275
|
async connectWorkspace(workspaceId) {
|
|
1228
1276
|
const workspace = this.workspaces.list.getSnapshot().items.find((item) => item.workspaceId === workspaceId);
|
|
1229
1277
|
if (workspace === void 0) throw new Error(`ya-workspace-sidebar: unknown workspace "${workspaceId}"`);
|
|
1230
1278
|
const inflight = this.connecting.get(workspaceId);
|
|
1231
1279
|
if (inflight !== void 0) return inflight;
|
|
1280
|
+
const attempt = this.reuseOrCreateBlank(workspace).finally(() => {
|
|
1281
|
+
this.connecting.delete(workspaceId);
|
|
1282
|
+
});
|
|
1283
|
+
this.connecting.set(workspaceId, attempt);
|
|
1284
|
+
return attempt;
|
|
1285
|
+
}
|
|
1286
|
+
reuseOrCreateBlank(workspace) {
|
|
1232
1287
|
const archived = this.workspaces.list.getSnapshot().archivedSessionIds;
|
|
1233
1288
|
const sessions = this.sessions.list.getSnapshot();
|
|
1234
1289
|
for (const id of sessions.ids) {
|
|
1235
1290
|
const summary = sessions.byId[id];
|
|
1236
|
-
if (summary
|
|
1291
|
+
if (summary === void 0 || !summary.blank || summary.cwd !== workspace.path || !workspace.sessionIds.includes(id) || archived.includes(id)) continue;
|
|
1292
|
+
return this.reuseBlank(workspace.workspaceId, id);
|
|
1237
1293
|
}
|
|
1238
|
-
|
|
1239
|
-
this.connecting.delete(workspaceId);
|
|
1240
|
-
});
|
|
1241
|
-
this.connecting.set(workspaceId, attempt);
|
|
1242
|
-
return attempt;
|
|
1294
|
+
return this.sessions.create({ workspaceId: workspace.workspaceId });
|
|
1243
1295
|
}
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1296
|
+
async reuseBlank(workspaceId, sessionId) {
|
|
1297
|
+
try {
|
|
1298
|
+
return await this.sessions.create({
|
|
1299
|
+
workspaceId,
|
|
1300
|
+
sessionId
|
|
1301
|
+
});
|
|
1302
|
+
} catch (error) {
|
|
1303
|
+
if (!(error instanceof Error) || error.name !== "SessionCreateError") throw error;
|
|
1304
|
+
if (error.rpcError?.code !== "session/writer-held") throw error;
|
|
1305
|
+
return this.sessions.create({ workspaceId });
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
openSession(target) {
|
|
1309
|
+
this.replaceMain(target, this.lifetime.signal, "reveal");
|
|
1247
1310
|
}
|
|
1248
1311
|
async openWorkspace(workspaceId, beforeOpen) {
|
|
1249
1312
|
const navigation = AbortSignal.any([this.ctx.layout.beginNavigation(), this.lifetime.signal]);
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1313
|
+
let sessionId;
|
|
1314
|
+
try {
|
|
1315
|
+
sessionId = await this.connectWorkspace(workspaceId);
|
|
1316
|
+
} catch (error) {
|
|
1317
|
+
if (!navigation.aborted) console.warn("ya-workspace-sidebar: workspace open failed:", error);
|
|
1318
|
+
throw error;
|
|
1319
|
+
}
|
|
1320
|
+
if (navigation.aborted) return;
|
|
1321
|
+
this.replaceMain(sessionId, navigation, "reveal", beforeOpen);
|
|
1255
1322
|
}
|
|
1256
1323
|
async forkSession(sessionId) {
|
|
1257
|
-
|
|
1258
|
-
const childId = await this.sessions.fork({
|
|
1324
|
+
await this.sessions.fork({
|
|
1259
1325
|
sessionId,
|
|
1260
1326
|
increaseTitle: true
|
|
1261
1327
|
});
|
|
1262
|
-
if (!navigation.aborted) this.openSession(childId);
|
|
1263
1328
|
}
|
|
1264
1329
|
startSession(workspaceId) {
|
|
1265
1330
|
const workspaces = this.workspaces.list.getSnapshot();
|
|
1266
1331
|
const sessions = this.sessions.list.getSnapshot();
|
|
1267
|
-
const current =
|
|
1332
|
+
const current = this.mainReference?.sessionId;
|
|
1268
1333
|
const currentWorkspaceId = current === void 0 ? void 0 : workspaces.items.find((item) => item.sessionIds.includes(current))?.workspaceId;
|
|
1269
1334
|
const recent = workspaces.phase === "ready" && sessions.phase === "ready" ? recentWorkspace(workspaces.items, sessions.byId) : void 0;
|
|
1270
1335
|
const target = workspaceId ?? currentWorkspaceId ?? recent;
|
|
1271
1336
|
if (target === void 0) {
|
|
1272
|
-
this.
|
|
1273
|
-
this.ctx.layout.selectPanel(null);
|
|
1337
|
+
this.clearMain();
|
|
1274
1338
|
return;
|
|
1275
1339
|
}
|
|
1276
1340
|
this.openWorkspace(target).then(() => {}, (reason) => {
|
|
1277
1341
|
console.warn("ya-workspace-sidebar: new session failed:", reason);
|
|
1278
1342
|
});
|
|
1279
1343
|
}
|
|
1280
|
-
async archiveSession(sessionId) {
|
|
1281
|
-
await this.workspaces.archiveSession(sessionId);
|
|
1344
|
+
async archiveSession(sessionId, options = {}) {
|
|
1345
|
+
await this.workspaces.archiveSession(sessionId, options);
|
|
1346
|
+
if (this.mainReference?.sessionId === sessionId) this.clearMain();
|
|
1347
|
+
}
|
|
1348
|
+
async unarchiveSession(sessionId) {
|
|
1349
|
+
await this.workspaces.unarchiveSession(sessionId);
|
|
1350
|
+
}
|
|
1351
|
+
async pinSession(sessionId) {
|
|
1352
|
+
await this.workspaces.pinSession(sessionId);
|
|
1353
|
+
}
|
|
1354
|
+
async unpinSession(sessionId) {
|
|
1355
|
+
await this.workspaces.unpinSession(sessionId);
|
|
1282
1356
|
}
|
|
1283
1357
|
async pickDirectory() {
|
|
1284
1358
|
const result = await this.directoryPicker.pick();
|
|
@@ -1304,24 +1378,17 @@ window.__ModuleLoader__.load({
|
|
|
1304
1378
|
const workspaces = this.workspaces.list.getSnapshot();
|
|
1305
1379
|
const sessions = this.sessions.list.getSnapshot();
|
|
1306
1380
|
if (workspaces.phase !== "ready" || sessions.phase !== "ready") return;
|
|
1307
|
-
if (
|
|
1308
|
-
initial = "done";
|
|
1309
|
-
return;
|
|
1310
|
-
}
|
|
1311
|
-
const target = recentWorkspace(workspaces.items, sessions.byId);
|
|
1312
|
-
if (target === void 0) {
|
|
1381
|
+
if (this.mainReference !== void 0) {
|
|
1313
1382
|
initial = "done";
|
|
1314
1383
|
return;
|
|
1315
1384
|
}
|
|
1316
1385
|
initial = "connecting";
|
|
1317
|
-
this.
|
|
1318
|
-
if (this.lifetime.signal.aborted) return;
|
|
1319
|
-
if (this.sessions.list.getSnapshot().current === void 0) this.sessions.open(sessionId);
|
|
1386
|
+
this.restoreSelection(workspaces, sessions).then(() => {
|
|
1320
1387
|
initial = "done";
|
|
1321
1388
|
}, (reason) => {
|
|
1322
1389
|
if (this.lifetime.signal.aborted) return;
|
|
1323
1390
|
initial = "waiting";
|
|
1324
|
-
console.warn("ya-workspace-sidebar: initial
|
|
1391
|
+
console.warn("ya-workspace-sidebar: initial Session restoration failed:", reason);
|
|
1325
1392
|
});
|
|
1326
1393
|
};
|
|
1327
1394
|
const disposeWorkspaces = this.workspaces.list.subscribe(reconcile);
|
|
@@ -1333,13 +1400,63 @@ window.__ModuleLoader__.load({
|
|
|
1333
1400
|
disposeWorkspaces();
|
|
1334
1401
|
};
|
|
1335
1402
|
}
|
|
1403
|
+
async restoreSelection(workspaces, sessions) {
|
|
1404
|
+
const saved = this.selection.getSnapshot();
|
|
1405
|
+
if (saved.subagentAddress !== void 0) {
|
|
1406
|
+
this.replaceMain(saved.subagentAddress, this.lifetime.signal, "preserve");
|
|
1407
|
+
return;
|
|
1408
|
+
}
|
|
1409
|
+
const summary = saved.sessionId === void 0 ? void 0 : sessions.byId[saved.sessionId];
|
|
1410
|
+
const workspace = summary === void 0 ? void 0 : workspaces.items.find((item) => item.sessionIds.includes(summary.id));
|
|
1411
|
+
if (summary !== void 0 && (!summary.blank || workspace === void 0)) {
|
|
1412
|
+
this.replaceMain(summary.id, this.lifetime.signal, "preserve");
|
|
1413
|
+
return;
|
|
1414
|
+
}
|
|
1415
|
+
const navigation = AbortSignal.any([this.ctx.layout.beginNavigation(), this.lifetime.signal]);
|
|
1416
|
+
let sessionId;
|
|
1417
|
+
if (summary !== void 0 && workspace !== void 0 && summary.cwd === workspace.path && !workspaces.archivedSessionIds.includes(summary.id)) sessionId = await this.reuseBlank(workspace.workspaceId, summary.id);
|
|
1418
|
+
const target = workspace?.workspaceId ?? recentWorkspace(workspaces.items, sessions.byId);
|
|
1419
|
+
if (sessionId === void 0 && target !== void 0) sessionId = await this.connectWorkspace(target);
|
|
1420
|
+
if (sessionId !== void 0 && !navigation.aborted) this.replaceMain(sessionId, navigation, "preserve");
|
|
1421
|
+
}
|
|
1336
1422
|
/** @returns true when an archived current selection was cleared. */
|
|
1337
1423
|
clearArchivedCurrent() {
|
|
1338
|
-
const current = this.
|
|
1424
|
+
const current = this.mainReference?.sessionId;
|
|
1339
1425
|
if (current === void 0 || !this.workspaces.list.getSnapshot().archivedSessionIds.includes(current)) return false;
|
|
1340
|
-
this.
|
|
1426
|
+
this.clearMain();
|
|
1341
1427
|
return true;
|
|
1342
1428
|
}
|
|
1429
|
+
clearMain() {
|
|
1430
|
+
const previous = this.mainReference;
|
|
1431
|
+
this.mainReference = void 0;
|
|
1432
|
+
this.selection.set({});
|
|
1433
|
+
previous?.release();
|
|
1434
|
+
this.ctx.layout.selectPanel(null);
|
|
1435
|
+
}
|
|
1436
|
+
replaceMain(target, signal, panel, beforeOpen) {
|
|
1437
|
+
signal.throwIfAborted();
|
|
1438
|
+
const reference = this.sessions.retain(target, { source: "mainView" });
|
|
1439
|
+
try {
|
|
1440
|
+
signal.throwIfAborted();
|
|
1441
|
+
beforeOpen?.(reference.sessionId);
|
|
1442
|
+
if (signal.aborted) {
|
|
1443
|
+
reference.release();
|
|
1444
|
+
return;
|
|
1445
|
+
}
|
|
1446
|
+
const subagentAddress = typeof target === "string" ? this.sessions.subagentAddress(reference.sessionId) : target;
|
|
1447
|
+
this.selection.set({
|
|
1448
|
+
sessionId: reference.sessionId,
|
|
1449
|
+
...subagentAddress === void 0 ? {} : { subagentAddress }
|
|
1450
|
+
});
|
|
1451
|
+
} catch (error) {
|
|
1452
|
+
reference.release();
|
|
1453
|
+
throw error;
|
|
1454
|
+
}
|
|
1455
|
+
const previous = this.mainReference;
|
|
1456
|
+
this.mainReference = reference;
|
|
1457
|
+
previous?.release();
|
|
1458
|
+
if (panel === "reveal") this.ctx.layout.selectPanel(null);
|
|
1459
|
+
}
|
|
1343
1460
|
};
|
|
1344
1461
|
/** Stable tie-breaking follows Host Workspace order. */
|
|
1345
1462
|
function recentWorkspace(workspaces, sessions) {
|
|
@@ -1464,14 +1581,14 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
1464
1581
|
const addEntries = flowAvailable ? [{
|
|
1465
1582
|
id: ADD,
|
|
1466
1583
|
label: t("addWorkspaceMenu"),
|
|
1467
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
1584
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineRegular, { size: 16 }),
|
|
1468
1585
|
disabled: flowOpen || busy
|
|
1469
1586
|
}] : [];
|
|
1470
1587
|
const pinnedAdd = !addOnly && snapshot.items.length > 0;
|
|
1471
1588
|
const items = pinnedAdd ? snapshot.items.map((workspace) => ({
|
|
1472
1589
|
id: workspace.workspaceId,
|
|
1473
1590
|
label: workspace.title,
|
|
1474
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
1591
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderCloseRegular, { size: 16 }),
|
|
1475
1592
|
disabled: flowOpen || busy
|
|
1476
1593
|
})) : addEntries;
|
|
1477
1594
|
const settled = addOnly || snapshot.phase === "ready";
|
|
@@ -1575,7 +1692,7 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
1575
1692
|
//#region src/client/model.ts
|
|
1576
1693
|
/** Resolve the visible status-dot kind for one session, if any. */
|
|
1577
1694
|
function pendingKindOf(pending, id) {
|
|
1578
|
-
const kind = pending.get(id)?.kind;
|
|
1695
|
+
const kind = pending.get(id)?.pendingInteraction?.kind;
|
|
1579
1696
|
return kind === "approval" || kind === "plan-review" || kind === "question" ? kind : void 0;
|
|
1580
1697
|
}
|
|
1581
1698
|
/** Navigation key for sessions not accounted to a real workspace. */
|
|
@@ -1591,7 +1708,7 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
1591
1708
|
blank: summary.blank,
|
|
1592
1709
|
running: summary.running,
|
|
1593
1710
|
...pendingInteraction === void 0 ? {} : { pendingInteraction },
|
|
1594
|
-
completed: summary.
|
|
1711
|
+
completed: pending.get(summary.id)?.completionUnread === true,
|
|
1595
1712
|
updatedAt: summary.updatedAt,
|
|
1596
1713
|
workspaceKey,
|
|
1597
1714
|
workspaceTitle,
|
|
@@ -2122,7 +2239,7 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
2122
2239
|
const title = row.blank ? t("newSession") : row.title;
|
|
2123
2240
|
const isDelete = actionMode === "delete";
|
|
2124
2241
|
const actionLabel = isDelete ? t("deleteSession") : t("archive");
|
|
2125
|
-
const actionIcon = isDelete ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2242
|
+
const actionIcon = isDelete ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutlineRegular, {}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconArchiveOutlineRegular, { size: 16 });
|
|
2126
2243
|
const hasCwd = row.cwd !== void 0;
|
|
2127
2244
|
const pathsKnown = paths !== void 0;
|
|
2128
2245
|
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -2183,17 +2300,17 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
2183
2300
|
{
|
|
2184
2301
|
id: "rename",
|
|
2185
2302
|
label: t("rename"),
|
|
2186
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2303
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutlineRegular, {})
|
|
2187
2304
|
},
|
|
2188
2305
|
{
|
|
2189
2306
|
id: "fork",
|
|
2190
2307
|
label: t("fork"),
|
|
2191
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2308
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconBranchOutlineRegular, {})
|
|
2192
2309
|
},
|
|
2193
2310
|
{
|
|
2194
2311
|
id: "unread",
|
|
2195
2312
|
label: unread ? t("markRead") : t("markUnread"),
|
|
2196
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2313
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconClockOutlineRegular, {})
|
|
2197
2314
|
},
|
|
2198
2315
|
{
|
|
2199
2316
|
type: "separator",
|
|
@@ -2202,31 +2319,31 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
2202
2319
|
{
|
|
2203
2320
|
id: "reveal",
|
|
2204
2321
|
label: t("revealInExplorer"),
|
|
2205
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2322
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderOpenOutlineRegular, {}),
|
|
2206
2323
|
disabled: !hasCwd
|
|
2207
2324
|
},
|
|
2208
2325
|
{
|
|
2209
2326
|
id: "copy-path",
|
|
2210
2327
|
label: t("copyPath"),
|
|
2211
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2328
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCopyOutlineRegular, {}),
|
|
2212
2329
|
disabled: !hasCwd
|
|
2213
2330
|
},
|
|
2214
2331
|
{
|
|
2215
2332
|
id: "copy-dir",
|
|
2216
2333
|
label: t("copySessionDir"),
|
|
2217
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2334
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCopyOutlineRegular, {}),
|
|
2218
2335
|
disabled: !pathsKnown || paths?.dir == null
|
|
2219
2336
|
},
|
|
2220
2337
|
{
|
|
2221
2338
|
id: "copy-log",
|
|
2222
2339
|
label: t("copyLogPath"),
|
|
2223
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2340
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCopyOutlineRegular, {}),
|
|
2224
2341
|
disabled: !pathsKnown || paths?.log == null
|
|
2225
2342
|
},
|
|
2226
2343
|
{
|
|
2227
2344
|
id: "copy-id",
|
|
2228
2345
|
label: t("copySessionId"),
|
|
2229
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2346
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconLinkOutlineRegular, {})
|
|
2230
2347
|
},
|
|
2231
2348
|
{
|
|
2232
2349
|
type: "separator",
|
|
@@ -2292,7 +2409,7 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
2292
2409
|
onOpenMenu(row);
|
|
2293
2410
|
setMenuOpenButton((value) => !value);
|
|
2294
2411
|
},
|
|
2295
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2412
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutlineRegular, {})
|
|
2296
2413
|
})
|
|
2297
2414
|
})
|
|
2298
2415
|
})
|
|
@@ -2318,7 +2435,7 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
2318
2435
|
children: [
|
|
2319
2436
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2320
2437
|
className: "ya-status-slot",
|
|
2321
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2438
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderCloseRegular, {})
|
|
2322
2439
|
}),
|
|
2323
2440
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
|
|
2324
2441
|
className: "ya-row-main",
|
|
@@ -2336,7 +2453,7 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
2336
2453
|
children: row.path
|
|
2337
2454
|
})]
|
|
2338
2455
|
}),
|
|
2339
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2456
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutlineMedium, {}),
|
|
2340
2457
|
row.real && menuAt !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Menu, {
|
|
2341
2458
|
open: true,
|
|
2342
2459
|
onClose: () => {
|
|
@@ -2346,7 +2463,7 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
2346
2463
|
{
|
|
2347
2464
|
id: "create",
|
|
2348
2465
|
label: t("newSession"),
|
|
2349
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2466
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineRegular, {})
|
|
2350
2467
|
},
|
|
2351
2468
|
{
|
|
2352
2469
|
type: "separator",
|
|
@@ -2355,13 +2472,13 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
2355
2472
|
{
|
|
2356
2473
|
id: "reveal",
|
|
2357
2474
|
label: t("revealInExplorer"),
|
|
2358
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2475
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderOpenOutlineRegular, {}),
|
|
2359
2476
|
disabled: !hasPath
|
|
2360
2477
|
},
|
|
2361
2478
|
{
|
|
2362
2479
|
id: "copy-path",
|
|
2363
2480
|
label: t("copyPath"),
|
|
2364
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2481
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCopyOutlineRegular, {}),
|
|
2365
2482
|
disabled: !hasPath
|
|
2366
2483
|
},
|
|
2367
2484
|
{
|
|
@@ -2371,12 +2488,12 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
2371
2488
|
{
|
|
2372
2489
|
id: "rename",
|
|
2373
2490
|
label: t("rename"),
|
|
2374
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2491
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEditOutlineRegular, {})
|
|
2375
2492
|
},
|
|
2376
2493
|
{
|
|
2377
2494
|
id: "delete",
|
|
2378
2495
|
label: t("deleteWorkspace"),
|
|
2379
|
-
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2496
|
+
icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutlineRegular, {}),
|
|
2380
2497
|
danger: true
|
|
2381
2498
|
}
|
|
2382
2499
|
],
|
|
@@ -2403,12 +2520,17 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
2403
2520
|
}
|
|
2404
2521
|
/** Fill `sidebar.workspaces` with the replacement browser. */
|
|
2405
2522
|
function WorkspaceSidebar(props) {
|
|
2406
|
-
const { wide, expandSidebar, useSessions,
|
|
2523
|
+
const { wide, expandSidebar, useSessions, useSessionStatus, useCurrentSession, useWorkspaces, startSession, open, searchSessions, searchResultLimit, renameSession, forkSession, renameWorkspace, deleteWorkspace, archiveSession, createWorkspace, useDirectoryFlow, renderSlot, t, resolveSessionPaths, revealInExplorer } = props;
|
|
2407
2524
|
const sessions = useSessions((state) => state);
|
|
2525
|
+
const current = useCurrentSession((value) => value);
|
|
2526
|
+
const sessionsView = (0, react.useMemo)(() => ({
|
|
2527
|
+
...sessions,
|
|
2528
|
+
current
|
|
2529
|
+
}), [sessions, current]);
|
|
2408
2530
|
const workspaceState = useWorkspaces((state) => state);
|
|
2409
2531
|
const workspaces = workspaceState.items;
|
|
2410
2532
|
const archived = workspaceState.archivedSessionIds;
|
|
2411
|
-
const pendingInteractions =
|
|
2533
|
+
const pendingInteractions = useSessionStatus((state) => state);
|
|
2412
2534
|
const directoryFlowAvailable = useDirectoryFlow((value) => value);
|
|
2413
2535
|
const [pinnedOrder, setPinnedOrder] = (0, react.useState)(() => getPinnedOrder());
|
|
2414
2536
|
const [unreadSet, setUnreadSet] = (0, react.useState)(() => getUnread());
|
|
@@ -2434,16 +2556,16 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
2434
2556
|
setPathsTick((tick) => tick + 1);
|
|
2435
2557
|
}).catch(() => {});
|
|
2436
2558
|
};
|
|
2437
|
-
const allRows = (0, react.useMemo)(() => deriveRecent(
|
|
2559
|
+
const allRows = (0, react.useMemo)(() => deriveRecent(sessionsView, workspaces, archived, pendingInteractions, Number.MAX_SAFE_INTEGER), [
|
|
2438
2560
|
archived,
|
|
2439
2561
|
pendingInteractions,
|
|
2440
|
-
|
|
2562
|
+
sessionsView,
|
|
2441
2563
|
workspaces
|
|
2442
2564
|
]);
|
|
2443
2565
|
const recent = (0, react.useMemo)(() => applyPinned(allRows, pinnedOrder), [allRows, pinnedOrder]);
|
|
2444
|
-
const workspaceRows = (0, react.useMemo)(() => deriveWorkspaces(
|
|
2566
|
+
const workspaceRows = (0, react.useMemo)(() => deriveWorkspaces(sessionsView, workspaces, archived), [
|
|
2445
2567
|
archived,
|
|
2446
|
-
|
|
2568
|
+
sessionsView,
|
|
2447
2569
|
workspaces
|
|
2448
2570
|
]);
|
|
2449
2571
|
const now = Date.now();
|
|
@@ -2457,31 +2579,31 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
2457
2579
|
const observedCurrent = (0, react.useRef)(void 0);
|
|
2458
2580
|
const initialized = (0, react.useRef)(false);
|
|
2459
2581
|
(0, react.useEffect)(() => {
|
|
2460
|
-
if (initialized.current && observedCurrent.current ===
|
|
2582
|
+
if (initialized.current && observedCurrent.current === current) return;
|
|
2461
2583
|
initialized.current = true;
|
|
2462
|
-
observedCurrent.current =
|
|
2463
|
-
if (
|
|
2584
|
+
observedCurrent.current = current;
|
|
2585
|
+
if (current !== void 0) {
|
|
2464
2586
|
setDirection("forward");
|
|
2465
|
-
setSelectedKey(workspaceKeyForSession(
|
|
2587
|
+
setSelectedKey(workspaceKeyForSession(current, workspaces));
|
|
2466
2588
|
}
|
|
2467
|
-
}, [
|
|
2589
|
+
}, [current, workspaces]);
|
|
2468
2590
|
(0, react.useEffect)(() => {
|
|
2469
2591
|
if (selectedKey !== null && selectedKey !== "__ya_ungrouped__" && !workspaces.some((workspace) => workspace.workspaceId === selectedKey)) setSelectedKey(UNGROUPED);
|
|
2470
2592
|
}, [selectedKey, workspaces]);
|
|
2471
2593
|
const selectedWorkspace = selectedKey === null || selectedKey === "__ya_ungrouped__" ? void 0 : workspaces.find((workspace) => workspace.workspaceId === selectedKey);
|
|
2472
|
-
const levelGroups = (0, react.useMemo)(() => selectedKey !== null && selectedKey !== "__ya_ungrouped__" ? deriveWorkspaceSessionGroups(selectedKey,
|
|
2594
|
+
const levelGroups = (0, react.useMemo)(() => selectedKey !== null && selectedKey !== "__ya_ungrouped__" ? deriveWorkspaceSessionGroups(selectedKey, sessionsView, workspaces, archived, pendingInteractions, now) : [], [
|
|
2473
2595
|
archived,
|
|
2474
2596
|
pendingInteractions,
|
|
2475
|
-
|
|
2597
|
+
sessionsView,
|
|
2476
2598
|
workspaces,
|
|
2477
2599
|
selectedKey,
|
|
2478
2600
|
now
|
|
2479
2601
|
]);
|
|
2480
2602
|
const levelPinned = (0, react.useMemo)(() => extractPinnedGroups(levelGroups, pinnedOrder), [levelGroups, pinnedOrder]);
|
|
2481
|
-
const levelRows = (0, react.useMemo)(() => applyPinned(selectedKey === "__ya_ungrouped__" ? deriveWorkspaceSessions(UNGROUPED,
|
|
2603
|
+
const levelRows = (0, react.useMemo)(() => applyPinned(selectedKey === "__ya_ungrouped__" ? deriveWorkspaceSessions(UNGROUPED, sessionsView, workspaces, archived, pendingInteractions) : [], pinnedOrder), [
|
|
2482
2604
|
archived,
|
|
2483
2605
|
pendingInteractions,
|
|
2484
|
-
|
|
2606
|
+
sessionsView,
|
|
2485
2607
|
workspaces,
|
|
2486
2608
|
selectedKey,
|
|
2487
2609
|
pinnedOrder
|
|
@@ -2736,7 +2858,7 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
2736
2858
|
};
|
|
2737
2859
|
const sessionItem = (row, context = false) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SessionItem, {
|
|
2738
2860
|
row,
|
|
2739
|
-
current
|
|
2861
|
+
current,
|
|
2740
2862
|
now,
|
|
2741
2863
|
open: openRow,
|
|
2742
2864
|
rename: beginSessionRename,
|
|
@@ -2773,7 +2895,7 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
2773
2895
|
event.stopPropagation();
|
|
2774
2896
|
toggleActionMode();
|
|
2775
2897
|
},
|
|
2776
|
-
children: actionMode === "delete" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2898
|
+
children: actionMode === "delete" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutlineRegular, { size: wide ? 16 : 18 }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconArchiveOutlineRegular, { size: wide ? 16 : 18 })
|
|
2777
2899
|
}),
|
|
2778
2900
|
directoryFlowAvailable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
2779
2901
|
ref: pickerAnchor,
|
|
@@ -2783,7 +2905,7 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
2783
2905
|
onClick: () => {
|
|
2784
2906
|
setPickerOpen((value) => !value);
|
|
2785
2907
|
},
|
|
2786
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2908
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconProjectAddOutlineRegular, { size: wide ? 16 : 18 })
|
|
2787
2909
|
}),
|
|
2788
2910
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorkspacePickFlow, {
|
|
2789
2911
|
t,
|
|
@@ -2815,7 +2937,7 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
2815
2937
|
type: "button",
|
|
2816
2938
|
className: "ya-search-icon",
|
|
2817
2939
|
"aria-label": t("search"),
|
|
2818
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2940
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconSearchOutlineRegular, { size: wide ? 14 : 18 })
|
|
2819
2941
|
}),
|
|
2820
2942
|
wide && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
|
|
2821
2943
|
className: "ya-search-input",
|
|
@@ -2833,7 +2955,7 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
2833
2955
|
onClick: () => {
|
|
2834
2956
|
setQuery("");
|
|
2835
2957
|
},
|
|
2836
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2958
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCloseFillMedium, {})
|
|
2837
2959
|
})
|
|
2838
2960
|
]
|
|
2839
2961
|
}),
|
|
@@ -2874,7 +2996,7 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
2874
2996
|
event.stopPropagation();
|
|
2875
2997
|
setRecentCollapsed((value) => !value);
|
|
2876
2998
|
},
|
|
2877
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
2999
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutlineMedium, {})
|
|
2878
3000
|
})]
|
|
2879
3001
|
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
2880
3002
|
className: "ya-recent-list-wrap",
|
|
@@ -2923,7 +3045,7 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
2923
3045
|
},
|
|
2924
3046
|
children: t("workspaces")
|
|
2925
3047
|
}),
|
|
2926
|
-
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
3048
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronRightOutlineMedium, {}),
|
|
2927
3049
|
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
2928
3050
|
className: "ya-crumb",
|
|
2929
3051
|
children: selectedKey === "__ya_ungrouped__" ? t("ungrouped") : selectedWorkspace?.title
|
|
@@ -2935,7 +3057,7 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
2935
3057
|
onClick: () => {
|
|
2936
3058
|
startSession(selectedKey);
|
|
2937
3059
|
},
|
|
2938
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.
|
|
3060
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineRegular, {})
|
|
2939
3061
|
})
|
|
2940
3062
|
] })
|
|
2941
3063
|
}),
|
|
@@ -3131,6 +3253,10 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
3131
3253
|
const createWorkspace = (input) => ctx.workspaces.create(input);
|
|
3132
3254
|
const navigation = new YaWorkspaceNavigation(ctx, ctx.remote.directoryPicker, ctx.workspaces, ctx.sessions);
|
|
3133
3255
|
ctx.slots.provideRoot({ hooks: { workspaces: ctx.workspaces.list } });
|
|
3256
|
+
const currentSession = {
|
|
3257
|
+
getSnapshot: () => navigation.currentSessionId,
|
|
3258
|
+
subscribe: (listener) => navigation.subscribeSelection(listener)
|
|
3259
|
+
};
|
|
3134
3260
|
const searchSessions = async (query, signal) => {
|
|
3135
3261
|
const result = await ctx.sessions.search(query, signal);
|
|
3136
3262
|
if (!result.ok) throw new Error(result.error.message);
|
|
@@ -3197,7 +3323,10 @@ button.ya-crumb:hover { background:var(--dsw-alias-interactive-bg-hover); color:
|
|
|
3197
3323
|
console.warn("reveal request rejected:", reason);
|
|
3198
3324
|
}
|
|
3199
3325
|
},
|
|
3200
|
-
hooks: {
|
|
3326
|
+
hooks: {
|
|
3327
|
+
directoryFlow: sidebarFlow,
|
|
3328
|
+
currentSession
|
|
3329
|
+
}
|
|
3201
3330
|
});
|
|
3202
3331
|
const pickerInjected = () => ({
|
|
3203
3332
|
createWorkspace,
|