@michengai/dsh-archive-manager 0.1.41 → 0.1.43
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/CHANGELOG.md +24 -0
- package/CHANGELOG.zh-CN.md +24 -0
- package/README.md +11 -5
- package/README.zh-CN.md +11 -5
- package/cordis.patch.yml +7 -0
- package/lib/archive-experience.js +7 -2
- package/lib/client.js +369 -139
- package/lib/workspace.js +143 -188
- package/package.json +41 -41
package/lib/workspace.js
CHANGED
|
@@ -41,17 +41,6 @@ function markRemoteMethod(instance, method) {
|
|
|
41
41
|
};
|
|
42
42
|
Remote(method)(void 0, context);
|
|
43
43
|
}
|
|
44
|
-
function unknownSessionMessage(sessionId) {
|
|
45
|
-
return `unknown session "${sessionId}" (UNKNOWN_SESSION)`;
|
|
46
|
-
}
|
|
47
|
-
var ArchiveUnknownSessionError = class extends Error {
|
|
48
|
-
sessionId;
|
|
49
|
-
constructor(sessionId) {
|
|
50
|
-
super(unknownSessionMessage(sessionId));
|
|
51
|
-
this.sessionId = sessionId;
|
|
52
|
-
this.name = "ArchiveUnknownSessionError";
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
44
|
function headerIdentity(header) {
|
|
56
45
|
return {
|
|
57
46
|
createdAt: header.createdAt,
|
|
@@ -67,15 +56,6 @@ const sessionIdSchema = {
|
|
|
67
56
|
return value;
|
|
68
57
|
}
|
|
69
58
|
};
|
|
70
|
-
const workspaceIdSchema = {
|
|
71
|
-
parse(value) {
|
|
72
|
-
if (typeof value !== "string" || value.length === 0)
|
|
73
|
-
throw new TypeError(
|
|
74
|
-
`workspaceId must be a non-empty string, got ${String(value)}`
|
|
75
|
-
);
|
|
76
|
-
return value;
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
59
|
const archivedSetSchema = {
|
|
80
60
|
parse(value) {
|
|
81
61
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
@@ -107,28 +87,6 @@ const archivedBatchTargetSchema = {
|
|
|
107
87
|
);
|
|
108
88
|
}
|
|
109
89
|
};
|
|
110
|
-
const unarchivedBatchSchema = {
|
|
111
|
-
parse(value) {
|
|
112
|
-
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
113
|
-
throw new TypeError("result must be an object");
|
|
114
|
-
if (!Array.isArray(value.archivedSessionIds) || value.archivedSessionIds.some((id) => typeof id !== "string"))
|
|
115
|
-
throw new TypeError("archivedSessionIds must be a string array");
|
|
116
|
-
if (!Array.isArray(value.unarchivedSessionIds) || value.unarchivedSessionIds.some((id) => typeof id !== "string"))
|
|
117
|
-
throw new TypeError("unarchivedSessionIds must be a string array");
|
|
118
|
-
return value;
|
|
119
|
-
}
|
|
120
|
-
};
|
|
121
|
-
const archivedWorkspaceBatchSchema = {
|
|
122
|
-
parse(value) {
|
|
123
|
-
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
124
|
-
throw new TypeError("result must be an object");
|
|
125
|
-
if (!Array.isArray(value.archivedSessionIds) || value.archivedSessionIds.some((id) => typeof id !== "string"))
|
|
126
|
-
throw new TypeError("archivedSessionIds must be a string array");
|
|
127
|
-
if (!Array.isArray(value.archivedSessionIdsAdded) || value.archivedSessionIdsAdded.some((id) => typeof id !== "string"))
|
|
128
|
-
throw new TypeError("archivedSessionIdsAdded must be a string array");
|
|
129
|
-
return value;
|
|
130
|
-
}
|
|
131
|
-
};
|
|
132
90
|
const deletedBatchSchema = {
|
|
133
91
|
parse(value) {
|
|
134
92
|
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
@@ -220,64 +178,6 @@ const ARCHIVE_MANAGER_INVOCATIONS = [
|
|
|
220
178
|
column: 1
|
|
221
179
|
}
|
|
222
180
|
},
|
|
223
|
-
{
|
|
224
|
-
id: "@michengai/dsh-archive-manager#workspaceRegistry/unarchiveSessions",
|
|
225
|
-
service: "workspaceRegistry",
|
|
226
|
-
namespace: "workspaceRegistry",
|
|
227
|
-
method: "unarchiveSessions",
|
|
228
|
-
invocation: { kind: "direct" },
|
|
229
|
-
parameters: [
|
|
230
|
-
{
|
|
231
|
-
name: "target",
|
|
232
|
-
wire: "target",
|
|
233
|
-
source: "json",
|
|
234
|
-
codec: {
|
|
235
|
-
mode: "strict",
|
|
236
|
-
typeSymbol: "@michengai/dsh-archive-manager/types#ArchivedBatchTarget",
|
|
237
|
-
schema: archivedBatchTargetSchema
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
],
|
|
241
|
-
result: {
|
|
242
|
-
mode: "strict",
|
|
243
|
-
typeSymbol: "@michengai/dsh-archive-manager/types#UnarchivedBatch",
|
|
244
|
-
schema: unarchivedBatchSchema
|
|
245
|
-
},
|
|
246
|
-
sourceLocation: {
|
|
247
|
-
file: "@michengai/dsh-archive-manager/lib/workspace.js",
|
|
248
|
-
line: 1,
|
|
249
|
-
column: 1
|
|
250
|
-
}
|
|
251
|
-
},
|
|
252
|
-
{
|
|
253
|
-
id: "@michengai/dsh-archive-manager#workspaceRegistry/archiveWorkspaceSessions",
|
|
254
|
-
service: "workspaceRegistry",
|
|
255
|
-
namespace: "workspaceRegistry",
|
|
256
|
-
method: "archiveWorkspaceSessions",
|
|
257
|
-
invocation: { kind: "direct" },
|
|
258
|
-
parameters: [
|
|
259
|
-
{
|
|
260
|
-
name: "workspaceId",
|
|
261
|
-
wire: "workspaceId",
|
|
262
|
-
source: "json",
|
|
263
|
-
codec: {
|
|
264
|
-
mode: "strict",
|
|
265
|
-
typeSymbol: "@deepseek-ai/dsh-workspace/types#WorkspaceId",
|
|
266
|
-
schema: workspaceIdSchema
|
|
267
|
-
}
|
|
268
|
-
}
|
|
269
|
-
],
|
|
270
|
-
result: {
|
|
271
|
-
mode: "strict",
|
|
272
|
-
typeSymbol: "@michengai/dsh-archive-manager/types#ArchivedWorkspaceBatch",
|
|
273
|
-
schema: archivedWorkspaceBatchSchema
|
|
274
|
-
},
|
|
275
|
-
sourceLocation: {
|
|
276
|
-
file: "@michengai/dsh-archive-manager/lib/workspace.js",
|
|
277
|
-
line: 1,
|
|
278
|
-
column: 1
|
|
279
|
-
}
|
|
280
|
-
},
|
|
281
181
|
{
|
|
282
182
|
id: "@michengai/dsh-archive-manager#workspaceRegistry/deleteArchivedSessions",
|
|
283
183
|
service: "workspaceRegistry",
|
|
@@ -358,28 +258,113 @@ var ArchiveWorkspaceRegistry = class extends WorkspaceRegistry {
|
|
|
358
258
|
deletedSessionTombstoneLimit = 4096;
|
|
359
259
|
/** 被删生命周期的日志身份(createdAt/cwd):冷复用探针区分“同 id 新会话”与 stale list() 的依据。 */
|
|
360
260
|
deletedIdentities = /* @__PURE__ */ new Map();
|
|
261
|
+
archivedSessionPathIndex = /* @__PURE__ */ new Map();
|
|
262
|
+
archivedSessionPathIndexKey;
|
|
361
263
|
constructor(ctx) {
|
|
362
264
|
super(ctx);
|
|
265
|
+
const indexedPath = this.host.sessionPath;
|
|
266
|
+
this.host.sessionPath = (id) => {
|
|
267
|
+
const path = indexedPath(id);
|
|
268
|
+
if (path !== void 0) return path;
|
|
269
|
+
if (this.invalidSessionPaths.has(id)) return void 0;
|
|
270
|
+
try {
|
|
271
|
+
return this.archivedWorkspacePath(id);
|
|
272
|
+
} catch {
|
|
273
|
+
return void 0;
|
|
274
|
+
}
|
|
275
|
+
};
|
|
363
276
|
this.typertRemote = bindTypertRemote(this, this.name);
|
|
364
277
|
markRemoteMethod(this, "unarchiveSession");
|
|
365
278
|
markRemoteMethod(this, "deleteSession");
|
|
366
|
-
markRemoteMethod(this, "unarchiveSessions");
|
|
367
|
-
markRemoteMethod(this, "archiveWorkspaceSessions");
|
|
368
279
|
markRemoteMethod(this, "deleteArchivedSessions");
|
|
369
280
|
markRemoteMethod(this, "archivedSessionMetadata");
|
|
370
281
|
registerHostRemote(this.ctx);
|
|
371
282
|
}
|
|
283
|
+
/** 归档集合未变时复用反查表,避免每次 sessionPath 都扫全部工作区记账。 */
|
|
284
|
+
archivedWorkspacePath(sessionId) {
|
|
285
|
+
const state = this.requireState();
|
|
286
|
+
if (!state.archivedSessionIds.includes(sessionId)) return void 0;
|
|
287
|
+
if (this.archivedSessionPathIndexKey !== state.archivedSessionIds) {
|
|
288
|
+
const index = /* @__PURE__ */ new Map();
|
|
289
|
+
const archived = new Set(state.archivedSessionIds);
|
|
290
|
+
const table = this.requireTable();
|
|
291
|
+
for (const workspaceId of state.workspaceIds) {
|
|
292
|
+
const record = table.get(workspaceId);
|
|
293
|
+
if (record === void 0) continue;
|
|
294
|
+
for (const id of record.sessionIds) {
|
|
295
|
+
if (archived.has(id)) index.set(id, record.path);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
this.archivedSessionPathIndex = index;
|
|
299
|
+
this.archivedSessionPathIndexKey = state.archivedSessionIds;
|
|
300
|
+
}
|
|
301
|
+
return this.archivedSessionPathIndex.get(sessionId);
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* 只有 persistence.stat 明确说文件不在时才从持久集合摘掉。
|
|
305
|
+
* list/header 读不出不等于文件没了;没有 stat 时宁可不落盘删除。
|
|
306
|
+
*/
|
|
307
|
+
async sessionArtifactMissing(sessionId) {
|
|
308
|
+
const persistence = this.ctx.get("sessionPersistence");
|
|
309
|
+
if (typeof persistence?.stat !== "function") return false;
|
|
310
|
+
try {
|
|
311
|
+
return await persistence.stat(sessionId) === void 0;
|
|
312
|
+
} catch (error) {
|
|
313
|
+
this.ctx.logger.warn(
|
|
314
|
+
`archive-manager: could not stat archived session "${sessionId}": ${String(error)}`
|
|
315
|
+
);
|
|
316
|
+
return false;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* 从归档集合摘掉已经确认不存在的会话。打开归档列表时调用。
|
|
321
|
+
* 读不出头部的标记留在持久集合里,只从本次元数据结果里隐藏。
|
|
322
|
+
*/
|
|
323
|
+
async pruneUnknownArchivedSessionIds() {
|
|
324
|
+
return this.enqueueOperation(async () => {
|
|
325
|
+
const state = this.requireState();
|
|
326
|
+
const listed = /* @__PURE__ */ new Set();
|
|
327
|
+
for (const item of await this.listStoredHeaders()) {
|
|
328
|
+
const header = item.header ?? item;
|
|
329
|
+
if (typeof header?.id === "string") listed.add(header.id);
|
|
330
|
+
}
|
|
331
|
+
const sessions = this.ctx.get("sessions");
|
|
332
|
+
const kept = [];
|
|
333
|
+
const seen = /* @__PURE__ */ new Set();
|
|
334
|
+
for (const sessionId of state.archivedSessionIds) {
|
|
335
|
+
if (seen.has(sessionId)) continue;
|
|
336
|
+
seen.add(sessionId);
|
|
337
|
+
if (sessions?.get(sessionId) !== void 0) {
|
|
338
|
+
kept.push(sessionId);
|
|
339
|
+
continue;
|
|
340
|
+
}
|
|
341
|
+
if (this.deletedSessionIds.has(sessionId)) {
|
|
342
|
+
if (await this.coldReuseKnown(sessionId)) kept.push(sessionId);
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
if (this.headers.has(sessionId) || listed.has(sessionId)) {
|
|
346
|
+
kept.push(sessionId);
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
if (!await this.sessionArtifactMissing(sessionId)) kept.push(sessionId);
|
|
350
|
+
}
|
|
351
|
+
if (kept.length === state.archivedSessionIds.length && kept.every((id, index) => id === state.archivedSessionIds[index]))
|
|
352
|
+
return kept;
|
|
353
|
+
await this.setState({ ...state, archivedSessionIds: kept });
|
|
354
|
+
return kept;
|
|
355
|
+
});
|
|
356
|
+
}
|
|
372
357
|
/**
|
|
373
358
|
* 归档设置页创建时间排序所需的最小元数据。老用户可能仍有会话原文和
|
|
374
359
|
* 归档标记、却没有投影缓存;这里按需从完整日志重建一次,再通知客户端
|
|
375
360
|
* 刷新会话列表。已有缓存不读原文,新老 DSH 的缓存布局都走同一 put。
|
|
361
|
+
* 读取前只清掉文件已确认不存在的归档标记。
|
|
376
362
|
*/
|
|
377
363
|
async archivedSessionMetadata() {
|
|
364
|
+
await this.pruneUnknownArchivedSessionIds();
|
|
378
365
|
const items = [];
|
|
379
366
|
const repairedSessionIds = [];
|
|
380
|
-
for (const sessionId of
|
|
381
|
-
...new Set(this.requireState().archivedSessionIds)
|
|
382
|
-
]) {
|
|
367
|
+
for (const sessionId of this.requireState().archivedSessionIds) {
|
|
383
368
|
try {
|
|
384
369
|
const header = await this.readSessionHeader(sessionId);
|
|
385
370
|
if (await this.repairArchivedProjection(header))
|
|
@@ -470,17 +455,32 @@ var ArchiveWorkspaceRegistry = class extends WorkspaceRegistry {
|
|
|
470
455
|
await handle.close();
|
|
471
456
|
}
|
|
472
457
|
}
|
|
458
|
+
/**
|
|
459
|
+
* 把一个已知会话加入注册表全局归档集合。已归档的 id 不写入;
|
|
460
|
+
* 未知 id 直接跳过,不抛 `UNKNOWN_SESSION`,避免把幽灵 id 写进集合。
|
|
461
|
+
* @param sessionId - 要归档的会话。
|
|
462
|
+
*/
|
|
463
|
+
async archiveSession(sessionId) {
|
|
464
|
+
return this.enqueueOperation(async () => {
|
|
465
|
+
if (this.requireState().archivedSessionIds.includes(sessionId)) return;
|
|
466
|
+
if (!await this.sessionKnown(sessionId)) return;
|
|
467
|
+
const state = this.requireState();
|
|
468
|
+
await this.setState({
|
|
469
|
+
...state,
|
|
470
|
+
archivedSessionIds: [...state.archivedSessionIds, sessionId]
|
|
471
|
+
});
|
|
472
|
+
});
|
|
473
|
+
}
|
|
473
474
|
/**
|
|
474
475
|
* 把一个会话移出注册表全局归档集合,恢复其正常可见性(其记账位从未
|
|
475
|
-
*
|
|
476
|
-
*
|
|
476
|
+
* 移动,会话在原工作区位置重新出现)。与官方一致:不做会话存在性检查,
|
|
477
|
+
* 因为从集合摘掉 id 不会引入未知引用。孤儿归档标记也会被清掉;
|
|
478
|
+
* 未归档的 id(含不存在的 id)不写入即返回。
|
|
477
479
|
* @param sessionId - 要取消归档的会话。
|
|
478
480
|
* @returns 更新后的完整归档集合。
|
|
479
481
|
*/
|
|
480
482
|
async unarchiveSession(sessionId) {
|
|
481
483
|
return this.enqueueOperation(async () => {
|
|
482
|
-
if (!await this.sessionKnown(sessionId))
|
|
483
|
-
throw new ArchiveUnknownSessionError(sessionId);
|
|
484
484
|
const state = this.requireState();
|
|
485
485
|
if (!state.archivedSessionIds.includes(sessionId))
|
|
486
486
|
return { archivedSessionIds: [...state.archivedSessionIds] };
|
|
@@ -491,73 +491,33 @@ var ArchiveWorkspaceRegistry = class extends WorkspaceRegistry {
|
|
|
491
491
|
)
|
|
492
492
|
};
|
|
493
493
|
await this.setState(next);
|
|
494
|
+
await this.restoreWorkspaceMembership(sessionId);
|
|
494
495
|
return { archivedSessionIds: [...next.archivedSessionIds] };
|
|
495
496
|
});
|
|
496
497
|
}
|
|
497
498
|
/**
|
|
498
|
-
*
|
|
499
|
-
*
|
|
499
|
+
* 恢复后重新编入路径索引;若会话已不在任何工作区记账但 cwd 仍对应某工作区,
|
|
500
|
+
* 则挂回去,避免「恢复并打开」时官方成员过滤把会话从原工作区抹掉。
|
|
500
501
|
*/
|
|
501
|
-
async
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
};
|
|
521
|
-
const next = {
|
|
522
|
-
...state,
|
|
523
|
-
archivedSessionIds: [
|
|
524
|
-
...state.archivedSessionIds,
|
|
525
|
-
...archivedSessionIdsAdded
|
|
526
|
-
]
|
|
527
|
-
};
|
|
528
|
-
await this.setState(next);
|
|
529
|
-
return {
|
|
530
|
-
archivedSessionIds: [...next.archivedSessionIds],
|
|
531
|
-
archivedSessionIdsAdded
|
|
532
|
-
};
|
|
533
|
-
});
|
|
534
|
-
}
|
|
535
|
-
/**
|
|
536
|
-
* 按宿主权威归档集合一次恢复全部、一个工作区或未分组的归档会话。
|
|
537
|
-
* 目标全部来自已归档集合,因此即使日志已被外部移除,也会清掉陈旧归档标记。
|
|
538
|
-
*/
|
|
539
|
-
async unarchiveSessions(target) {
|
|
540
|
-
return this.enqueueOperation(async () => {
|
|
541
|
-
const unarchivedSessionIds = this.archivedSessionIdsForTarget(target);
|
|
542
|
-
if (unarchivedSessionIds.length === 0)
|
|
543
|
-
return {
|
|
544
|
-
archivedSessionIds: [...this.requireState().archivedSessionIds],
|
|
545
|
-
unarchivedSessionIds: []
|
|
546
|
-
};
|
|
547
|
-
const restored = new Set(unarchivedSessionIds);
|
|
548
|
-
const state = this.requireState();
|
|
549
|
-
const next = {
|
|
550
|
-
...state,
|
|
551
|
-
archivedSessionIds: state.archivedSessionIds.filter(
|
|
552
|
-
(id) => !restored.has(id)
|
|
553
|
-
)
|
|
554
|
-
};
|
|
555
|
-
await this.setState(next);
|
|
556
|
-
return {
|
|
557
|
-
archivedSessionIds: [...next.archivedSessionIds],
|
|
558
|
-
unarchivedSessionIds
|
|
559
|
-
};
|
|
560
|
-
});
|
|
502
|
+
async restoreWorkspaceMembership(sessionId) {
|
|
503
|
+
let header;
|
|
504
|
+
try {
|
|
505
|
+
header = await this.readSessionHeader(sessionId);
|
|
506
|
+
await this.indexHeader(header);
|
|
507
|
+
} catch {
|
|
508
|
+
return;
|
|
509
|
+
}
|
|
510
|
+
const path = this.sessionPaths.get(sessionId);
|
|
511
|
+
if (path === void 0) return;
|
|
512
|
+
const table = this.requireTable();
|
|
513
|
+
for (const workspaceId of this.requireState().workspaceIds) {
|
|
514
|
+
const record = table.get(workspaceId);
|
|
515
|
+
if (record === void 0 || record.path !== path) continue;
|
|
516
|
+
if (record.sessionIds.includes(sessionId)) return;
|
|
517
|
+
const entity = this.entities.get(workspaceId);
|
|
518
|
+
if (entity !== void 0) await entity.attachSession(sessionId);
|
|
519
|
+
return;
|
|
520
|
+
}
|
|
561
521
|
}
|
|
562
522
|
/**
|
|
563
523
|
* 按作用域永久删除归档会话。跨会话文件删除无法组成事务,因此继续处理
|
|
@@ -571,18 +531,10 @@ var ArchiveWorkspaceRegistry = class extends WorkspaceRegistry {
|
|
|
571
531
|
const failures = [];
|
|
572
532
|
for (const sessionId of requestedSessionIds) {
|
|
573
533
|
try {
|
|
574
|
-
await this.deleteSessionCore(sessionId);
|
|
575
|
-
|
|
534
|
+
const result = await this.deleteSessionCore(sessionId);
|
|
535
|
+
if (result?.skipped) skippedSessionIds.push(sessionId);
|
|
536
|
+
else deletedSessionIds.push(sessionId);
|
|
576
537
|
} catch (error) {
|
|
577
|
-
if (error instanceof ArchiveUnknownSessionError) {
|
|
578
|
-
try {
|
|
579
|
-
await this.cleanupUnknownArchivedSession(sessionId);
|
|
580
|
-
skippedSessionIds.push(sessionId);
|
|
581
|
-
} catch (cleanupError) {
|
|
582
|
-
failures.push({ sessionId, message: String(cleanupError) });
|
|
583
|
-
}
|
|
584
|
-
continue;
|
|
585
|
-
}
|
|
586
538
|
failures.push({ sessionId, message: String(error) });
|
|
587
539
|
}
|
|
588
540
|
}
|
|
@@ -648,16 +600,20 @@ var ArchiveWorkspaceRegistry = class extends WorkspaceRegistry {
|
|
|
648
600
|
* 永久删除一个会话及其全部痕迹(转录目录、工作区记账、归档标记、
|
|
649
601
|
* 投影缓存行)。
|
|
650
602
|
* @param sessionId - 要删除的会话。
|
|
651
|
-
* @returns 持久化完成后的 `{ deleted: true }
|
|
652
|
-
* @throws {@link ArchiveUnknownSessionError} 会话未知时抛出。
|
|
603
|
+
* @returns 持久化完成后的 `{ deleted: true }`。未知会话清掉残留痕迹后同样返回成功,不抛错。
|
|
653
604
|
*/
|
|
654
605
|
async deleteSession(sessionId) {
|
|
655
|
-
return this.enqueueOperation(() =>
|
|
606
|
+
return this.enqueueOperation(async () => {
|
|
607
|
+
await this.deleteSessionCore(sessionId);
|
|
608
|
+
return { deleted: true };
|
|
609
|
+
});
|
|
656
610
|
}
|
|
657
611
|
/** 串行化后的删除主体(级联路径复用:它已持有操作链,绝不能再入队)。 */
|
|
658
612
|
async deleteSessionCore(sessionId) {
|
|
659
|
-
if (!await this.sessionKnown(sessionId))
|
|
660
|
-
|
|
613
|
+
if (!await this.sessionKnown(sessionId)) {
|
|
614
|
+
await this.cleanupUnknownArchivedSession(sessionId);
|
|
615
|
+
return { deleted: true, skipped: true };
|
|
616
|
+
}
|
|
661
617
|
const sessions = this.ctx.get("sessions");
|
|
662
618
|
const live = sessions?.get(sessionId);
|
|
663
619
|
const deletedHeader = this.headers.get(sessionId) ?? live?.header;
|
|
@@ -887,7 +843,6 @@ var ArchiveWorkspaceRegistry = class extends WorkspaceRegistry {
|
|
|
887
843
|
if (!await this.sessionKnown(childId)) continue;
|
|
888
844
|
await this.deleteSessionCore(childId);
|
|
889
845
|
} catch (error) {
|
|
890
|
-
if (error instanceof ArchiveUnknownSessionError) continue;
|
|
891
846
|
this.ctx.logger.warn(
|
|
892
847
|
`archive-manager: cascade delete of subagent session "${childId}" (child of "${sessionId}") failed: ${String(error)}`
|
|
893
848
|
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@michengai/dsh-archive-manager",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.43",
|
|
4
4
|
"description": "NPM-installable DSH Web plugin for managing archived sessions.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "pnpm@11.22.0",
|
|
@@ -38,22 +38,22 @@
|
|
|
38
38
|
},
|
|
39
39
|
"peerDependencies": {
|
|
40
40
|
"@deepseek-ai/cordis": "^4.0.1",
|
|
41
|
-
"@deepseek-ai/dsh-client-connection": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2",
|
|
42
|
-
"@deepseek-ai/dsh-client-locale": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2",
|
|
43
|
-
"@deepseek-ai/dsh-client-runtime": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2",
|
|
44
|
-
"@deepseek-ai/dsh-client-store": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2",
|
|
45
|
-
"@deepseek-ai/dsh-client-ui-conversation": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2",
|
|
46
|
-
"@deepseek-ai/dsh-client-ui-primitives": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2",
|
|
47
|
-
"@deepseek-ai/dsh-client-ui-sidebar": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2",
|
|
48
|
-
"@deepseek-ai/dsh-client-ui-workspace": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2",
|
|
49
|
-
"@deepseek-ai/dsh-host-webserver": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2",
|
|
50
|
-
"@deepseek-ai/dsh-session": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2",
|
|
51
|
-
"@deepseek-ai/dsh-session-projection-cache": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2",
|
|
52
|
-
"@deepseek-ai/dsh-spill-local": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2",
|
|
53
|
-
"@deepseek-ai/dsh-storage-domain": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2",
|
|
54
|
-
"@deepseek-ai/dsh-typert-protocol": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2",
|
|
55
|
-
"@deepseek-ai/dsh-typert-registry": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2",
|
|
56
|
-
"@deepseek-ai/dsh-workspace": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2"
|
|
41
|
+
"@deepseek-ai/dsh-client-connection": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1",
|
|
42
|
+
"@deepseek-ai/dsh-client-locale": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1",
|
|
43
|
+
"@deepseek-ai/dsh-client-runtime": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1",
|
|
44
|
+
"@deepseek-ai/dsh-client-store": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1",
|
|
45
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1",
|
|
46
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1",
|
|
47
|
+
"@deepseek-ai/dsh-client-ui-sidebar": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1",
|
|
48
|
+
"@deepseek-ai/dsh-client-ui-workspace": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1",
|
|
49
|
+
"@deepseek-ai/dsh-host-webserver": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1",
|
|
50
|
+
"@deepseek-ai/dsh-session": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1",
|
|
51
|
+
"@deepseek-ai/dsh-session-projection-cache": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1",
|
|
52
|
+
"@deepseek-ai/dsh-spill-local": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1",
|
|
53
|
+
"@deepseek-ai/dsh-storage-domain": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1",
|
|
54
|
+
"@deepseek-ai/dsh-typert-protocol": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1",
|
|
55
|
+
"@deepseek-ai/dsh-typert-registry": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1",
|
|
56
|
+
"@deepseek-ai/dsh-workspace": "0.1.0-rc.8 || 0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1"
|
|
57
57
|
},
|
|
58
58
|
"peerDependenciesMeta": {
|
|
59
59
|
"@deepseek-ai/dsh-client-runtime": {
|
|
@@ -65,30 +65,30 @@
|
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@deepseek-ai/cordis": "4.0.2",
|
|
68
|
-
"@deepseek-ai/dsh-api-gateway": "0.1.
|
|
69
|
-
"@deepseek-ai/dsh-client-connection": "0.1.
|
|
70
|
-
"@deepseek-ai/dsh-client-locale": "0.1.
|
|
71
|
-
"@deepseek-ai/dsh-client-store": "0.1.
|
|
72
|
-
"@deepseek-ai/dsh-client-ui-conversation": "0.1.
|
|
73
|
-
"@deepseek-ai/dsh-client-ui-primitives": "0.1.
|
|
74
|
-
"@deepseek-ai/dsh-client-ui-renderer": "0.1.
|
|
75
|
-
"@deepseek-ai/dsh-client-ui-sidebar": "0.1.
|
|
76
|
-
"@deepseek-ai/dsh-client-ui-slots": "0.1.
|
|
77
|
-
"@deepseek-ai/dsh-client-ui-workspace": "0.1.
|
|
78
|
-
"@deepseek-ai/dsh-host-webserver": "0.1.
|
|
79
|
-
"@deepseek-ai/dsh-invariants": "0.1.
|
|
80
|
-
"@deepseek-ai/dsh-scope": "0.1.
|
|
81
|
-
"@deepseek-ai/dsh-session": "0.1.
|
|
82
|
-
"@deepseek-ai/dsh-session-persistence": "0.1.
|
|
83
|
-
"@deepseek-ai/dsh-session-projection": "0.1.
|
|
84
|
-
"@deepseek-ai/dsh-session-projection-cache": "0.1.
|
|
85
|
-
"@deepseek-ai/dsh-spill": "0.1.
|
|
86
|
-
"@deepseek-ai/dsh-spill-local": "0.1.
|
|
87
|
-
"@deepseek-ai/dsh-storage": "0.1.
|
|
88
|
-
"@deepseek-ai/dsh-storage-domain": "0.1.
|
|
89
|
-
"@deepseek-ai/dsh-typert-protocol": "0.1.
|
|
90
|
-
"@deepseek-ai/dsh-typert-registry": "0.1.
|
|
91
|
-
"@deepseek-ai/dsh-workspace": "0.1.
|
|
68
|
+
"@deepseek-ai/dsh-api-gateway": "0.1.6-alpha.1",
|
|
69
|
+
"@deepseek-ai/dsh-client-connection": "0.1.6-alpha.1",
|
|
70
|
+
"@deepseek-ai/dsh-client-locale": "0.1.6-alpha.1",
|
|
71
|
+
"@deepseek-ai/dsh-client-store": "0.1.6-alpha.1",
|
|
72
|
+
"@deepseek-ai/dsh-client-ui-conversation": "0.1.6-alpha.1",
|
|
73
|
+
"@deepseek-ai/dsh-client-ui-primitives": "0.1.6-alpha.1",
|
|
74
|
+
"@deepseek-ai/dsh-client-ui-renderer": "0.1.6-alpha.1",
|
|
75
|
+
"@deepseek-ai/dsh-client-ui-sidebar": "0.1.6-alpha.1",
|
|
76
|
+
"@deepseek-ai/dsh-client-ui-slots": "0.1.6-alpha.1",
|
|
77
|
+
"@deepseek-ai/dsh-client-ui-workspace": "0.1.6-alpha.1",
|
|
78
|
+
"@deepseek-ai/dsh-host-webserver": "0.1.6-alpha.1",
|
|
79
|
+
"@deepseek-ai/dsh-invariants": "0.1.6-alpha.1",
|
|
80
|
+
"@deepseek-ai/dsh-scope": "0.1.6-alpha.1",
|
|
81
|
+
"@deepseek-ai/dsh-session": "0.1.6-alpha.1",
|
|
82
|
+
"@deepseek-ai/dsh-session-persistence": "0.1.6-alpha.1",
|
|
83
|
+
"@deepseek-ai/dsh-session-projection": "0.1.6-alpha.1",
|
|
84
|
+
"@deepseek-ai/dsh-session-projection-cache": "0.1.6-alpha.1",
|
|
85
|
+
"@deepseek-ai/dsh-spill": "0.1.6-alpha.1",
|
|
86
|
+
"@deepseek-ai/dsh-spill-local": "0.1.6-alpha.1",
|
|
87
|
+
"@deepseek-ai/dsh-storage": "0.1.6-alpha.1",
|
|
88
|
+
"@deepseek-ai/dsh-storage-domain": "0.1.6-alpha.1",
|
|
89
|
+
"@deepseek-ai/dsh-typert-protocol": "0.1.6-alpha.1",
|
|
90
|
+
"@deepseek-ai/dsh-typert-registry": "0.1.6-alpha.1",
|
|
91
|
+
"@deepseek-ai/dsh-workspace": "0.1.6-alpha.1",
|
|
92
92
|
"react": "18.3.1",
|
|
93
93
|
"react-dom": "18.3.1",
|
|
94
94
|
"esbuild": "0.25.0",
|