@michengai/dsh-archive-manager 1.0.0 → 1.0.2

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 CHANGED
@@ -1,5 +1,18 @@
1
+ "use strict";
1
2
  (() => {
2
- // src/session-health-locales.js
3
+ // src/contracts.ts
4
+ function record(value) {
5
+ if (typeof value !== "object" || value === null || Array.isArray(value)) throw new TypeError("\u53C2\u6570\u5FC5\u987B\u4E3A\u5BF9\u8C61");
6
+ return value;
7
+ }
8
+ function errorMessage(error) {
9
+ return String(error && typeof error === "object" && "message" in error ? error.message ?? error : error);
10
+ }
11
+ function errorCode(error) {
12
+ return error && typeof error === "object" && "code" in error ? error.code : void 0;
13
+ }
14
+
15
+ // src/session-health-locales.ts
3
16
  var healthZh = {
4
17
  "health.archived": "\u5DF2\u5F52\u6863\u4F1A\u8BDD\u9700\u8981\u68C0\u67E5",
5
18
  "health.unarchived": "\u672A\u5F52\u6863\u4F1A\u8BDD\u9700\u8981\u68C0\u67E5",
@@ -79,7 +92,7 @@
79
92
  "health.failed.advice": "Expand technical details to inspect the error. Resolve it before diagnosing again."
80
93
  };
81
94
 
82
- // src/archive-discovery.js
95
+ // src/archive-discovery.ts
83
96
  var id = (value) => {
84
97
  if (typeof value !== "string" || !value.length || value.length > 1024) throw new TypeError("\u4F1A\u8BDD ID \u65E0\u6548");
85
98
  return value;
@@ -88,11 +101,13 @@
88
101
  if (typeof value !== "string" || value.length > 200 || required && !value.trim()) throw new TypeError("\u5173\u952E\u8BCD\u987B\u4E3A 1\uFF5E200 \u4E2A\u5B57\u7B26");
89
102
  return value.trim();
90
103
  };
91
- var searchInputSchema = { parse(value) {
104
+ var searchInputSchema = { parse(input) {
105
+ const value = record(input);
92
106
  if (!value || !Array.isArray(value.sessionIds) || !value.sessionIds.length || value.sessionIds.length > 20) throw new TypeError("\u6BCF\u6B21\u68C0\u7D22\u987B\u5305\u542B 1\uFF5E20 \u4E2A\u4F1A\u8BDD");
93
107
  return { sessionIds: [...new Set(value.sessionIds.map(id))], query: queryText(value.query, true) };
94
108
  } };
95
- var previewInputSchema = { parse(value) {
109
+ var previewInputSchema = { parse(input) {
110
+ const value = record(input);
96
111
  if (!value) throw new TypeError("\u9884\u89C8\u53C2\u6570\u65E0\u6548");
97
112
  return { sessionId: id(value.sessionId), query: queryText(value.query ?? "") };
98
113
  } };
@@ -101,41 +116,45 @@
101
116
  return value;
102
117
  };
103
118
  var sequence = (value) => {
104
- if (!Number.isSafeInteger(value) || value < 0) throw new TypeError("\u6D88\u606F\u5E8F\u53F7\u65E0\u6548");
119
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) throw new TypeError("\u6D88\u606F\u5E8F\u53F7\u65E0\u6548");
105
120
  return value;
106
121
  };
107
- var searchResultSchema = { parse(value) {
122
+ var searchResultSchema = { parse(input) {
123
+ const value = record(input);
108
124
  if (!value || !Array.isArray(value.items) || !Array.isArray(value.failures) || value.items.length > 20 || value.failures.length > 20) throw new TypeError("\u68C0\u7D22\u7ED3\u679C\u65E0\u6548");
109
125
  return {
110
- items: value.items.map((row) => ({ sessionId: id(row.sessionId), seq: sequence(row.seq), snippet: boundedString(row.snippet, 400) })),
111
- failures: value.failures.map((row) => ({ sessionId: id(row.sessionId), message: boundedString(row.message, 500) }))
126
+ items: value.items.map(record).map((row) => ({ sessionId: id(row.sessionId), seq: sequence(row.seq), snippet: boundedString(row.snippet, 400) })),
127
+ failures: value.failures.map(record).map((row) => ({ sessionId: id(row.sessionId), message: boundedString(row.message, 500) }))
112
128
  };
113
129
  } };
114
- var previewResultSchema = { parse(value) {
130
+ var previewResultSchema = { parse(input) {
131
+ const value = record(input);
115
132
  if (!value || !Array.isArray(value.messages) || value.messages.length > 8 || typeof value.hasEarlier !== "boolean" || typeof value.hasLater !== "boolean") throw new TypeError("\u9884\u89C8\u7ED3\u679C\u65E0\u6548");
116
133
  return {
117
134
  sessionId: id(value.sessionId),
118
135
  hasEarlier: value.hasEarlier,
119
136
  hasLater: value.hasLater,
120
- messages: value.messages.map((row) => {
121
- if (!["user", "assistant"].includes(row.role) || typeof row.truncated !== "boolean") throw new TypeError("\u6D88\u606F\u89D2\u8272\u6216\u622A\u65AD\u72B6\u6001\u65E0\u6548");
137
+ messages: value.messages.map(record).map((row) => {
138
+ if (typeof row.role !== "string" || !["user", "assistant"].includes(row.role) || typeof row.truncated !== "boolean") throw new TypeError("\u6D88\u606F\u89D2\u8272\u6216\u622A\u65AD\u72B6\u6001\u65E0\u6548");
122
139
  return { seq: sequence(row.seq), role: row.role, text: boundedString(row.text, 2e3), truncated: row.truncated };
123
140
  })
124
141
  };
125
142
  } };
126
- var detailsInputSchema = { parse(value) {
143
+ var detailsInputSchema = { parse(input) {
144
+ const value = record(input);
127
145
  if (!value || !Array.isArray(value.sessionIds) || !value.sessionIds.length || value.sessionIds.length > 20) throw new TypeError("\u6BCF\u6B21\u987B\u5305\u542B 1\uFF5E20 \u4E2A\u4F1A\u8BDD");
128
146
  return { sessionIds: [...new Set(value.sessionIds.map(id))] };
129
147
  } };
130
- var detailsResultSchema = { parse(value) {
148
+ var detailsResultSchema = { parse(input) {
149
+ const value = record(input);
131
150
  if (!value || !Array.isArray(value.items) || value.items.length > 20) throw new TypeError("\u4F1A\u8BDD\u8BE6\u60C5\u65E0\u6548");
132
- return { items: value.items.map((row) => ({ sessionId: id(row.sessionId), ...row.createdAt !== void 0 ? { createdAt: sequence(row.createdAt) } : {}, turnCount: row.turnCount === null ? null : sequence(row.turnCount), path: row.path === null ? null : boundedString(row.path, 32768), error: boundedString(row.error, 500) })) };
151
+ return { items: value.items.map(record).map((row) => ({ sessionId: id(row.sessionId), ...row.createdAt !== void 0 ? { createdAt: sequence(row.createdAt) } : {}, turnCount: row.turnCount === null ? null : sequence(row.turnCount), path: row.path === null ? null : boundedString(row.path, 32768), error: boundedString(row.error, 500) })) };
133
152
  } };
134
153
  function compareTurnCounts(left, right, order) {
135
- const a = Number.isSafeInteger(left) && left >= 0;
136
- const b = Number.isSafeInteger(right) && right >= 0;
154
+ const a = typeof left === "number" && Number.isSafeInteger(left) && left >= 0;
155
+ const b = typeof right === "number" && Number.isSafeInteger(right) && right >= 0;
137
156
  if (a !== b) return a ? -1 : 1;
138
- return a ? order === "turnsAsc" ? left - right : right - left : 0;
157
+ return a && b ? order === "turnsAsc" ? left - right : right - left : 0;
139
158
  }
140
159
  async function copySessionText(text, clipboard = globalThis.navigator?.clipboard) {
141
160
  if (typeof text !== "string" || !text) throw Object.assign(new Error("\u6CA1\u6709\u53EF\u590D\u5236\u7684\u5185\u5BB9"), { code: "copy.empty" });
@@ -148,7 +167,8 @@
148
167
  }
149
168
  function discoveryInvocations() {
150
169
  const codec = (name, schema) => ({ mode: "strict", typeSymbol: `@michengai/dsh-archive-manager/types#${name}`, create: () => schema, schema });
151
- return [["searchSessionContent", searchInputSchema, searchResultSchema], ["diagnoseSession", repairInputSchema, repairResultSchema], ["repairSession", repairInputSchema, repairResultSchema], ["sessionDetails", detailsInputSchema, detailsResultSchema], ["searchArchivedContent", searchInputSchema, searchResultSchema], ["previewArchivedSession", previewInputSchema, previewResultSchema]].map(([method, input, output]) => ({
170
+ const methods = [["searchSessionContent", searchInputSchema, searchResultSchema], ["diagnoseSession", repairInputSchema, repairResultSchema], ["repairSession", repairInputSchema, repairResultSchema], ["sessionDetails", detailsInputSchema, detailsResultSchema], ["searchArchivedContent", searchInputSchema, searchResultSchema], ["previewArchivedSession", previewInputSchema, previewResultSchema]];
171
+ return methods.map(([method, input, output]) => ({
152
172
  id: `@michengai/dsh-archive-manager#workspaceRegistry/${method}`,
153
173
  service: "workspaceRegistry",
154
174
  namespace: "workspaceRegistry",
@@ -169,7 +189,7 @@
169
189
  const next = folded + character.toLowerCase().length;
170
190
  if (start === void 0 && next > position) start = original;
171
191
  original += character.length;
172
- if (next >= position + needle.length) return { start, end: original };
192
+ if (next >= position + needle.length) return { start: start ?? original, end: original };
173
193
  folded = next;
174
194
  }
175
195
  return null;
@@ -191,7 +211,7 @@
191
211
  function matchesUpdatedRange(value, from, to) {
192
212
  if (!validUpdatedRange(from, to)) return false;
193
213
  if (!from && !to) return true;
194
- const time = typeof value === "number" ? value : Date.parse(value);
214
+ const time = typeof value === "number" ? value : Date.parse(value ?? "");
195
215
  return Number.isFinite(time) && (!from || time >= dayBoundary(from)) && (!to || time < dayBoundary(to, true));
196
216
  }
197
217
  async function searchArchiveBatches(ids, query, call, { signal, onProgress } = {}) {
@@ -212,7 +232,7 @@
212
232
  return { items, failures };
213
233
  }
214
234
  function classifySessionError(error) {
215
- const message = String(error?.message ?? error);
235
+ const message = errorMessage(error);
216
236
  const descriptions = {
217
237
  "repair-frame": ["\u65E7\u7248\u4FEE\u590D\u751F\u6210\u7684\u538B\u7F29\u683C\u5F0F\u4E0D\u7B26\u5408\u5BBF\u4E3B\u8981\u6C42", "\u91CD\u65B0\u8BCA\u65AD\u53EF\u7EA0\u6B63\u538B\u7F29\u5E27\u683C\u5F0F\uFF0C\u539F\u59CB\u65E5\u5FD7\u4FDD\u6301\u4E0D\u53D8\u3002"],
218
238
  "legacy-source": ["\u65E7\u7248\u6D88\u606F\u6765\u6E90\u4E0D\u53D7\u65B0\u7248 DSH \u652F\u6301", "\u8FD0\u884C\u8BCA\u65AD\uFF0C\u68C0\u67E5\u662F\u5426\u4E3A\u53EF\u8F6C\u6362\u7684\u65E7\u81EA\u52A8\u5316\u6765\u6E90\u3002"],
@@ -229,22 +249,25 @@
229
249
  ["permission", /EACCES|EPERM|permission/i],
230
250
  ["corrupt", /corrupt|JSON|incomplete|truncat|损坏/i]
231
251
  ];
232
- const explicit = Object.hasOwn(codes, error?.code) ? codes[error.code] : error?.code;
252
+ const rawCode = errorCode(error);
253
+ const explicit = typeof rawCode === "string" ? codes[rawCode] ?? rawCode : "";
233
254
  const code = Object.hasOwn(descriptions, explicit) ? explicit : patterns.find(([, pattern]) => pattern.test(message))?.[0] ?? "unknown";
234
255
  const [reason, advice] = descriptions[code];
235
256
  return { code, reason, advice };
236
257
  }
237
- var repairInputSchema = { parse(value) {
258
+ var repairInputSchema = { parse(input) {
259
+ const value = record(input);
238
260
  const sessionId = id(value?.sessionId);
239
- if (value?.token !== void 0 && !/^[a-f0-9]{64}$/.test(value.token)) throw new TypeError("\u4FEE\u590D\u51ED\u636E\u65E0\u6548");
261
+ if (value?.token !== void 0 && (typeof value.token !== "string" || !/^[a-f0-9]{64}$/.test(value.token))) throw new TypeError("\u4FEE\u590D\u51ED\u636E\u65E0\u6548");
240
262
  return { sessionId, ...value.token !== void 0 ? { token: value.token } : {} };
241
263
  } };
242
- var repairResultSchema = { parse(value) {
264
+ var repairResultSchema = { parse(input) {
265
+ const value = record(input);
243
266
  if (!value || typeof value.repairable !== "boolean" || typeof value.repaired !== "boolean") throw new TypeError("\u8BCA\u65AD\u7ED3\u679C\u65E0\u6548");
244
267
  return { ...value.code !== void 0 ? { code: boundedString(value.code, 64) } : {}, sessionId: id(value.sessionId), repairable: value.repairable, repaired: value.repaired, reason: boundedString(value.reason, 1e3), advice: boundedString(value.advice, 1e3), token: boundedString(value.token ?? "", 64), count: sequence(value.count ?? 0) };
245
268
  } };
246
269
 
247
- // src/session-health-ui.js
270
+ // src/session-health-ui.ts
248
271
  var defaultT = (key, args = {}) => Object.entries(args).reduce((text, [name, value]) => text.replaceAll("{" + name + "}", String(value)), healthZh[key] ?? key);
249
272
  var sessionHealthCss = `
250
273
  .dsham_health{margin:0 0 16px;font-size:13px;line-height:1.6;color:var(--dsw-alias-label-primary);--health-accent:var(--dsw-alias-state-business-primary,#507fe5);--health-warning:var(--dsw-alias-state-warn-label)}
@@ -280,14 +303,14 @@
280
303
  setBusyId(row.sessionId);
281
304
  setNotice("");
282
305
  try {
283
- const result = await (repair ? repairSession({ sessionId: row.sessionId, token: results[row.sessionId].token }) : diagnoseSession({ sessionId: row.sessionId }));
306
+ const result = await (repair && repairSession ? repairSession({ sessionId: row.sessionId, token: results[row.sessionId].token }) : diagnoseSession({ sessionId: row.sessionId }));
284
307
  setResults((previous) => ({ ...previous, [row.sessionId]: result }));
285
308
  if (result.repaired) {
286
309
  setNotice(true);
287
310
  retry();
288
311
  }
289
312
  } catch (error) {
290
- setResults((previous) => ({ ...previous, [row.sessionId]: { repairable: false, code: "failed", reason: "", advice: String(error?.message ?? error).slice(0, 1e3) } }));
313
+ setResults((previous) => ({ ...previous, [row.sessionId]: { repairable: false, code: "failed", reason: "", advice: errorMessage(error).slice(0, 1e3) } }));
291
314
  } finally {
292
315
  setBusyId("");
293
316
  }
@@ -363,10 +386,10 @@
363
386
  };
364
387
  }
365
388
 
366
- // src/archive-discovery-ui.js
389
+ // src/archive-discovery-ui.ts
367
390
  function createDiscoveryTools(React) {
368
391
  const h = React.createElement;
369
- function HighlightedText({ text, query }) {
392
+ function HighlightedText({ text, query = "" }) {
370
393
  const match = findTextRange(text, query);
371
394
  return !match ? text : h(React.Fragment, null, text.slice(0, match.start), h("mark", null, text.slice(match.start, match.end)), text.slice(match.end));
372
395
  }
@@ -385,7 +408,7 @@
385
408
  } }).then((result) => {
386
409
  if (!controller.signal.aborted) setState({ key, status: "ready", done: ids.length, total: ids.length, ...result });
387
410
  }).catch((error) => {
388
- if (!controller.signal.aborted) setState((previous) => ({ ...previous, key, status: "error", error: String(error?.message ?? error) }));
411
+ if (!controller.signal.aborted) setState((previous) => ({ ...previous, key, status: "error", error: errorMessage(error) }));
389
412
  });
390
413
  }, 350);
391
414
  return () => {
@@ -414,7 +437,7 @@
414
437
  const found = new Map(result.items.map((row) => [row.sessionId, row]));
415
438
  items2.push(...batch.map((sessionId) => found.get(sessionId) ?? { sessionId, turnCount: null, path: null, error: "", errorKey: "details.notReturned" }));
416
439
  } catch (error) {
417
- items2.push(...batch.map((sessionId) => ({ sessionId, turnCount: null, path: null, error: String(error?.message ?? error) })));
440
+ items2.push(...batch.map((sessionId) => ({ sessionId, turnCount: null, path: null, error: errorMessage(error) })));
418
441
  }
419
442
  if (active) setState({ key, items: [...items2], pending: start + 20 < ids.length });
420
443
  }
@@ -456,7 +479,7 @@
456
479
  Promise.resolve().then(() => call({ sessionId: target.session.id, query: target.query })).then((value) => {
457
480
  if (active) setState({ key, status: "ready", value });
458
481
  }).catch((error) => {
459
- if (active) setState({ key, status: "error", error: String(error?.message ?? error) });
482
+ if (active) setState({ key, status: "error", error: errorMessage(error) });
460
483
  });
461
484
  return () => {
462
485
  active = false;
@@ -501,8 +524,8 @@
501
524
  h(
502
525
  "div",
503
526
  { className: "dsham_datePanel" },
504
- h("label", null, t("discovery.from"), h("input", { type: "date", value: from, max: to || void 0, onChange: (event) => onFrom(event.target.value) })),
505
- h("label", null, t("discovery.to"), h("input", { type: "date", value: to, min: from || void 0, onChange: (event) => onTo(event.target.value) })),
527
+ h("label", null, t("discovery.from"), h("input", { type: "date", value: from, max: to || void 0, onChange: (event) => onFrom(event.currentTarget.value) })),
528
+ h("label", null, t("discovery.to"), h("input", { type: "date", value: to, min: from || void 0, onChange: (event) => onTo(event.currentTarget.value) })),
506
529
  invalid && h("p", { role: "alert" }, t("discovery.invalidDate")),
507
530
  h("button", { type: "button", className: "dsham_settingsAction", disabled: !active, onClick: onClear }, t("discovery.clearDate"))
508
531
  )
@@ -657,8 +680,9 @@
657
680
  "discovery.searchPlaceholder": "Search titles or content"
658
681
  };
659
682
 
660
- // src/archive-experience.js
683
+ // src/archive-experience.ts
661
684
  var ArchiveNavigationError = class extends Error {
685
+ code;
662
686
  constructor(code) {
663
687
  super(code);
664
688
  this.name = "ArchiveNavigationError";
@@ -666,18 +690,22 @@
666
690
  }
667
691
  };
668
692
  function formatArchiveNavigationError(error, t) {
669
- return error instanceof ArchiveNavigationError ? t(`archives.${error.code}`) : String(error?.message ?? error);
693
+ return error instanceof ArchiveNavigationError ? t(`archives.${error.code}`) : errorMessage(error);
670
694
  }
671
695
  function retainInfoSnapshot(sessions, id2) {
672
696
  if (typeof sessions?.retainInfo !== "function") return;
673
697
  const source = sessions.retainInfo(id2);
674
- return typeof source?.getSnapshot === "function" ? source.getSnapshot() : source;
698
+ const value = source && typeof source === "object" && "getSnapshot" in source && typeof source.getSnapshot === "function" ? source.getSnapshot() : source;
699
+ if (!value || typeof value !== "object" || !("retainedBy" in value)) return;
700
+ const retainedBy = value.retainedBy;
701
+ if (!retainedBy || typeof retainedBy !== "object" || !("mainView" in retainedBy) || typeof retainedBy.mainView !== "number") return;
702
+ return { retainedBy: { mainView: retainedBy.mainView } };
675
703
  }
676
704
  function mainViewSessionId(list) {
677
705
  const byId = list?.byId;
678
706
  if (byId === void 0) return;
679
707
  for (const session of Object.values(byId)) {
680
- if ((session?.retainedBy?.mainView ?? 0) > 0) return session.id;
708
+ if (session && (session.retainedBy?.mainView ?? 0) > 0) return session.id;
681
709
  }
682
710
  }
683
711
  function currentSessionId(list) {
@@ -706,10 +734,10 @@
706
734
  const wrapped = function(...args) {
707
735
  if (allowed !== void 0 && viewing(allowed) && workspaces.list.getSnapshot().archivedSessionIds.includes(allowed)) return false;
708
736
  allowed = void 0;
709
- return original.apply(this, args);
737
+ return original?.apply(this, args);
710
738
  };
711
739
  const ownsWrapper = () => navigation && Object.getOwnPropertyDescriptor(navigation, "clearArchivedCurrent")?.value === wrapped;
712
- if (typeof original === "function") {
740
+ if (navigation && typeof original === "function") {
713
741
  try {
714
742
  navigation.clearArchivedCurrent = wrapped;
715
743
  if (!ownsWrapper()) throw new Error("\u5BFC\u822A\u65B9\u6CD5\u672A\u63A5\u7EB3\u5F52\u6863\u9002\u914D");
@@ -748,12 +776,12 @@
748
776
  if (!navigation || Object.getOwnPropertyDescriptor(navigation, "clearArchivedCurrent")?.value !== wrapped) return;
749
777
  if (descriptor) Object.defineProperty(navigation, "clearArchivedCurrent", descriptor);
750
778
  else delete navigation.clearArchivedCurrent;
751
- original.call(navigation);
779
+ original?.call(navigation);
752
780
  }
753
781
  };
754
782
  }
755
783
 
756
- // src/directory-flow-slot.js
784
+ // src/directory-flow-slot.ts
757
785
  function mirrorDirectoryFlow(ctx, target) {
758
786
  const source = "sidebar.workspaces.directoryFlow";
759
787
  return ctx.slots.inject(target, () => ctx.effect(() => {
@@ -818,7 +846,7 @@
818
846
  }, "dsh-archive-manager: official directory flow"));
819
847
  }
820
848
 
821
- // src/plugin-update-ui.js
849
+ // src/plugin-update-ui.ts
822
850
  var UPDATE_HEADER = "x-michengai-plugin-update";
823
851
  var STYLE_ID = "michengai-plugin-update-ui";
824
852
  var CSS = `
@@ -903,7 +931,7 @@
903
931
  ...signalOption
904
932
  });
905
933
  const value = await response.json();
906
- if (!response.ok || !validPayload(value)) throw new Error(typeof value.error === "string" ? value.error : strings().failed);
934
+ if (!response.ok || !validPayload(value)) throw new Error(value && typeof value === "object" && "error" in value && typeof value.error === "string" ? value.error : strings().failed);
907
935
  return value;
908
936
  }
909
937
  function manualPluginUpdateCommand(profileName, packageName, version) {
@@ -991,22 +1019,27 @@
991
1019
  dialog.setAttribute("role", "dialog");
992
1020
  dialog.setAttribute("aria-modal", "true");
993
1021
  dialog.innerHTML = `<header class="mpi-head"><h2></h2><button type="button" class="mpi-dialog-close" data-action="close"></button></header><p class="mpi-intro"></p><dl class="mpi-meta"><dt></dt><dd data-role="current"></dd><dt></dt><dd data-role="latest"></dd><dt></dt><dd data-role="profile"></dd></dl><div class="mpi-status" role="status"></div><div class="mpi-progress" hidden></div><section class="mpi-manual"><h3></h3><p></p><div class="mpi-command"><code></code><button type="button" class="mpi-action" data-action="copy"></button></div></section><footer class="mpi-actions"><div class="mpi-actions-group"><button type="button" class="mpi-action" data-action="check"></button><button type="button" class="mpi-action mpi-primary" data-action="update"></button></div></footer>`;
1022
+ const required = (selector) => {
1023
+ const element = dialog.querySelector(selector);
1024
+ if (!element) throw new Error(`\u66F4\u65B0\u5F39\u7A97\u7F3A\u5C11\u8282\u70B9\uFF1A${selector}`);
1025
+ return element;
1026
+ };
994
1027
  const name = text === EN ? options.enName : options.zhName;
995
- dialog.querySelector("h2").textContent = `${name} ${text.update}`;
996
- dialog.querySelector(".mpi-intro").textContent = text.intro;
1028
+ required("h2").textContent = `${name} ${text.update}`;
1029
+ required(".mpi-intro").textContent = text.intro;
997
1030
  const terms = dialog.querySelectorAll("dt");
998
1031
  terms[0].textContent = text.current;
999
1032
  terms[1].textContent = text.latestLabel;
1000
1033
  terms[2].textContent = text.profile;
1001
- dialog.querySelector(".mpi-manual h3").textContent = text.manual;
1002
- dialog.querySelector(".mpi-manual p").textContent = text.manualHint;
1003
- const status = dialog.querySelector(".mpi-status");
1004
- const progress = dialog.querySelector(".mpi-progress");
1005
- const command = dialog.querySelector(".mpi-command code");
1006
- const close = dialog.querySelector("[data-action=close]");
1007
- const check = dialog.querySelector("[data-action=check]");
1008
- const update = dialog.querySelector("[data-action=update]");
1009
- const copy = dialog.querySelector("[data-action=copy]");
1034
+ required(".mpi-manual h3").textContent = text.manual;
1035
+ required(".mpi-manual p").textContent = text.manualHint;
1036
+ const status = required(".mpi-status");
1037
+ const progress = required(".mpi-progress");
1038
+ const command = required(".mpi-command code");
1039
+ const close = required("[data-action=close]");
1040
+ const check = required("[data-action=check]");
1041
+ const update = required("[data-action=update]");
1042
+ const copy = required("[data-action=copy]");
1010
1043
  setButtonContent(close, text.close, "close");
1011
1044
  close.querySelector("[data-mpi-label]")?.remove();
1012
1045
  close.setAttribute("aria-label", text.close);
@@ -1027,9 +1060,9 @@
1027
1060
  progress.hidden = !value;
1028
1061
  };
1029
1062
  const render = () => {
1030
- dialog.querySelector("[data-role=current]").textContent = payload === void 0 ? text.unknown : `v${payload.currentVersion}`;
1031
- dialog.querySelector("[data-role=latest]").textContent = payload?.latestVersion === void 0 ? text.unknown : `v${payload.latestVersion}`;
1032
- dialog.querySelector("[data-role=profile]").textContent = payload?.profileName ?? text.unknown;
1063
+ required("[data-role=current]").textContent = payload === void 0 ? text.unknown : `v${payload.currentVersion}`;
1064
+ required("[data-role=latest]").textContent = payload?.latestVersion === void 0 ? text.unknown : `v${payload.latestVersion}`;
1065
+ required("[data-role=profile]").textContent = payload?.profileName ?? text.unknown;
1033
1066
  command.textContent = manualPluginUpdateCommand(payload?.profileName ?? "", options.packageName, payload?.latestVersion ?? "latest");
1034
1067
  update.disabled = busy || payload?.canAutoUpdate !== true || payload.updateAvailable !== true;
1035
1068
  if (payload === void 0) setMessage(text.checking);
@@ -1117,19 +1150,21 @@
1117
1150
  };
1118
1151
  }
1119
1152
 
1120
- // src/archive-organizer.js
1153
+ // src/archive-organizer.ts
1121
1154
  function checkedId(value) {
1122
1155
  if (typeof value !== "string" || value.length === 0 || value.length > 1024) throw new TypeError("\u4F1A\u8BDD ID \u957F\u5EA6\u987B\u4E3A 1\uFF5E1024 \u4E2A\u5B57\u7B26");
1123
1156
  return value;
1124
1157
  }
1125
1158
  var favoriteInputSchema = {
1126
- parse(value) {
1159
+ parse(input) {
1160
+ const value = record(input);
1127
1161
  if (!value || typeof value !== "object" || typeof value.favorite !== "boolean") throw new TypeError("\u6536\u85CF\u72B6\u6001\u5FC5\u987B\u4E3A\u5E03\u5C14\u503C");
1128
1162
  return { sessionId: checkedId(value.sessionId), favorite: value.favorite };
1129
1163
  }
1130
1164
  };
1131
1165
  var favoriteStateSchema = {
1132
- parse(value) {
1166
+ parse(input) {
1167
+ const value = record(input);
1133
1168
  if (!value || !Array.isArray(value.favoriteSessionIds) || value.favoriteSessionIds.length > 1e5) throw new TypeError("\u6536\u85CF\u96C6\u5408\u65E0\u6548");
1134
1169
  return { favoriteSessionIds: [...new Set(value.favoriteSessionIds.map(checkedId))] };
1135
1170
  },
@@ -1156,9 +1191,9 @@
1156
1191
  }
1157
1192
  function idleArchiveCandidate(session, { days, now = Date.now(), favorites = /* @__PURE__ */ new Set(), currentId, pending = /* @__PURE__ */ new Map() }) {
1158
1193
  if (!session || !Number.isInteger(days) || days < 1 || days > 36500) return false;
1159
- if (favorites.has(session.id) || session.id === currentId || session.retainedBy?.mainView > 0) return false;
1160
- if (session.running || session.runningSubagentCount > 0 || session.pendingInteraction != null || pending.has(session.id)) return false;
1161
- const updated = typeof session.updatedAt === "number" ? session.updatedAt : Date.parse(session.updatedAt);
1194
+ if (favorites.has(session.id) || session.id === currentId || (session.retainedBy?.mainView ?? 0) > 0) return false;
1195
+ if (session.running || (session.runningSubagentCount ?? 0) > 0 || session.pendingInteraction != null || pending.has(session.id)) return false;
1196
+ const updated = typeof session.updatedAt === "number" ? session.updatedAt : Date.parse(session.updatedAt ?? "");
1162
1197
  return Number.isFinite(updated) && updated <= now - days * 864e5;
1163
1198
  }
1164
1199
  async function runSessionBatch(ids, operate, { onProgress, refresh } = {}) {
@@ -1216,7 +1251,7 @@
1216
1251
  };
1217
1252
  }
1218
1253
 
1219
- // src/archive-organizer-ui.js
1254
+ // src/archive-organizer-ui.ts
1220
1255
  function createOrganizerPanel(React) {
1221
1256
  const h = React.createElement;
1222
1257
  return function OrganizerPanel({ t, archived, busy, ready, days, onDays, count, onPreview, progress, result, onRetry, undoCount, onUndo, onReload }) {
@@ -1234,7 +1269,7 @@
1234
1269
  !archived && h(
1235
1270
  React.Fragment,
1236
1271
  null,
1237
- h("label", null, t("organizer.idleDays"), h("input", { type: "number", min: 1, max: 36500, step: 1, value: days, disabled: busy, onChange: (event) => onDays(event.target.value), "aria-label": t("organizer.idleDays") })),
1272
+ h("label", null, t("organizer.idleDays"), h("input", { type: "number", min: 1, max: 36500, step: 1, value: days, disabled: busy, onChange: (event) => onDays(event.currentTarget.value), "aria-label": t("organizer.idleDays") })),
1238
1273
  h("button", { type: "button", className: "dsham_settingsAction", disabled: busy || !ready || count === 0, onClick: onPreview }, t("organizer.preview", { n: count }))
1239
1274
  )
1240
1275
  ),
@@ -1321,7 +1356,7 @@
1321
1356
  "organizer.manualConfirm": "Only checked sessions below will be archived. You can undo this batch afterward."
1322
1357
  };
1323
1358
 
1324
- // src/client.js
1359
+ // src/client.ts
1325
1360
  window.__ModuleLoader__.load({
1326
1361
  id: "@michengai/dsh-archive-manager",
1327
1362
  factory: (require2) => {
@@ -1375,7 +1410,8 @@
1375
1410
  }
1376
1411
  };
1377
1412
  const archivedSetSchema = {
1378
- parse(value) {
1413
+ parse(input) {
1414
+ const value = record(input);
1379
1415
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new TypeError("result must be an object");
1380
1416
  const ids = value.archivedSessionIds;
1381
1417
  if (!Array.isArray(ids) || ids.some((id2) => typeof id2 !== "string")) throw new TypeError("archivedSessionIds must be a string array");
@@ -1383,13 +1419,15 @@
1383
1419
  }
1384
1420
  };
1385
1421
  const deletedSchema = {
1386
- parse(value) {
1422
+ parse(input) {
1423
+ const value = record(input);
1387
1424
  if (typeof value !== "object" || value === null || Array.isArray(value) || value.deleted !== true) throw new TypeError("deleted must be true");
1388
1425
  return value;
1389
1426
  }
1390
1427
  };
1391
1428
  const archivedBatchTargetSchema = {
1392
- parse(value) {
1429
+ parse(input) {
1430
+ const value = record(input);
1393
1431
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new TypeError("target must be an object");
1394
1432
  if (value.scope === "all" || value.scope === "ungrouped") return value;
1395
1433
  if (value.scope === "workspace" && typeof value.workspaceId === "string" && value.workspaceId.length > 0) return value;
@@ -1398,7 +1436,8 @@
1398
1436
  }
1399
1437
  };
1400
1438
  const deletedBatchSchema = {
1401
- parse(value) {
1439
+ parse(input) {
1440
+ const value = record(input);
1402
1441
  if (typeof value !== "object" || value === null || Array.isArray(value)) throw new TypeError("result must be an object");
1403
1442
  for (const key of ["requestedSessionIds", "deletedSessionIds", "skippedSessionIds"]) {
1404
1443
  if (!Array.isArray(value[key]) || value[key].some((id2) => typeof id2 !== "string")) throw new TypeError(`${key} must be a string array`);
@@ -1408,7 +1447,8 @@
1408
1447
  }
1409
1448
  };
1410
1449
  const archivedSessionMetadataSchema = {
1411
- parse(value) {
1450
+ parse(input) {
1451
+ const value = record(input);
1412
1452
  if (typeof value !== "object" || value === null || Array.isArray(value) || !Array.isArray(value.items)) throw new TypeError("result.items must be an array");
1413
1453
  if (value.items.some((item) => typeof item !== "object" || item === null || typeof item.sessionId !== "string" || typeof item.createdAt !== "number" || !Number.isFinite(item.createdAt))) throw new TypeError("items must contain sessionId/createdAt objects");
1414
1454
  if (value.repairedSessionIds !== void 0 && (!Array.isArray(value.repairedSessionIds) || value.repairedSessionIds.some((id2) => typeof id2 !== "string"))) throw new TypeError("repairedSessionIds must be a string array");
@@ -1641,7 +1681,7 @@
1641
1681
  setFavoritesReady(true);
1642
1682
  } catch (reason) {
1643
1683
  setFavoritesReady(false);
1644
- setError(String(reason?.message ?? reason));
1684
+ setError(errorMessage(reason));
1645
1685
  }
1646
1686
  };
1647
1687
  (0, react.useEffect)(() => {
@@ -1652,7 +1692,7 @@
1652
1692
  setFavoritesReady(true);
1653
1693
  }
1654
1694
  }).catch((reason) => {
1655
- if (active) setError(String(reason?.message ?? reason));
1695
+ if (active) setError(errorMessage(reason));
1656
1696
  });
1657
1697
  return () => {
1658
1698
  active = false;
@@ -1667,7 +1707,7 @@
1667
1707
  const value = await setSessionFavorite({ sessionId, favorite: !favoriteSet.has(sessionId) });
1668
1708
  setFavoriteIds(value.favoriteSessionIds);
1669
1709
  } catch (reason) {
1670
- setError(String(reason?.message ?? reason));
1710
+ setError(errorMessage(reason));
1671
1711
  } finally {
1672
1712
  favoriteLock.current = false;
1673
1713
  setFavoriteBusy(false);
@@ -1691,7 +1731,7 @@
1691
1731
  if (kind === "delete") setFavoriteIds((previous) => previous.filter((id2) => !result.succeeded.includes(id2)));
1692
1732
  return result;
1693
1733
  } catch (reason) {
1694
- setError(String(reason?.message ?? reason));
1734
+ setError(errorMessage(reason));
1695
1735
  } finally {
1696
1736
  batchLock.current = false;
1697
1737
  setBusy(false);
@@ -1807,7 +1847,7 @@
1807
1847
  await copySessionText(text);
1808
1848
  if (navigationActive.current) setNotice(t("details.copied"));
1809
1849
  } catch (reason) {
1810
- if (navigationActive.current) setError(reason?.code?.startsWith("copy.") ? t(reason.code) : String(reason?.message ?? reason));
1850
+ if (navigationActive.current) setError(typeof errorCode(reason) === "string" && String(errorCode(reason)).startsWith("copy.") ? t(String(errorCode(reason))) : errorMessage(reason));
1811
1851
  }
1812
1852
  };
1813
1853
  const sortedGroups = (0, react.useMemo)(() => sortArchivedGroups(groups, sortBy, createdAtById, t, details.byId), [groups, sortBy, createdAtById, t, details.byId]);
@@ -1897,7 +1937,7 @@
1897
1937
  if (event.key !== "Escape") return;
1898
1938
  event.preventDefault();
1899
1939
  event.stopPropagation();
1900
- if (typeof event.stopImmediatePropagation === "function") event.stopImmediatePropagation();
1940
+ if ("stopImmediatePropagation" in event && typeof event.stopImmediatePropagation === "function") event.stopImmediatePropagation();
1901
1941
  if (!busy) setDeleteTarget(null);
1902
1942
  };
1903
1943
  window.addEventListener("keydown", onKeyDown, true);
@@ -1935,8 +1975,8 @@
1935
1975
  }
1936
1976
  };
1937
1977
  const batchScope = deleteTarget?.kind === "batch" ? deleteTarget.target.scope : null;
1938
- const deleteDialogTitle = batchScope === "ungrouped" ? t("archives.deleteUngroupedTitle") : batchScope === "workspace" ? t("archives.deleteProjectTitle", { name: deleteTarget.title }) : batchScope === "sessions" ? t("archives.deleteSelectedTitle") : t("deleteSession.title");
1939
- const deleteDialogDescription = deleteTarget === null ? void 0 : batchScope === "ungrouped" ? t("archives.deleteUngroupedDesc", { n: deleteTarget.count }) : batchScope === "workspace" ? t("archives.deleteProjectDesc", { name: deleteTarget.title, n: deleteTarget.count }) : batchScope === "sessions" ? t("archives.deleteSelectedDesc", { n: deleteTarget.count }) : t("deleteSession.desc", { name: displayTitle(deleteTarget.session, t) });
1978
+ const deleteDialogTitle = batchScope === "ungrouped" ? t("archives.deleteUngroupedTitle") : batchScope === "workspace" ? t("archives.deleteProjectTitle", { name: deleteTarget?.kind === "batch" ? deleteTarget.title : "" }) : batchScope === "sessions" ? t("archives.deleteSelectedTitle") : t("deleteSession.title");
1979
+ const deleteDialogDescription = deleteTarget === null ? void 0 : batchScope === "ungrouped" ? t("archives.deleteUngroupedDesc", { n: deleteTarget.kind === "batch" ? deleteTarget.count : 0 }) : batchScope === "workspace" ? t("archives.deleteProjectDesc", { name: deleteTarget?.kind === "batch" ? deleteTarget.title : "", n: deleteTarget.kind === "batch" ? deleteTarget.count : 0 }) : batchScope === "sessions" ? t("archives.deleteSelectedDesc", { n: deleteTarget.kind === "batch" ? deleteTarget.count : 0 }) : t("deleteSession.desc", { name: displayTitle(deleteTarget.kind === "session" ? deleteTarget.session : {}, t) });
1940
1980
  const deleteConfirmLabel = batchScope === "ungrouped" ? t("archives.deleteUngroupedConfirm") : batchScope === "workspace" ? t("archives.deleteProjectConfirm") : batchScope === "sessions" ? t("archives.deleteSelectedConfirm") : t("deleteSession.title");
1941
1981
  return (0, react_jsx_runtime.jsxs)("section", {
1942
1982
  className: "dsham_settings",
@@ -1965,7 +2005,7 @@
1965
2005
  event.preventDefault();
1966
2006
  const next = event.key === "Home" ? "archived" : event.key === "End" ? "unarchived" : isArchived ? "unarchived" : "archived";
1967
2007
  switchTab(next);
1968
- event.currentTarget.parentElement.querySelector("#dsham-tab-" + next)?.focus();
2008
+ event.currentTarget.parentElement?.querySelector("#dsham-tab-" + next)?.focus();
1969
2009
  }
1970
2010
  },
1971
2011
  children: t("archives.tab." + tab)
@@ -1979,7 +2019,7 @@
1979
2019
  setDateFrom("");
1980
2020
  setDateTo("");
1981
2021
  } })]
1982
- }), (0, react_jsx_runtime.jsx)(ArchiveProjectSelect, { id: "dsham-sort-filter", value: sortBy, options: [{ value: "updated", label: t("archives.sortUpdated") }, { value: "created", label: t("archives.sortCreated") }, { value: "alphabetical", label: t("archives.sortAlphabetical") }, ...sessionDetails ? [{ value: "turnsDesc", label: t("details.more") }, { value: "turnsAsc", label: t("details.less") }] : []], onChange: setSortBy, "aria-label": t("archives.sortBy") }), (0, react_jsx_runtime.jsx)(ArchiveProjectSelect, { id: "dsham-project-filter", value: project, options: [{ value: "all", label: t("archives.allProjects") }, ...sortedGroups.map((group) => ({ value: group.key, label: group.title }))], onChange: setProject, "aria-label": t("archives.projectFilter") }), setSessionFavorite && (0, react_jsx_runtime.jsx)(ArchiveProjectSelect, { id: "dsham-favorite-filter", value: favoritesOnly ? "favorites" : "all", disabled: busy || favoriteBusy || !favoritesReady, options: [{ value: "all", label: t("organizer.allSessions") }, { value: "favorites", label: t("organizer.favoritesOnly") }], onChange: (value) => setFavoritesOnly(value === "favorites"), "aria-label": t("organizer.favoriteFilter") })]
2022
+ }), (0, react_jsx_runtime.jsx)(ArchiveProjectSelect, { id: "dsham-sort-filter", value: sortBy, options: [{ value: "updated", label: t("archives.sortUpdated") }, { value: "created", label: t("archives.sortCreated") }, { value: "alphabetical", label: t("archives.sortAlphabetical") }, ...typeof sessionDetails === "function" ? [{ value: "turnsDesc", label: t("details.more") }, { value: "turnsAsc", label: t("details.less") }] : []], onChange: setSortBy, "aria-label": t("archives.sortBy") }), (0, react_jsx_runtime.jsx)(ArchiveProjectSelect, { id: "dsham-project-filter", value: project, options: [{ value: "all", label: t("archives.allProjects") }, ...sortedGroups.map((group) => ({ value: group.key, label: group.title }))], onChange: setProject, "aria-label": t("archives.projectFilter") }), typeof setSessionFavorite === "function" && (0, react_jsx_runtime.jsx)(ArchiveProjectSelect, { id: "dsham-favorite-filter", value: favoritesOnly ? "favorites" : "all", disabled: busy || favoriteBusy || !favoritesReady, options: [{ value: "all", label: t("organizer.allSessions") }, { value: "favorites", label: t("organizer.favoritesOnly") }], onChange: (value) => setFavoritesOnly(value === "favorites"), "aria-label": t("organizer.favoriteFilter") })]
1983
2023
  }), react.createElement("style", null, discoveryCss), react.createElement(SearchStatus, { state: contentSearch, t }), react.createElement(SessionHealthPanel, { key: archiveTab, t, isArchived, items: details.items, sessions: groups.flatMap((group) => group.sessions), diagnoseSession, repairSession, retry: details.retry, pending: details.pending }), organizeBatch && (0, react_jsx_runtime.jsx)(OrganizerPanel, {
1984
2024
  t,
1985
2025
  archived: isArchived,
@@ -2042,13 +2082,13 @@
2042
2082
  (0, react_jsx_runtime.jsx)(ArchiveSelectionCheckbox, { checked: selectedSessionIdSet.has(session.id), disabled: busy, label: t("archives.selectSession", { name: displayTitle(session, t) }), onChange: (event) => toggleSessionSelection(session.id, event.target.checked) }),
2043
2083
  (0, react_jsx_runtime.jsxs)("div", { className: "dsham_settingsContent", children: [
2044
2084
  (0, react_jsx_runtime.jsx)("button", { type: "button", className: "dsham_settingsTitleLink", title: displayTitle(session, t), "aria-label": t("archives.openSession") + t("common.separator") + displayTitle(session, t), disabled: busy || unarchivingSessionIds.has(session.id), onClick: () => viewConversation(session), children: displayTitle(session, t) }),
2045
- (0, react_jsx_runtime.jsx)("div", { className: "dsham_settingsMeta", children: [archiveTimeLabel(session.updatedAt, t), sessionDetails && react.createElement("span", { key: "turns", title: details.byId[session.id]?.error || t("details.hint") }, " \xB7 ", t(typeof details.byId[session.id]?.turnCount === "number" ? "details.turns" : details.byId[session.id] ? "details.unknown" : "details.pending", { n: details.byId[session.id]?.turnCount }))] }),
2046
- contentMatches.has(session.id) && react.createElement("button", { type: "button", className: "dsham_settingsSnippet", disabled: busy, title: t(isArchived ? "discovery.preview" : "archives.openSession"), onClick: () => isArchived ? preview.open(session, query) : viewConversation(session) }, react.createElement(HighlightedText, { text: contentMatches.get(session.id).snippet, query }))
2085
+ (0, react_jsx_runtime.jsx)("div", { className: "dsham_settingsMeta", children: [archiveTimeLabel(session.updatedAt, t), typeof sessionDetails === "function" && react.createElement("span", { key: "turns", title: details.byId[session.id]?.error || t("details.hint") }, " \xB7 ", t(typeof details.byId[session.id]?.turnCount === "number" ? "details.turns" : details.byId[session.id] ? "details.unknown" : "details.pending", { n: details.byId[session.id]?.turnCount }))] }),
2086
+ contentMatches.has(session.id) && react.createElement("button", { type: "button", className: "dsham_settingsSnippet", disabled: busy, title: t(isArchived ? "discovery.preview" : "archives.openSession"), onClick: () => isArchived ? preview.open(session, query) : viewConversation(session) }, react.createElement(HighlightedText, { text: contentMatches.get(session.id)?.snippet ?? "", query }))
2047
2087
  ] }),
2048
2088
  (0, react_jsx_runtime.jsxs)("div", { className: "dsham_settingsActions", children: [
2049
- setSessionFavorite && (0, react_jsx_runtime.jsx)("button", { type: "button", className: "dsham_favorite", title: t(favoriteSet.has(session.id) ? "organizer.unfavorite" : "organizer.favorite"), "aria-pressed": favoriteSet.has(session.id), "aria-label": t(favoriteSet.has(session.id) ? "organizer.unfavorite" : "organizer.favorite") + t("common.separator") + displayTitle(session, t), disabled: busy || favoriteBusy || !favoritesReady, onClick: () => toggleFavorite(session.id), children: (0, react_jsx_runtime.jsx)("span", { "aria-hidden": true, children: favoriteSet.has(session.id) ? "\u2605" : "\u2606" }) }),
2089
+ typeof setSessionFavorite === "function" && (0, react_jsx_runtime.jsx)("button", { type: "button", className: "dsham_favorite", title: t(favoriteSet.has(session.id) ? "organizer.unfavorite" : "organizer.favorite"), "aria-pressed": favoriteSet.has(session.id), "aria-label": t(favoriteSet.has(session.id) ? "organizer.unfavorite" : "organizer.favorite") + t("common.separator") + displayTitle(session, t), disabled: busy || favoriteBusy || !favoritesReady, onClick: () => toggleFavorite(session.id), children: (0, react_jsx_runtime.jsx)("span", { "aria-hidden": true, children: favoriteSet.has(session.id) ? "\u2605" : "\u2606" }) }),
2050
2090
  (0, react_jsx_runtime.jsx)("button", { type: "button", className: "dsham_restoreIcon", title: t(isArchived ? "archives.restore" : "archives.archiveSelected"), "aria-label": t(isArchived ? "archives.restore" : "archives.archiveSelected"), disabled: busy || unarchivingSessionIds.has(session.id), onClick: () => isArchived ? onUnarchive(session.id) : requestArchive([session.id]), children: (0, react_jsx_runtime.jsx)(isArchived ? _deepseek_ai_dsh_client_ui_primitives.IconRefreshOutline16 : _deepseek_ai_dsh_client_ui_primitives.IconArchiveOutline20, { size: 16 }) }),
2051
- (isArchived || sessionDetails) && (0, react_jsx_runtime.jsx)(ArchivedSessionMenu, { busy: busy || unarchivingSessionIds.has(session.id), t, title: displayTitle(session, t), onCopyId: () => copyDetail(session, "id"), onCopyPath: sessionDetails ? () => copyDetail(session, "path") : void 0, onPreview: isArchived && previewArchivedSession ? () => preview.open(session, query) : void 0, onRestoreOpen: isArchived ? () => viewConversation(session, true) : void 0, onDelete: isArchived ? () => setDeleteTarget({ kind: "session", session }) : void 0 })
2091
+ (isArchived || typeof sessionDetails === "function") && (0, react_jsx_runtime.jsx)(ArchivedSessionMenu, { busy: busy || unarchivingSessionIds.has(session.id), t, title: displayTitle(session, t), onCopyId: () => copyDetail(session, "id"), onCopyPath: typeof sessionDetails === "function" ? () => copyDetail(session, "path") : void 0, onPreview: isArchived && typeof previewArchivedSession === "function" ? () => preview.open(session, query) : void 0, onRestoreOpen: isArchived ? () => viewConversation(session, true) : void 0, onDelete: isArchived ? () => setDeleteTarget({ kind: "session", session }) : void 0 })
2052
2092
  ] })
2053
2093
  ]
2054
2094
  }, session.id))
@@ -2081,7 +2121,7 @@
2081
2121
  ] }),
2082
2122
  children: (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
2083
2123
  organizeBatch && (0, react_jsx_runtime.jsx)("p", { children: t(idleRequest ? "organizer.idleConfirm" : "organizer.manualConfirm") }),
2084
- organizeBatch && (0, react_jsx_runtime.jsx)("div", { className: "dsham_archivePreview", children: (archiveTarget ?? []).map((id2) => (0, react_jsx_runtime.jsxs)("label", { children: [(0, react_jsx_runtime.jsx)("input", { type: "checkbox", checked: true, disabled: busy, onChange: () => setArchiveTarget((current) => current.filter((value) => value !== id2)) }), displayTitle(sessions.byId[id2] ?? { id: id2 }, t)] }, id2)) }),
2124
+ organizeBatch && (0, react_jsx_runtime.jsx)("div", { className: "dsham_archivePreview", children: (archiveTarget ?? []).map((id2) => (0, react_jsx_runtime.jsxs)("label", { children: [(0, react_jsx_runtime.jsx)("input", { type: "checkbox", checked: true, disabled: busy, onChange: () => setArchiveTarget((current) => (current ?? []).filter((value) => value !== id2)) }), displayTitle(sessions.byId[id2] ?? { id: id2 }, t)] }, id2)) }),
2085
2125
  batchProgress && (0, react_jsx_runtime.jsxs)("div", { role: "status", children: [(0, react_jsx_runtime.jsx)("progress", { value: batchProgress.done, max: Math.max(1, batchProgress.total) }), t("organizer.progressCount", { done: batchProgress.done, total: batchProgress.total })] }),
2086
2126
  error !== null && (0, react_jsx_runtime.jsx)("div", { className: "dsham_settingsError", role: "alert", children: error })
2087
2127
  ] })
@@ -2105,7 +2145,7 @@
2105
2145
  } else for (f in e) e[f] && (n && (n += " "), n += f);
2106
2146
  return n;
2107
2147
  }
2108
- function clsx() {
2148
+ function clsx(..._values) {
2109
2149
  for (var e, t, f = 0, n = "", o = arguments.length; f < o; f++) (e = arguments[f]) && (t = r(e)) && (n && (n += " "), n += t);
2110
2150
  return n;
2111
2151
  }
@@ -2450,7 +2490,7 @@
2450
2490
  return unit === "now" ? t("time.now") : t("time.ago", { t: t(`time.${unit}`, { n }) });
2451
2491
  }
2452
2492
  function createdLabel(createdAt, t) {
2453
- const d = new Date(createdAt);
2493
+ const d = new Date(createdAt ?? NaN);
2454
2494
  const pad2 = (v) => String(v).padStart(2, "0");
2455
2495
  return t("hover.created", { time: `${t("date.ymd", {
2456
2496
  y: d.getFullYear(),
@@ -3198,7 +3238,7 @@
3198
3238
  const rect = e.currentTarget.getBoundingClientRect();
3199
3239
  return e.clientY < rect.top + rect.height / 2 ? "before" : "after";
3200
3240
  }
3201
- function SessionTree({ useSessions, useSessionPendingInteraction, useSessionStatus, preferSessionStatus, startSession, open, forkSession, workspaces, archivedSessionIds, showArchived, onRenameRequest, onArchiveRequest, onDeleteRequest, onSessionRename, onSessionArchive, onSessionUnarchive, onSessionDelete, insertWorkspaceBefore, insertSessionBefore, orderBy, groupExpansion, setGroupExpanded, sessionOrderByAccount, sessionUpdatedAtByAccount, syncSessionOrderAccount, setSessionOrder, t, revealSessionId, onSessionRevealed }) {
3241
+ function SessionTree({ useSessions, useSessionPendingInteraction, useSessionStatus, preferSessionStatus, startSession, open, forkSession, workspaces, archivedSessionIds, showArchived, onRenameRequest, onArchiveRequest, onDeleteRequest, onSessionRename, onSessionArchive, onSessionUnarchive, onSessionDelete, insertWorkspaceBefore, insertSessionBefore, orderBy, groupExpansion, setGroupExpanded, sessionOrderByAccount, sessionUpdatedAtByAccount, syncSessionOrderAccount, setSessionOrder, t, revealSessionId, onSessionRevealed, showArchivedToast }) {
3202
3242
  const list = useSessions((s) => s);
3203
3243
  const pendingInteractions = useSessionUiFacts(useSessionPendingInteraction, useSessionStatus, preferSessionStatus);
3204
3244
  const current = currentSessionId(list);
@@ -3439,9 +3479,7 @@
3439
3479
  onOpen: open,
3440
3480
  onRename: onSessionRename,
3441
3481
  onFork: (sessionId) => {
3442
- Promise.resolve(forkSession(sessionId)).catch((reason) => {
3443
- showArchivedToast(formatForkError(reason, t));
3444
- });
3482
+ void forkWithFeedback(sessionId, forkSession, showArchivedToast, t);
3445
3483
  },
3446
3484
  onArchive: onSessionArchive,
3447
3485
  onUnarchive: onSessionUnarchive,
@@ -3502,7 +3540,7 @@
3502
3540
  ]
3503
3541
  });
3504
3542
  }
3505
- function FlatList({ useSessions, useSessionPendingInteraction, useSessionStatus, preferSessionStatus, open, forkSession, onSessionRename, onSessionArchive, onSessionUnarchive, onSessionDelete, archivedSessionIds, showArchived, orderBy, sessionOrderByAccount, sessionUpdatedAtByAccount, syncSessionOrderAccount, setSessionOrder, t, revealSessionId, onSessionRevealed }) {
3543
+ function FlatList({ useSessions, useSessionPendingInteraction, useSessionStatus, preferSessionStatus, open, forkSession, onSessionRename, onSessionArchive, onSessionUnarchive, onSessionDelete, archivedSessionIds, showArchived, orderBy, sessionOrderByAccount, sessionUpdatedAtByAccount, syncSessionOrderAccount, setSessionOrder, t, revealSessionId, onSessionRevealed, showArchivedToast }) {
3506
3544
  const list = useSessions((s) => s);
3507
3545
  const pendingInteractions = useSessionUiFacts(useSessionPendingInteraction, useSessionStatus, preferSessionStatus);
3508
3546
  const current = currentSessionId(list);
@@ -3586,9 +3624,7 @@
3586
3624
  onOpen: open,
3587
3625
  onRename: onSessionRename,
3588
3626
  onFork: (sessionId) => {
3589
- Promise.resolve(forkSession(sessionId)).catch((reason) => {
3590
- showArchivedToast(formatForkError(reason, t));
3591
- });
3627
+ void forkWithFeedback(sessionId, forkSession, showArchivedToast, t);
3592
3628
  },
3593
3629
  onArchive: onSessionArchive,
3594
3630
  onUnarchive: onSessionUnarchive,
@@ -3731,7 +3767,7 @@
3731
3767
  };
3732
3768
  const [archivedToast, setArchivedToast] = (0, react.useState)(null);
3733
3769
  const archivedToastSeq = (0, react.useRef)(0);
3734
- const showArchivedToast2 = (text) => {
3770
+ const showArchivedToast = (text) => {
3735
3771
  archivedToastSeq.current += 1;
3736
3772
  setArchivedToast({
3737
3773
  text,
@@ -3740,7 +3776,7 @@
3740
3776
  };
3741
3777
  const guardedOpen = (sessionId) => {
3742
3778
  if (archivedSet.has(sessionId)) {
3743
- showArchivedToast2(t("archived.notOpenable"));
3779
+ showArchivedToast(t("archived.notOpenable"));
3744
3780
  return;
3745
3781
  }
3746
3782
  open(sessionId);
@@ -3906,7 +3942,7 @@
3906
3942
  };
3907
3943
  const onSessionArchive = (sessionId) => {
3908
3944
  archiveSession(sessionId).catch((reason) => {
3909
- showArchivedToast2(formatArchiveError(reason, t));
3945
+ showArchivedToast(formatArchiveError(reason, t));
3910
3946
  });
3911
3947
  };
3912
3948
  const [archiveWorkspaceTarget, setArchiveWorkspaceTarget] = (0, react.useState)(null);
@@ -3965,7 +4001,7 @@
3965
4001
  };
3966
4002
  const onSessionUnarchive = (sessionId) => {
3967
4003
  unarchiveSession(sessionId).catch((reason) => {
3968
- showArchivedToast2(formatUnarchiveError(reason, t));
4004
+ showArchivedToast(formatUnarchiveError(reason, t));
3969
4005
  });
3970
4006
  };
3971
4007
  const [deleteSessionTarget, setDeleteSessionTarget] = (0, react.useState)(null);
@@ -4159,6 +4195,7 @@
4159
4195
  open: guardedOpen,
4160
4196
  revealSessionId,
4161
4197
  onSessionRevealed: acknowledgeSessionReveal,
4198
+ showArchivedToast,
4162
4199
  forkSession,
4163
4200
  onSessionRename,
4164
4201
  onSessionArchive,
@@ -4182,6 +4219,7 @@
4182
4219
  preferSessionStatus,
4183
4220
  revealSessionId,
4184
4221
  onSessionRevealed: acknowledgeSessionReveal,
4222
+ showArchivedToast,
4185
4223
  onSessionRename,
4186
4224
  onSessionArchive,
4187
4225
  onSessionUnarchive,
@@ -4549,7 +4587,7 @@
4549
4587
  if (event.key === "Escape" || event.key === "Tab") {
4550
4588
  event.preventDefault();
4551
4589
  event.stopPropagation();
4552
- if (typeof event.stopImmediatePropagation === "function") event.stopImmediatePropagation();
4590
+ if ("stopImmediatePropagation" in event && typeof event.stopImmediatePropagation === "function") event.stopImmediatePropagation();
4553
4591
  setOpen(false);
4554
4592
  }
4555
4593
  },
@@ -4629,8 +4667,8 @@
4629
4667
  if (id2 === "copyId") return onCopyId?.();
4630
4668
  if (id2 === "copyPath") return onCopyPath?.();
4631
4669
  if (id2 === "preview") return onPreview?.();
4632
- if (id2 === "restoreOpen") return onRestoreOpen();
4633
- if (id2 === "delete") onDelete();
4670
+ if (id2 === "restoreOpen") return onRestoreOpen?.();
4671
+ if (id2 === "delete") onDelete?.();
4634
4672
  },
4635
4673
  anchor: (0, react_jsx_runtime.jsx)("button", { type: "button", className: "dsham_settingsGroupMenu", disabled: busy, title: t("archives.moreActions"), "aria-label": t("archives.moreActions") + t("common.separator") + title, "aria-haspopup": "menu", "aria-expanded": open, onClick: () => setOpen((value) => !value), children: (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutline16, {}) })
4636
4674
  });
@@ -4661,8 +4699,8 @@
4661
4699
  setOpen(false);
4662
4700
  if (busy) return;
4663
4701
  if (id2 === "archive") onArchive?.();
4664
- else if (id2 === "restore") onRestore();
4665
- else if (id2 === "delete") onDelete();
4702
+ else if (id2 === "restore") onRestore?.();
4703
+ else if (id2 === "delete") onDelete?.();
4666
4704
  },
4667
4705
  portal: true,
4668
4706
  anchor: (0, react_jsx_runtime.jsx)("button", {
@@ -4740,7 +4778,7 @@
4740
4778
  for (const id2 of archivedSessionIds) {
4741
4779
  const session = byId[id2];
4742
4780
  if (session === void 0 || session.origin === "subagent") continue;
4743
- const group = byWorkspace.find((workspace) => workspace.ids.has(id2));
4781
+ const group = byWorkspace.find((workspace) => workspace.ids?.has(id2));
4744
4782
  (group === void 0 ? ungrouped : group.sessions).push(session);
4745
4783
  }
4746
4784
  const result = byWorkspace.filter((group) => group.sessions.length > 0);
@@ -5124,7 +5162,7 @@
5124
5162
  async function unarchiveSessionsViaOfficial(workspaces, sessionIds, refresh, unarchive) {
5125
5163
  const before = new Set(workspaces.list?.getSnapshot?.()?.archivedSessionIds ?? []);
5126
5164
  const seen = /* @__PURE__ */ new Set();
5127
- const run = typeof unarchive === "function" ? unarchive : (id2) => workspaces.unarchiveSession(id2);
5165
+ const run = typeof unarchive === "function" ? unarchive : (id2) => workspaces.unarchiveSession?.(id2);
5128
5166
  let archivedSessionIds;
5129
5167
  for (const sessionId of sessionIds) {
5130
5168
  if (typeof sessionId !== "string" || sessionId.length === 0 || seen.has(sessionId)) continue;
@@ -5172,7 +5210,7 @@
5172
5210
  onOpened: () => ctx.get("layout")?.selectPanel(null),
5173
5211
  beginNavigation: () => ctx.get("layout")?.beginNavigation?.()
5174
5212
  });
5175
- return () => archiveNavigation.dispose();
5213
+ return () => archiveNavigation?.dispose();
5176
5214
  };
5177
5215
  if (typeof ctx.inject === "function") ctx.inject(["uiWorkspace"], (ready) => attachArchiveNavigation(ready.uiWorkspace ?? uiWorkspaceAt()));
5178
5216
  else ctx.effect(() => attachArchiveNavigation(uiWorkspaceAt()), "archive-manager: explicit archived navigation");
@@ -5204,28 +5242,22 @@
5204
5242
  }
5205
5243
  };
5206
5244
  const unarchiveOne = createUnarchiveSession(ctx.workspaces, () => ctx.get("remote.workspaceRegistry"));
5207
- const favoriteCall = async (method, input) => {
5208
- const registry = ctx.get("remote.workspaceRegistry");
5209
- if (!registry || typeof registry[method] !== "function") throw new Error(ctx.locale.bind(NS)("service.unavailable"));
5210
- const result = input === void 0 ? await registry[method]() : await registry[method](input);
5211
- if (!result.ok) throw new Error(result.error.message);
5212
- return result.value;
5213
- };
5214
- const discoveryCall = async (method, input) => {
5245
+ const registryCall = async (method, ...args) => {
5215
5246
  const registry = ctx.get("remote.workspaceRegistry");
5216
5247
  if (!registry || typeof registry[method] !== "function") throw new Error(ctx.locale.bind(NS)("service.unavailable"));
5217
- const result = await registry[method](input);
5248
+ const call = registry[method];
5249
+ const result = await call.apply(registry, args);
5218
5250
  if (!result.ok) throw new Error(result.error.message);
5219
5251
  return result.value;
5220
5252
  };
5221
- const sessionDetails = (input) => discoveryCall("sessionDetails", input);
5222
- const diagnoseSession = (input) => discoveryCall("diagnoseSession", input);
5223
- const repairSession = (input) => discoveryCall("repairSession", input);
5224
- const searchArchivedContent = (input) => discoveryCall("searchArchivedContent", input);
5225
- const searchSessionContent = (input) => discoveryCall("searchSessionContent", input);
5226
- const previewArchivedSession = (input) => discoveryCall("previewArchivedSession", input);
5227
- const favoriteSessions = () => favoriteCall("favoriteSessions");
5228
- const setSessionFavorite = (input) => favoriteCall("setSessionFavorite", input);
5253
+ const sessionDetails = (input) => registryCall("sessionDetails", input);
5254
+ const diagnoseSession = (input) => registryCall("diagnoseSession", input);
5255
+ const repairSession = (input) => registryCall("repairSession", input);
5256
+ const searchArchivedContent = (input) => registryCall("searchArchivedContent", input);
5257
+ const searchSessionContent = (input) => registryCall("searchSessionContent", input);
5258
+ const previewArchivedSession = (input) => registryCall("previewArchivedSession", input);
5259
+ const favoriteSessions = () => registryCall("favoriteSessions");
5260
+ const setSessionFavorite = (input) => registryCall("setSessionFavorite", input);
5229
5261
  const organizeBatch = createSessionOrganizer({
5230
5262
  workspaces: ctx.workspaces.list,
5231
5263
  sessions: ctx.sessions.list,
@@ -5396,7 +5428,15 @@
5396
5428
  })
5397
5429
  }, ArchivedSessionsSection));
5398
5430
  }
5431
+ async function forkWithFeedback(sessionId, fork, notify, t) {
5432
+ try {
5433
+ await fork(sessionId);
5434
+ } catch (reason) {
5435
+ notify(formatForkError(reason, t));
5436
+ }
5437
+ }
5399
5438
  exports.__test = {
5439
+ forkWithFeedback,
5400
5440
  unarchivedSessionIds,
5401
5441
  ArchiveSelectionToolbar,
5402
5442
  ArchivedSessionsSection,