@michengai/dsh-archive-manager 1.0.9 → 1.0.11

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/workspace.js CHANGED
@@ -273,6 +273,24 @@ function hostEvent(ctx, name) {
273
273
  const caller = ctx[name];
274
274
  return typeof caller === "function" ? caller : void 0;
275
275
  }
276
+ const fileUploadResolverRestart = Symbol.for("dsh-archive-manager.file-upload-resolver-restart");
277
+ const staleFileUploadResolver = "file-upload: Agent resolver is already registered";
278
+ function tolerateStaleFileUploadResolver(ctx) {
279
+ const uploads = ctx.get?.("fileUploads");
280
+ const original = uploads?.registerAgentResolver;
281
+ if (uploads === void 0 || typeof original !== "function" || original[fileUploadResolverRestart] === true) return;
282
+ const registerAgentResolver = function(resolve2) {
283
+ try {
284
+ return original.call(this, resolve2);
285
+ } catch (error) {
286
+ if (!(error instanceof Error) || error.message !== staleFileUploadResolver || !Object.hasOwn(this, "agentResolver")) throw error;
287
+ this.agentResolver = void 0;
288
+ return original.call(this, resolve2);
289
+ }
290
+ };
291
+ registerAgentResolver[fileUploadResolverRestart] = true;
292
+ uploads.registerAgentResolver = registerAgentResolver;
293
+ }
276
294
  var ArchiveWorkspaceRegistry = class extends WorkspaceRegistry {
277
295
  static inject = [
278
296
  "storageDomain",
@@ -292,6 +310,7 @@ var ArchiveWorkspaceRegistry = class extends WorkspaceRegistry {
292
310
  archivedSessionPathIndexKey;
293
311
  constructor(ctx) {
294
312
  super(ctx);
313
+ tolerateStaleFileUploadResolver(ctx);
295
314
  const indexedPath = this.host.sessionPath;
296
315
  this.host.sessionPath = (id) => {
297
316
  const path = indexedPath(id);
@@ -800,9 +819,17 @@ var ArchiveWorkspaceRegistry = class extends WorkspaceRegistry {
800
819
  const deletedSessionIds = [];
801
820
  const skippedSessionIds = [];
802
821
  const failures = [];
822
+ let descendantHeaders;
823
+ try {
824
+ descendantHeaders = await this.listStoredHeaders();
825
+ } catch (error) {
826
+ this.ctx.logger.warn(
827
+ `archive-manager: batch descendant listing failed; each cascade will retry: ${String(error)}`
828
+ );
829
+ }
803
830
  for (const sessionId of requestedSessionIds) {
804
831
  try {
805
- const result = await this.deleteSessionCore(sessionId);
832
+ const result = await this.deleteSessionCore(sessionId, descendantHeaders);
806
833
  if (result?.skipped) skippedSessionIds.push(sessionId);
807
834
  else deletedSessionIds.push(sessionId);
808
835
  } catch (error) {
@@ -880,7 +907,7 @@ var ArchiveWorkspaceRegistry = class extends WorkspaceRegistry {
880
907
  });
881
908
  }
882
909
  /** 串行化后的删除主体(级联路径复用:它已持有操作链,绝不能再入队)。 */
883
- async deleteSessionCore(sessionId) {
910
+ async deleteSessionCore(sessionId, descendantHeaders) {
884
911
  if (!await this.sessionKnown(sessionId)) {
885
912
  await this.cleanupUnknownArchivedSession(sessionId);
886
913
  return { deleted: true, skipped: true };
@@ -897,7 +924,7 @@ var ArchiveWorkspaceRegistry = class extends WorkspaceRegistry {
897
924
  const projCache = this.ctx.get("sessionProjectionCache");
898
925
  await projCache?.whenIdle?.();
899
926
  if (projCache !== void 0) await projCache.delete(sessionId);
900
- await this.deleteDescendants(sessionId);
927
+ await this.deleteDescendants(sessionId, descendantHeaders);
901
928
  await this.cleanSpill(sessionId);
902
929
  await this.removeTranscriptDirectory(sessionId);
903
930
  const state = this.requireState();
@@ -1127,23 +1154,28 @@ var ArchiveWorkspaceRegistry = class extends WorkspaceRegistry {
1127
1154
  /** 尽力而为的级联删除:删除 `sessionId` 的 SUBAGENT 子会话。
1128
1155
  * 仅头部标记 `origin: "subagent"` 的会话参与:单凭 `parentSession` 有歧义
1129
1156
  *(fork 分支也携带它),而 fork 分支是独立的用户会话,绝不能被级联删除。 */
1130
- async deleteDescendants(sessionId) {
1157
+ async deleteDescendants(sessionId, storedHeaders) {
1131
1158
  try {
1132
1159
  const descendants = [];
1160
+ const collected = /* @__PURE__ */ new Set();
1133
1161
  const sessions = this.ctx.get("sessions");
1134
1162
  if (sessions !== void 0)
1135
1163
  for (const session of sessions.list()) {
1136
- if (session.header.parentSession === sessionId && session.header.origin === "subagent")
1164
+ if (session.header.parentSession === sessionId && session.header.origin === "subagent") {
1137
1165
  descendants.push(session.id);
1166
+ collected.add(session.id);
1167
+ }
1138
1168
  }
1139
- for (const header of await this.listStoredHeaders()) {
1140
- if (header.parentSession === sessionId && header.origin === "subagent" && !descendants.includes(header.id))
1169
+ for (const header of storedHeaders ?? await this.listStoredHeaders()) {
1170
+ if (header.parentSession === sessionId && header.origin === "subagent" && !collected.has(header.id)) {
1141
1171
  descendants.push(header.id);
1172
+ collected.add(header.id);
1173
+ }
1142
1174
  }
1143
1175
  for (const childId of descendants) {
1144
1176
  try {
1145
1177
  if (!await this.sessionKnown(childId)) continue;
1146
- await this.deleteSessionCore(childId);
1178
+ await this.deleteSessionCore(childId, storedHeaders);
1147
1179
  } catch (error) {
1148
1180
  this.ctx.logger.warn(
1149
1181
  `archive-manager: cascade delete of subagent session "${childId}" (child of "${sessionId}") failed: ${String(error)}`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@michengai/dsh-archive-manager",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
4
  "description": "NPM-installable DSH Web plugin for managing archived sessions.",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@11.22.0",