@michengai/dsh-archive-manager 1.3.0 → 1.3.1

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/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { getEntryLocation, getOnlineUpdate, getSidebarFavoriteStar, setEntryLocation, setOnlineUpdate, setSidebarFavoriteStar } from "./plugin-settings.js";
1
+ import { getEntryLocation, getOnlineUpdate, getSidebarFavoriteStarMode, setEntryLocation, setOnlineUpdate, setSidebarFavoriteStarMode } from "./plugin-settings.js";
2
2
  import { isTrustedUpdateRequest, rawService, registerPluginUpdater, releaseUpdateRoute } from "./plugin-updater.js";
3
3
  import { apply as installHost, inject as hostInject } from "./host-install.js";
4
4
  import { authorizeExplorerPath } from "./explorer-path-policy.js";
@@ -85,8 +85,8 @@ function registerSettingsRoutes(ctx, hostUpdateDisabled) {
85
85
  path: SIDEBAR_FAVORITE_STAR_ENDPOINT,
86
86
  handler: async (request, response) => {
87
87
  if (request.method === "GET" || request.method === "HEAD") {
88
- const enabled = await getSidebarFavoriteStar();
89
- sendJson(response, 200, { ok: true, enabled });
88
+ const mode = await getSidebarFavoriteStarMode();
89
+ sendJson(response, 200, { ok: true, mode, enabled: mode !== "none" });
90
90
  return;
91
91
  }
92
92
  if (request.method === "POST") {
@@ -95,12 +95,25 @@ function registerSettingsRoutes(ctx, hostUpdateDisabled) {
95
95
  return;
96
96
  }
97
97
  const body = await readJsonBody(request);
98
- if (!body || typeof body.enabled !== "boolean") {
99
- sendJson(response, 400, { ok: false, error: "enabled \u5FC5\u987B\u662F\u5E03\u5C14\u503C" });
98
+ if (!body) {
99
+ sendJson(response, 400, { ok: false, error: "\u8BF7\u6C42\u4F53\u4E0D\u80FD\u4E3A\u7A7A" });
100
100
  return;
101
101
  }
102
- const enabled = await setSidebarFavoriteStar(body.enabled);
103
- sendJson(response, 200, { ok: true, enabled });
102
+ let targetMode;
103
+ if (typeof body.mode === "string") {
104
+ if (body.mode !== "all" && body.mode !== "favorites" && body.mode !== "none") {
105
+ sendJson(response, 400, { ok: false, error: "mode \u5FC5\u987B\u662F all\u3001favorites \u6216 none" });
106
+ return;
107
+ }
108
+ targetMode = body.mode;
109
+ } else if (typeof body.enabled === "boolean") {
110
+ targetMode = body.enabled ? "all" : "none";
111
+ } else {
112
+ sendJson(response, 400, { ok: false, error: "\u7F3A\u5C11\u5408\u6CD5\u7684 mode \u6216 enabled \u53C2\u6570" });
113
+ return;
114
+ }
115
+ const mode = await setSidebarFavoriteStarMode(targetMode);
116
+ sendJson(response, 200, { ok: true, mode, enabled: mode !== "none" });
104
117
  return;
105
118
  }
106
119
  response.writeHead(405, { allow: "GET, HEAD, POST" });
@@ -3,6 +3,11 @@ import { existsSync, mkdirSync } from "node:fs";
3
3
  import { readFile, rename, unlink, writeFile } from "node:fs/promises";
4
4
  import { homedir } from "node:os";
5
5
  import { dirname, join } from "node:path";
6
+ function normalizeFavoriteStarMode(value) {
7
+ if (value === "all" || value === "favorites" || value === "none") return value;
8
+ if (value === false) return "none";
9
+ return "all";
10
+ }
6
11
  function resolveDshHome() {
7
12
  const custom = process.env.DSH_HOME;
8
13
  if (typeof custom === "string" && custom.trim() !== "") {
@@ -62,7 +67,7 @@ async function readSettings() {
62
67
  entryLocation: "settings",
63
68
  sidebarEntry: false,
64
69
  onlineUpdate: true,
65
- sidebarFavoriteStar: true
70
+ sidebarFavoriteStar: "all"
66
71
  };
67
72
  if (!existsSync(path)) {
68
73
  return defaultSettings;
@@ -86,7 +91,7 @@ async function readSettings() {
86
91
  entryLocation,
87
92
  sidebarEntry: entryLocation !== "settings",
88
93
  onlineUpdate: typeof item.onlineUpdate === "boolean" ? item.onlineUpdate : true,
89
- sidebarFavoriteStar: typeof item.sidebarFavoriteStar === "boolean" ? item.sidebarFavoriteStar : true
94
+ sidebarFavoriteStar: normalizeFavoriteStarMode(item.sidebarFavoriteStar)
90
95
  };
91
96
  } catch {
92
97
  return defaultSettings;
@@ -99,7 +104,7 @@ async function writeSettings(next) {
99
104
  entryLocation: location,
100
105
  sidebarEntry: location !== "settings",
101
106
  onlineUpdate: next.onlineUpdate !== false,
102
- sidebarFavoriteStar: next.sidebarFavoriteStar !== false
107
+ sidebarFavoriteStar: normalizeFavoriteStarMode(next.sidebarFavoriteStar)
103
108
  };
104
109
  const serialized = `${JSON.stringify(normalized, null, 2)}
105
110
  `;
@@ -153,31 +158,49 @@ async function setOnlineUpdate(enabled) {
153
158
  return enabled;
154
159
  });
155
160
  }
156
- async function getSidebarFavoriteStar() {
161
+ async function getSidebarFavoriteStarMode() {
157
162
  const current = await readSettings();
158
- return current.sidebarFavoriteStar !== false;
163
+ return normalizeFavoriteStarMode(current.sidebarFavoriteStar);
159
164
  }
160
- async function setSidebarFavoriteStar(enabled) {
161
- if (typeof enabled !== "boolean") {
162
- throw new TypeError("sidebarFavoriteStar must be a boolean");
165
+ async function setSidebarFavoriteStarMode(mode) {
166
+ if (mode !== "all" && mode !== "favorites" && mode !== "none") {
167
+ throw new TypeError("sidebarFavoriteStar mode must be 'all', 'favorites', or 'none'");
163
168
  }
164
169
  return enqueueWrite(async () => {
165
170
  const current = await readSettings();
166
- current.sidebarFavoriteStar = enabled;
171
+ current.sidebarFavoriteStar = mode;
167
172
  await writeSettings(current);
168
- return enabled;
173
+ return mode;
169
174
  });
170
175
  }
176
+ async function getSidebarFavoriteStar() {
177
+ const mode = await getSidebarFavoriteStarMode();
178
+ return mode !== "none";
179
+ }
180
+ async function setSidebarFavoriteStar(value) {
181
+ if (typeof value !== "boolean" && value !== "all" && value !== "favorites" && value !== "none") {
182
+ throw new TypeError("sidebarFavoriteStar must be 'all', 'favorites', 'none', or a boolean");
183
+ }
184
+ if (typeof value === "boolean") {
185
+ const mode = value ? "all" : "none";
186
+ await setSidebarFavoriteStarMode(mode);
187
+ return value;
188
+ }
189
+ return setSidebarFavoriteStarMode(value);
190
+ }
171
191
  export {
172
192
  getEntryLocation,
173
193
  getOnlineUpdate,
174
194
  getSidebarEntry,
175
195
  getSidebarFavoriteStar,
196
+ getSidebarFavoriteStarMode,
176
197
  managerSettingsPath,
198
+ normalizeFavoriteStarMode,
177
199
  readSettings,
178
200
  setEntryLocation,
179
201
  setOnlineUpdate,
180
202
  setSidebarEntry,
181
203
  setSidebarFavoriteStar,
204
+ setSidebarFavoriteStarMode,
182
205
  writeSettings
183
206
  };
@@ -1,5 +1,5 @@
1
1
  import * as React from "react";
2
- import { IconArchiveOutlineMedium, SegmentedControl, Switch as PrimitiveSwitch } from "@deepseek-ai/dsh-client-ui-primitives";
2
+ import { IconArchiveOutlineMedium, SegmentedControl } from "@deepseek-ai/dsh-client-ui-primitives";
3
3
  const h = React.createElement;
4
4
  const BUNDLE_KEY = "@michengai/dsh-archive-manager";
5
5
  const SIDEBAR_PANEL_ID = "archived-sessions";
@@ -37,15 +37,14 @@ function ArchiveBundleConfigCard(props) {
37
37
  enabled = false,
38
38
  onToggle,
39
39
  disabled,
40
- onlineUpdateEnabled = true,
41
- onToggleOnlineUpdate,
42
- onlineUpdateDisabled,
43
- onlineUpdateLocked = false,
44
40
  sidebarFavoriteStarEnabled = true,
45
41
  onToggleSidebarFavoriteStar,
46
- sidebarFavoriteStarDisabled
42
+ sidebarFavoriteStarDisabled,
43
+ sidebarFavoriteStarMode: propStarMode,
44
+ onSidebarFavoriteStarModeChange
47
45
  } = props;
48
46
  const effectiveLocation = propLocation ?? (enabled ? "both" : "settings");
47
+ const effectiveStarMode = propStarMode ?? (sidebarFavoriteStarEnabled === false ? "none" : "all");
49
48
  const handleLocationChange = (next) => {
50
49
  if (next === "both" || next === "sidebar" || next === "settings") {
51
50
  if (typeof onLocationChange === "function") {
@@ -55,6 +54,15 @@ function ArchiveBundleConfigCard(props) {
55
54
  }
56
55
  }
57
56
  };
57
+ const handleStarModeChange = (next) => {
58
+ if (next === "all" || next === "favorites" || next === "none") {
59
+ if (typeof onSidebarFavoriteStarModeChange === "function") {
60
+ onSidebarFavoriteStarModeChange(next);
61
+ } else if (typeof onToggleSidebarFavoriteStar === "function") {
62
+ onToggleSidebarFavoriteStar(next !== "none");
63
+ }
64
+ }
65
+ };
58
66
  const rows = [
59
67
  h(
60
68
  "div",
@@ -80,7 +88,7 @@ function ArchiveBundleConfigCard(props) {
80
88
  })
81
89
  )
82
90
  ];
83
- if (typeof onToggleSidebarFavoriteStar === "function") {
91
+ if (typeof onSidebarFavoriteStarModeChange === "function" || typeof onToggleSidebarFavoriteStar === "function") {
84
92
  rows.push(
85
93
  h(
86
94
  "div",
@@ -91,11 +99,17 @@ function ArchiveBundleConfigCard(props) {
91
99
  h("span", { className: "dsham_bundle_title" }, t("sidebar.favoriteStar.title")),
92
100
  h("span", { className: "dsham_bundle_desc" }, t("sidebar.favoriteStar.desc"))
93
101
  ),
94
- h(PrimitiveSwitch, {
95
- checked: sidebarFavoriteStarEnabled,
96
- onChange: onToggleSidebarFavoriteStar,
97
- label: t("sidebar.favoriteStar.toggle"),
98
- disabled: sidebarFavoriteStarDisabled
102
+ h(SegmentedControl, {
103
+ id: "dsham-bundle-favorite-star-mode",
104
+ value: effectiveStarMode,
105
+ onChange: handleStarModeChange,
106
+ label: t("sidebar.favoriteStar.title"),
107
+ disabled: sidebarFavoriteStarDisabled ?? disabled,
108
+ options: [
109
+ { value: "all", label: t("sidebar.favoriteStar.all") },
110
+ { value: "favorites", label: t("sidebar.favoriteStar.favorites") },
111
+ { value: "none", label: t("sidebar.favoriteStar.none") }
112
+ ]
99
113
  })
100
114
  )
101
115
  );
@@ -104,7 +118,12 @@ function ArchiveBundleConfigCard(props) {
104
118
  }
105
119
  function ArchiveBundleConfigCardWrapper(props) {
106
120
  const [location, setLocation] = React.useState(props.getLocation);
107
- const [sidebarFavoriteStarEnabled, setSidebarFavoriteStarEnabled] = React.useState(props.getSidebarFavoriteStarEnabled ? props.getSidebarFavoriteStarEnabled : () => true);
121
+ const resolveInitialStarMode = () => {
122
+ if (props.getSidebarFavoriteStarMode) return props.getSidebarFavoriteStarMode();
123
+ if (props.getSidebarFavoriteStarEnabled) return props.getSidebarFavoriteStarEnabled() ? "all" : "none";
124
+ return "all";
125
+ };
126
+ const [sidebarFavoriteStarMode, setSidebarFavoriteStarMode] = React.useState(resolveInitialStarMode);
108
127
  const [saveError, setSaveError] = React.useState(null);
109
128
  const [savingLocation, setSavingLocation] = React.useState(false);
110
129
  const [savingFavoriteStar, setSavingFavoriteStar] = React.useState(false);
@@ -112,8 +131,10 @@ function ArchiveBundleConfigCardWrapper(props) {
112
131
  const syncState = () => {
113
132
  setLocation(props.getLocation());
114
133
  setSaveError(null);
115
- if (props.getSidebarFavoriteStarEnabled) {
116
- setSidebarFavoriteStarEnabled(props.getSidebarFavoriteStarEnabled());
134
+ if (props.getSidebarFavoriteStarMode) {
135
+ setSidebarFavoriteStarMode(props.getSidebarFavoriteStarMode());
136
+ } else if (props.getSidebarFavoriteStarEnabled) {
137
+ setSidebarFavoriteStarMode(props.getSidebarFavoriteStarEnabled() ? "all" : "none");
117
138
  }
118
139
  };
119
140
  syncState();
@@ -131,13 +152,12 @@ function ArchiveBundleConfigCardWrapper(props) {
131
152
  setSavingLocation(false);
132
153
  });
133
154
  };
134
- const onToggleSidebarFavoriteStar = props.setSidebarFavoriteStar ? (next) => {
155
+ const onSidebarFavoriteStarModeChange = props.setSidebarFavoriteStarMode || props.setSidebarFavoriteStar ? (next) => {
135
156
  setSavingFavoriteStar(true);
136
- setSidebarFavoriteStarEnabled(next);
137
- props.setSidebarFavoriteStar(next).catch(() => {
138
- if (props.getSidebarFavoriteStarEnabled) {
139
- setSidebarFavoriteStarEnabled(props.getSidebarFavoriteStarEnabled());
140
- }
157
+ setSidebarFavoriteStarMode(next);
158
+ const savePromise = props.setSidebarFavoriteStarMode ? props.setSidebarFavoriteStarMode(next) : props.setSidebarFavoriteStar(next !== "none");
159
+ savePromise.catch(() => {
160
+ setSidebarFavoriteStarMode(resolveInitialStarMode());
141
161
  }).finally(() => {
142
162
  setSavingFavoriteStar(false);
143
163
  });
@@ -148,9 +168,11 @@ function ArchiveBundleConfigCardWrapper(props) {
148
168
  errorMessage: saveError,
149
169
  disabled: savingLocation,
150
170
  onLocationChange,
151
- sidebarFavoriteStarEnabled,
171
+ sidebarFavoriteStarMode,
172
+ sidebarFavoriteStarEnabled: sidebarFavoriteStarMode !== "none",
152
173
  sidebarFavoriteStarDisabled: savingFavoriteStar,
153
- onToggleSidebarFavoriteStar
174
+ onSidebarFavoriteStarModeChange,
175
+ onToggleSidebarFavoriteStar: onSidebarFavoriteStarModeChange ? (enabled) => onSidebarFavoriteStarModeChange(enabled ? "all" : "none") : void 0
154
176
  });
155
177
  }
156
178
  function setupSidebarEntry(ctx, options) {
@@ -163,11 +185,10 @@ function setupSidebarEntry(ctx, options) {
163
185
  isEnabled: () => false,
164
186
  isSupported: () => false,
165
187
  setEnabled: async () => false,
166
- isOnlineUpdateEnabled: () => true,
167
- isOnlineUpdateLocked: () => false,
168
- setOnlineUpdate: async () => false,
169
188
  isSidebarFavoriteStarEnabled: () => true,
170
189
  setSidebarFavoriteStar: async () => false,
190
+ getSidebarFavoriteStarMode: () => "all",
191
+ setSidebarFavoriteStarMode: async () => "all",
171
192
  destroy: () => {
172
193
  }
173
194
  };
@@ -294,30 +315,22 @@ function setupSidebarEntry(ctx, options) {
294
315
  await setLocation(next ? "both" : "settings");
295
316
  return isSidebarEnabled();
296
317
  };
297
- let onlineUpdateEnabled = true;
298
- let onlineUpdateLocked = false;
299
- const setOnlineUpdate = async (next) => {
300
- if (destroyed || onlineUpdateLocked) return onlineUpdateEnabled;
301
- onlineUpdateEnabled = next;
318
+ let sidebarFavoriteStarMode = "all";
319
+ let favoriteStarEpoch = 0;
320
+ const setSidebarFavoriteStarMode = async (next) => {
321
+ if (destroyed) return sidebarFavoriteStarMode;
322
+ const currentEpoch = ++favoriteStarEpoch;
323
+ const previous = sidebarFavoriteStarMode;
324
+ sidebarFavoriteStarMode = next;
302
325
  notify();
303
- if (typeof options.onOnlineUpdateChange === "function") {
326
+ if (typeof options.onSidebarFavoriteStarModeChange === "function") {
304
327
  try {
305
- options.onOnlineUpdateChange(next);
328
+ options.onSidebarFavoriteStarModeChange(next);
306
329
  } catch {
307
330
  }
308
- }
309
- return next;
310
- };
311
- let sidebarFavoriteStarEnabled = true;
312
- let favoriteStarEpoch = 0;
313
- const setSidebarFavoriteStar = async (next) => {
314
- if (destroyed) return sidebarFavoriteStarEnabled;
315
- const currentEpoch = ++favoriteStarEpoch;
316
- sidebarFavoriteStarEnabled = next;
317
- notify();
318
- if (typeof options.onSidebarFavoriteStarChange === "function") {
331
+ } else if (typeof options.onSidebarFavoriteStarChange === "function") {
319
332
  try {
320
- options.onSidebarFavoriteStarChange(next);
333
+ options.onSidebarFavoriteStarChange(next !== "none");
321
334
  } catch {
322
335
  }
323
336
  }
@@ -325,16 +338,21 @@ function setupSidebarEntry(ctx, options) {
325
338
  await callApi("/sidebar-favorite-star", {
326
339
  method: "POST",
327
340
  headers: { "content-type": "application/json" },
328
- body: JSON.stringify({ enabled: next })
341
+ body: JSON.stringify({ mode: next, enabled: next !== "none" })
329
342
  });
330
343
  return next;
331
344
  } catch (err) {
332
345
  if (currentEpoch === favoriteStarEpoch) {
333
- sidebarFavoriteStarEnabled = !next;
346
+ sidebarFavoriteStarMode = previous;
334
347
  notify();
335
- if (typeof options.onSidebarFavoriteStarChange === "function") {
348
+ if (typeof options.onSidebarFavoriteStarModeChange === "function") {
349
+ try {
350
+ options.onSidebarFavoriteStarModeChange(previous);
351
+ } catch {
352
+ }
353
+ } else if (typeof options.onSidebarFavoriteStarChange === "function") {
336
354
  try {
337
- options.onSidebarFavoriteStarChange(!next);
355
+ options.onSidebarFavoriteStarChange(previous !== "none");
338
356
  } catch {
339
357
  }
340
358
  }
@@ -342,6 +360,10 @@ function setupSidebarEntry(ctx, options) {
342
360
  throw err;
343
361
  }
344
362
  };
363
+ const setSidebarFavoriteStar = async (next) => {
364
+ const res = await setSidebarFavoriteStarMode(next ? "all" : "none");
365
+ return res !== "none";
366
+ };
345
367
  const loadEpoch = epoch;
346
368
  callApi("/sidebar-entry").then((res) => {
347
369
  if (!destroyed && epoch === loadEpoch && res) {
@@ -363,12 +385,21 @@ function setupSidebarEntry(ctx, options) {
363
385
  });
364
386
  const loadFavoriteStarEpoch = favoriteStarEpoch;
365
387
  callApi("/sidebar-favorite-star").then((res) => {
366
- if (!destroyed && favoriteStarEpoch === loadFavoriteStarEpoch && res && typeof res.enabled === "boolean") {
367
- sidebarFavoriteStarEnabled = res.enabled;
388
+ if (!destroyed && favoriteStarEpoch === loadFavoriteStarEpoch && res) {
389
+ if (res.mode === "all" || res.mode === "favorites" || res.mode === "none") {
390
+ sidebarFavoriteStarMode = res.mode;
391
+ } else if (typeof res.enabled === "boolean") {
392
+ sidebarFavoriteStarMode = res.enabled ? "all" : "none";
393
+ }
368
394
  notify();
369
- if (typeof options.onSidebarFavoriteStarChange === "function") {
395
+ if (typeof options.onSidebarFavoriteStarModeChange === "function") {
396
+ try {
397
+ options.onSidebarFavoriteStarModeChange(sidebarFavoriteStarMode);
398
+ } catch {
399
+ }
400
+ } else if (typeof options.onSidebarFavoriteStarChange === "function") {
370
401
  try {
371
- options.onSidebarFavoriteStarChange(sidebarFavoriteStarEnabled);
402
+ options.onSidebarFavoriteStarChange(sidebarFavoriteStarMode !== "none");
372
403
  } catch {
373
404
  }
374
405
  }
@@ -413,11 +444,10 @@ function setupSidebarEntry(ctx, options) {
413
444
  setLocation,
414
445
  getEnabled: () => isSidebarEnabled(),
415
446
  setSidebar: setEnabled,
416
- getOnlineUpdateEnabled: () => onlineUpdateEnabled,
417
- setOnlineUpdate,
418
- getOnlineUpdateLocked: () => onlineUpdateLocked,
419
- getSidebarFavoriteStarEnabled: () => sidebarFavoriteStarEnabled,
447
+ getSidebarFavoriteStarEnabled: () => sidebarFavoriteStarMode !== "none",
420
448
  setSidebarFavoriteStar,
449
+ getSidebarFavoriteStarMode: () => sidebarFavoriteStarMode,
450
+ setSidebarFavoriteStarMode,
421
451
  subscribe: (fn) => {
422
452
  listeners.add(fn);
423
453
  return () => {
@@ -434,11 +464,10 @@ function setupSidebarEntry(ctx, options) {
434
464
  isEnabled: () => isSidebarEnabled(),
435
465
  isSupported: () => sidebarSupported,
436
466
  setEnabled,
437
- isOnlineUpdateEnabled: () => onlineUpdateEnabled,
438
- isOnlineUpdateLocked: () => onlineUpdateLocked,
439
- setOnlineUpdate,
440
- isSidebarFavoriteStarEnabled: () => sidebarFavoriteStarEnabled,
467
+ isSidebarFavoriteStarEnabled: () => sidebarFavoriteStarMode !== "none",
441
468
  setSidebarFavoriteStar,
469
+ getSidebarFavoriteStarMode: () => sidebarFavoriteStarMode,
470
+ setSidebarFavoriteStarMode,
442
471
  destroy: () => {
443
472
  if (destroyed) return;
444
473
  destroyed = true;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@michengai/dsh-archive-manager",
3
- "version": "1.3.0",
3
+ "version": "1.3.1",
4
4
  "description": "归档、恢复、收藏和永久删除会话,并诊断损坏的会话日志。 · Archive, restore, favorite, and permanently delete sessions, and diagnose damaged session logs.",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@11.22.0",