dsh-sessions-manager 3.4.2 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.en.md +6 -0
- package/README.md +6 -0
- package/lib/client.js +60 -17
- package/lib/client.js.map +2 -2
- package/lib/index.js +182 -58
- package/lib/index.js.map +4 -4
- package/package.json +1 -1
- package/src/client/index.jsx +42 -7
- package/src/compat/capabilities.js +34 -0
- package/src/compat/persistence.js +72 -0
- package/src/index.js +87 -55
package/lib/index.js
CHANGED
|
@@ -604,6 +604,101 @@ function createTitleIndexStore({ dir, file }) {
|
|
|
604
604
|
};
|
|
605
605
|
}
|
|
606
606
|
|
|
607
|
+
// src/compat/persistence.js
|
|
608
|
+
function asHeader(value) {
|
|
609
|
+
if (!value || typeof value !== "object") return null;
|
|
610
|
+
const candidate = value.header && typeof value.header === "object" ? value.header : value;
|
|
611
|
+
return candidate.id == null ? null : candidate;
|
|
612
|
+
}
|
|
613
|
+
function normalizePersistenceEntry(value) {
|
|
614
|
+
const header = asHeader(value);
|
|
615
|
+
if (!header) return null;
|
|
616
|
+
const snapshot = value && value.header === header ? value : null;
|
|
617
|
+
return {
|
|
618
|
+
header,
|
|
619
|
+
snapshot,
|
|
620
|
+
id: String(header.id),
|
|
621
|
+
sizeBytes: snapshot && Number.isFinite(snapshot.sizeBytes) ? Number(snapshot.sizeBytes) : null,
|
|
622
|
+
eventCount: snapshot && Number.isSafeInteger(snapshot.eventCount) ? snapshot.eventCount : null,
|
|
623
|
+
revision: snapshot ? snapshot.revision : null
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
function normalizePersistenceList(values) {
|
|
627
|
+
if (!Array.isArray(values)) return [];
|
|
628
|
+
return values.map(normalizePersistenceEntry).filter(Boolean);
|
|
629
|
+
}
|
|
630
|
+
function createPersistenceAdapter(service) {
|
|
631
|
+
if (!service || typeof service.list !== "function") throw new TypeError("sessionPersistence.list is required");
|
|
632
|
+
async function listEntries(options) {
|
|
633
|
+
return normalizePersistenceList(await service.list(options));
|
|
634
|
+
}
|
|
635
|
+
async function readSession(id, offset = 0) {
|
|
636
|
+
if (typeof service.readFrom === "function") {
|
|
637
|
+
const result = await service.readFrom(id, offset);
|
|
638
|
+
return {
|
|
639
|
+
meta: result && result.meta ? result.meta : null,
|
|
640
|
+
inheritedEventCount: result && Number.isSafeInteger(result.inheritedEventCount) ? result.inheritedEventCount : 0,
|
|
641
|
+
events: result && Array.isArray(result.events) ? result.events : []
|
|
642
|
+
};
|
|
643
|
+
}
|
|
644
|
+
if (typeof service.open !== "function") throw new Error("\u5F53\u524D DSH \u6301\u4E45\u5316\u670D\u52A1\u4E0D\u652F\u6301\u8BFB\u53D6\u4F1A\u8BDD");
|
|
645
|
+
const handle = await service.open(id, "read");
|
|
646
|
+
if (!handle || typeof handle.read !== "function" || typeof handle.close !== "function") {
|
|
647
|
+
try {
|
|
648
|
+
if (handle && typeof handle.close === "function") await handle.close();
|
|
649
|
+
} catch {
|
|
650
|
+
}
|
|
651
|
+
throw new Error("DSH \u8FD4\u56DE\u4E86\u65E0\u6548\u7684 SessionHandle");
|
|
652
|
+
}
|
|
653
|
+
try {
|
|
654
|
+
const events = await handle.read(offset);
|
|
655
|
+
return {
|
|
656
|
+
meta: handle.header || handle.meta || null,
|
|
657
|
+
inheritedEventCount: Number.isSafeInteger(handle.inheritedEventCount) ? handle.inheritedEventCount : 0,
|
|
658
|
+
events: Array.isArray(events) ? events : [...events || []]
|
|
659
|
+
};
|
|
660
|
+
} finally {
|
|
661
|
+
await handle.close();
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
function locate(header) {
|
|
665
|
+
if (typeof service.locate === "function") return service.locate(header);
|
|
666
|
+
return null;
|
|
667
|
+
}
|
|
668
|
+
const kind = typeof service.open === "function" ? "session-handle" : "legacy";
|
|
669
|
+
return { kind, listEntries, readSession, locate };
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// src/compat/capabilities.js
|
|
673
|
+
function action(available, reason = null) {
|
|
674
|
+
return { available: !!available, reason: available ? null : reason };
|
|
675
|
+
}
|
|
676
|
+
function detectCapabilities({ persistence, workspaceRegistry }) {
|
|
677
|
+
const handleApi = !!(persistence && typeof persistence.open === "function");
|
|
678
|
+
const legacyRead = !!(persistence && typeof persistence.readFrom === "function");
|
|
679
|
+
const legacyLocate = !!(persistence && (typeof persistence.locate === "function" || persistence.backend && typeof persistence.backend.locate === "function"));
|
|
680
|
+
const workspaceInternals = !!(workspaceRegistry && workspaceRegistry.headers && workspaceRegistry.sessionPaths && typeof workspaceRegistry.replaceHeaderIndex === "function");
|
|
681
|
+
return {
|
|
682
|
+
persistence: handleApi ? "session-handle" : "legacy",
|
|
683
|
+
actions: {
|
|
684
|
+
read: action(legacyRead || handleApi, "\u5F53\u524D DSH \u672A\u63D0\u4F9B\u53EF\u8BC6\u522B\u7684\u4F1A\u8BDD\u8BFB\u53D6\u63A5\u53E3"),
|
|
685
|
+
archive: action(!!(workspaceRegistry && typeof workspaceRegistry.archiveSession === "function"), "\u5F53\u524D DSH \u672A\u63D0\u4F9B\u5F52\u6863\u63A5\u53E3"),
|
|
686
|
+
trash: action(legacyRead || handleApi, "\u5F53\u524D DSH \u65E0\u6CD5\u8BFB\u53D6\u4F1A\u8BDD\uFF0C\u4E0D\u80FD\u5B89\u5168\u79FB\u5165\u56DE\u6536\u7AD9"),
|
|
687
|
+
restoreTrash: action(true),
|
|
688
|
+
purge: action(!handleApi && legacyLocate, "\u5F53\u524D DSH \u7248\u672C\u5C1A\u672A\u63D0\u4F9B\u7ECF\u8FC7\u9A8C\u8BC1\u7684\u5B89\u5168\u6C38\u4E45\u5220\u9664\u80FD\u529B"),
|
|
689
|
+
move: action(!handleApi && legacyRead && legacyLocate && workspaceInternals, "\u5F53\u524D DSH \u7248\u672C\u5C1A\u672A\u63D0\u4F9B\u7ECF\u8FC7\u9A8C\u8BC1\u7684\u8DE8\u5DE5\u4F5C\u533A\u8FC1\u79FB\u80FD\u529B")
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
}
|
|
693
|
+
function requireCapability(capabilities, name2) {
|
|
694
|
+
const value = capabilities && capabilities.actions && capabilities.actions[name2];
|
|
695
|
+
if (value && value.available) return;
|
|
696
|
+
const error = new Error(value && value.reason || `\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301 ${name2}`);
|
|
697
|
+
error.status = 409;
|
|
698
|
+
error.code = "DSM_CAPABILITY_UNAVAILABLE";
|
|
699
|
+
throw error;
|
|
700
|
+
}
|
|
701
|
+
|
|
607
702
|
// src/index.js
|
|
608
703
|
var name = "dsh-sessions-manager";
|
|
609
704
|
var inject = ["webServer", "workspaceRegistry", "sessionPersistence", "sessionQuery", "storageDomain"];
|
|
@@ -690,6 +785,8 @@ function foldTitle(events) {
|
|
|
690
785
|
function apply(ctx) {
|
|
691
786
|
const w = ctx.workspaceRegistry;
|
|
692
787
|
const sp = ctx.sessionPersistence;
|
|
788
|
+
const persistence = createPersistenceAdapter(sp);
|
|
789
|
+
const capabilities = detectCapabilities({ persistence: sp, workspaceRegistry: w });
|
|
693
790
|
const sq = ctx.sessionQuery;
|
|
694
791
|
const dom = () => ctx.storageDomain.get("workspace");
|
|
695
792
|
const authorityTitleCache = /* @__PURE__ */ new Map();
|
|
@@ -814,7 +911,7 @@ function apply(ctx) {
|
|
|
814
911
|
}
|
|
815
912
|
if (!meta.title || !meta.cwd) {
|
|
816
913
|
try {
|
|
817
|
-
const r = await
|
|
914
|
+
const r = await persistence.readSession(id, 0);
|
|
818
915
|
if (r.meta) {
|
|
819
916
|
if (!meta.cwd) meta.cwd = r.meta.cwd || null;
|
|
820
917
|
if (!meta.createdAt) meta.createdAt = r.meta.createdAt || null;
|
|
@@ -830,23 +927,25 @@ function apply(ctx) {
|
|
|
830
927
|
async function collectUsage(preloadedHeaders) {
|
|
831
928
|
const sizeById = /* @__PURE__ */ new Map();
|
|
832
929
|
const mtimeById = /* @__PURE__ */ new Map();
|
|
833
|
-
let
|
|
834
|
-
if (Array.isArray(preloadedHeaders))
|
|
930
|
+
let entries = null;
|
|
931
|
+
if (Array.isArray(preloadedHeaders)) entries = preloadedHeaders;
|
|
835
932
|
else {
|
|
836
933
|
try {
|
|
837
|
-
|
|
934
|
+
entries = await persistence.listEntries();
|
|
838
935
|
} catch (e) {
|
|
839
|
-
|
|
936
|
+
entries = [];
|
|
840
937
|
}
|
|
841
938
|
}
|
|
842
|
-
if (!Array.isArray(
|
|
939
|
+
if (!Array.isArray(entries)) entries = [];
|
|
843
940
|
const CHUNK = 8;
|
|
844
|
-
for (let i = 0; i <
|
|
845
|
-
await Promise.all(
|
|
846
|
-
const
|
|
941
|
+
for (let i = 0; i < entries.length; i += CHUNK) {
|
|
942
|
+
await Promise.all(entries.slice(i, i + CHUNK).map(async (entry) => {
|
|
943
|
+
const header = entry && entry.header ? entry.header : entry;
|
|
944
|
+
const id = entry && entry.id != null ? String(entry.id) : header && header.id != null ? String(header.id) : null;
|
|
847
945
|
if (!id) return;
|
|
946
|
+
if (entry && Number.isFinite(entry.sizeBytes)) sizeById.set(id, Number(entry.sizeBytes));
|
|
848
947
|
try {
|
|
849
|
-
const loc =
|
|
948
|
+
const loc = persistence.locate(header);
|
|
850
949
|
if (!loc || typeof loc.path !== "string" || !loc.path) return;
|
|
851
950
|
const st = await stat(loc.path);
|
|
852
951
|
if (!st) return;
|
|
@@ -918,17 +1017,20 @@ function apply(ctx) {
|
|
|
918
1017
|
let cwd = null;
|
|
919
1018
|
let title = null;
|
|
920
1019
|
let removedPath = null;
|
|
1020
|
+
let persistenceEntry = null;
|
|
921
1021
|
try {
|
|
922
|
-
const
|
|
923
|
-
|
|
1022
|
+
const entries = await persistence.listEntries();
|
|
1023
|
+
const found = entries.find((entry) => entry.id === sid) || null;
|
|
1024
|
+
persistenceEntry = found;
|
|
1025
|
+
header = found ? found.header : null;
|
|
924
1026
|
if (header) {
|
|
925
|
-
const loc =
|
|
1027
|
+
const loc = persistence.locate(header);
|
|
926
1028
|
if (loc && typeof loc.path === "string") removedPath = loc.path;
|
|
927
1029
|
cwd = header.cwd || null;
|
|
928
1030
|
title = header.title || header.meta && header.meta.title || null;
|
|
929
1031
|
}
|
|
930
1032
|
if (!title) {
|
|
931
|
-
const r = await
|
|
1033
|
+
const r = await persistence.readSession(sid, 0);
|
|
932
1034
|
if (r && r.meta) {
|
|
933
1035
|
if (!cwd) cwd = r.meta.cwd;
|
|
934
1036
|
title = foldTitle(r.events);
|
|
@@ -949,7 +1051,7 @@ function apply(ctx) {
|
|
|
949
1051
|
cwd: cwd || null,
|
|
950
1052
|
header: header || null,
|
|
951
1053
|
originalPath: removedPath || null,
|
|
952
|
-
sizeBytes:
|
|
1054
|
+
sizeBytes: persistenceEntry && Number.isFinite(persistenceEntry.sizeBytes) ? persistenceEntry.sizeBytes : null,
|
|
953
1055
|
wasArchived: archived,
|
|
954
1056
|
deletedAt: Date.now()
|
|
955
1057
|
};
|
|
@@ -977,6 +1079,7 @@ function apply(ctx) {
|
|
|
977
1079
|
}
|
|
978
1080
|
async function purgeFromTrash(sid) {
|
|
979
1081
|
requireSessionId(sid);
|
|
1082
|
+
requireCapability(capabilities, "purge");
|
|
980
1083
|
let purged = false;
|
|
981
1084
|
await mutateTrash(async (store) => {
|
|
982
1085
|
const entry = store.items.find((t) => String(t.sessionId) === sid);
|
|
@@ -987,13 +1090,18 @@ function apply(ctx) {
|
|
|
987
1090
|
}
|
|
988
1091
|
let target = null;
|
|
989
1092
|
try {
|
|
990
|
-
const
|
|
991
|
-
const current =
|
|
992
|
-
const located = current &&
|
|
1093
|
+
const entries = await persistence.listEntries();
|
|
1094
|
+
const current = entries.find((entry2) => entry2.id === sid);
|
|
1095
|
+
const located = current && persistence.locate(current.header);
|
|
993
1096
|
if (located && typeof located.path === "string") target = located.path;
|
|
994
1097
|
} catch (e) {
|
|
995
1098
|
}
|
|
996
1099
|
if (!target && typeof entry.originalPath === "string") target = entry.originalPath;
|
|
1100
|
+
if (!target) {
|
|
1101
|
+
const error = new Error("\u65E0\u6CD5\u786E\u8BA4\u8BE5\u4F1A\u8BDD\u7684\u7269\u7406\u65E5\u5FD7\u4F4D\u7F6E\uFF0C\u5DF2\u505C\u6B62\u6C38\u4E45\u5220\u9664");
|
|
1102
|
+
error.status = 409;
|
|
1103
|
+
throw error;
|
|
1104
|
+
}
|
|
997
1105
|
const targetOwnsSession = target && (basename(dirname2(target)) === sid || basename(target).includes(sid));
|
|
998
1106
|
if (target && !targetOwnsSession) {
|
|
999
1107
|
const error = new Error("\u65E5\u5FD7\u8DEF\u5F84\u4E0E\u4F1A\u8BDD ID \u4E0D\u5339\u914D\uFF0C\u5DF2\u505C\u6B62\u6C38\u4E45\u5220\u9664");
|
|
@@ -1069,6 +1177,7 @@ function apply(ctx) {
|
|
|
1069
1177
|
return (await readTrashStore()).settings;
|
|
1070
1178
|
}
|
|
1071
1179
|
async function cleanupExpiredTrash() {
|
|
1180
|
+
if (!capabilities.actions.purge.available) return 0;
|
|
1072
1181
|
const store = await readTrashStore();
|
|
1073
1182
|
const days = store.settings.retentionDays;
|
|
1074
1183
|
if (!days) return 0;
|
|
@@ -1102,11 +1211,12 @@ function apply(ctx) {
|
|
|
1102
1211
|
return { canonical, entity: await w.create(canonical, basename(canonical) || "workspace") };
|
|
1103
1212
|
}
|
|
1104
1213
|
async function moveOne(sid, targetPath) {
|
|
1214
|
+
requireCapability(capabilities, "move");
|
|
1105
1215
|
const activeId = getActiveSessionId(ctx);
|
|
1106
1216
|
if (activeId != null && String(activeId) === String(sid)) {
|
|
1107
1217
|
throw new Error("\u8BE5\u4F1A\u8BDD\u5F53\u524D\u5904\u4E8E\u6253\u5F00\u72B6\u6001\uFF0C\u8BF7\u5148\u5207\u6362\u5230\u522B\u7684\u4F1A\u8BDD\u518D\u79FB\u52A8\u3002");
|
|
1108
1218
|
}
|
|
1109
|
-
const r = await
|
|
1219
|
+
const r = await persistence.readSession(sid, 0);
|
|
1110
1220
|
if (!r || !r.meta) throw new Error("\u65E0\u6CD5\u8BFB\u53D6\u8BE5\u4F1A\u8BDD\u7684\u65E5\u5FD7");
|
|
1111
1221
|
const meta = r.meta;
|
|
1112
1222
|
const events = r.events;
|
|
@@ -1165,7 +1275,7 @@ function apply(ctx) {
|
|
|
1165
1275
|
return null;
|
|
1166
1276
|
};
|
|
1167
1277
|
if (isOpen) {
|
|
1168
|
-
await relocateLog(meta, newHeader);
|
|
1278
|
+
if (!await relocateLog(meta, newHeader)) throw new Error("\u79FB\u52A8\u5931\u8D25\uFF1A\u65E0\u6CD5\u786E\u8BA4\u4F1A\u8BDD\u65E5\u5FD7\u5DF2\u8FC1\u79FB\u5230\u76EE\u6807\u5DE5\u4F5C\u533A");
|
|
1169
1279
|
try {
|
|
1170
1280
|
const st = sp.states && sp.states.get && sp.states.get(sid);
|
|
1171
1281
|
if (st && st.meta) st.meta = Object.assign({}, st.meta, { cwd: canonical });
|
|
@@ -1181,7 +1291,7 @@ function apply(ctx) {
|
|
|
1181
1291
|
oldPath = null;
|
|
1182
1292
|
}
|
|
1183
1293
|
if (typeof sp.create !== "function" || typeof sp.append !== "function") {
|
|
1184
|
-
await relocateLog(meta, newHeader);
|
|
1294
|
+
if (!await relocateLog(meta, newHeader)) throw new Error("\u79FB\u52A8\u5931\u8D25\uFF1A\u65E0\u6CD5\u786E\u8BA4\u4F1A\u8BDD\u65E5\u5FD7\u5DF2\u8FC1\u79FB\u5230\u76EE\u6807\u5DE5\u4F5C\u533A");
|
|
1185
1295
|
} else {
|
|
1186
1296
|
const backupPath = oldPath ? `${oldPath}.move-backup-${Date.now()}` : null;
|
|
1187
1297
|
if (backupPath) {
|
|
@@ -1202,7 +1312,7 @@ function apply(ctx) {
|
|
|
1202
1312
|
try {
|
|
1203
1313
|
await sp.create(newHeader);
|
|
1204
1314
|
await sp.append(sid, events);
|
|
1205
|
-
const check = await
|
|
1315
|
+
const check = await persistence.readSession(sid, 0);
|
|
1206
1316
|
if (!check || !check.meta || check.meta.cwd !== canonical) {
|
|
1207
1317
|
throw new Error("\u79FB\u52A8\u540E\u6821\u9A8C\u5931\u8D25\uFF1A\u4F1A\u8BDD\u5DE5\u4F5C\u76EE\u5F55\u672A\u6B63\u786E\u66F4\u65B0");
|
|
1208
1318
|
}
|
|
@@ -1215,7 +1325,7 @@ function apply(ctx) {
|
|
|
1215
1325
|
} catch (e) {
|
|
1216
1326
|
if (ALREADY_EXISTS_RE.test(String(e && e.message || e))) {
|
|
1217
1327
|
await restore();
|
|
1218
|
-
await relocateLog(meta, newHeader);
|
|
1328
|
+
if (!await relocateLog(meta, newHeader)) throw new Error("\u79FB\u52A8\u5931\u8D25\uFF1A\u65E0\u6CD5\u786E\u8BA4\u4F1A\u8BDD\u65E5\u5FD7\u5DF2\u8FC1\u79FB\u5230\u76EE\u6807\u5DE5\u4F5C\u533A");
|
|
1219
1329
|
} else {
|
|
1220
1330
|
await restore();
|
|
1221
1331
|
throw new Error("\u79FB\u52A8\u4F1A\u8BDD\u65E5\u5FD7\u5931\u8D25\uFF1A" + String(e && e.message || e));
|
|
@@ -1261,14 +1371,14 @@ function apply(ctx) {
|
|
|
1261
1371
|
async function reindexRegistry() {
|
|
1262
1372
|
const reg = w;
|
|
1263
1373
|
if (!reg || typeof reg.replaceHeaderIndex !== "function") return false;
|
|
1264
|
-
let
|
|
1374
|
+
let entries = null;
|
|
1265
1375
|
try {
|
|
1266
|
-
|
|
1376
|
+
entries = await persistence.listEntries();
|
|
1267
1377
|
} catch (e) {
|
|
1268
|
-
|
|
1378
|
+
entries = null;
|
|
1269
1379
|
}
|
|
1270
|
-
if (!
|
|
1271
|
-
await reg.replaceHeaderIndex(
|
|
1380
|
+
if (!entries || !Array.isArray(entries)) return false;
|
|
1381
|
+
await reg.replaceHeaderIndex(entries.map((entry) => entry.header));
|
|
1272
1382
|
if (typeof reg.rebuildEntities === "function") reg.rebuildEntities();
|
|
1273
1383
|
return true;
|
|
1274
1384
|
}
|
|
@@ -1304,17 +1414,17 @@ function apply(ctx) {
|
|
|
1304
1414
|
return out;
|
|
1305
1415
|
}
|
|
1306
1416
|
async function allSessionItems(opts = {}) {
|
|
1307
|
-
let
|
|
1417
|
+
let entries = [];
|
|
1308
1418
|
let headersOk = false;
|
|
1309
1419
|
try {
|
|
1310
|
-
|
|
1311
|
-
headersOk = Array.isArray(
|
|
1312
|
-
if (!headersOk)
|
|
1420
|
+
entries = await persistence.listEntries();
|
|
1421
|
+
headersOk = Array.isArray(entries);
|
|
1422
|
+
if (!headersOk) entries = [];
|
|
1313
1423
|
} catch (e) {
|
|
1314
|
-
|
|
1424
|
+
entries = [];
|
|
1315
1425
|
}
|
|
1316
1426
|
let live = ctx.get("sessions");
|
|
1317
|
-
const ids =
|
|
1427
|
+
const ids = entries.map((entry) => entry.id);
|
|
1318
1428
|
if (live) {
|
|
1319
1429
|
try {
|
|
1320
1430
|
live.list().forEach((s) => {
|
|
@@ -1339,7 +1449,7 @@ function apply(ctx) {
|
|
|
1339
1449
|
}
|
|
1340
1450
|
const currentArchived = new Set((await archivedState().catch(() => ({ archivedSessionIds: [] }))).archivedSessionIds || []);
|
|
1341
1451
|
const items = [];
|
|
1342
|
-
const usage = await collectUsage(
|
|
1452
|
+
const usage = await collectUsage(entries);
|
|
1343
1453
|
const statsById = new Map(visibleIds.map((id) => [id, { mtimeMs: usage.mtimeById.get(id), size: usage.sizeById.get(id) }]));
|
|
1344
1454
|
const { cached, missing } = metaCache.partition(visibleIds, statsById);
|
|
1345
1455
|
const persisted = await hydrateFromPersist(missing, statsById);
|
|
@@ -1405,14 +1515,14 @@ function apply(ctx) {
|
|
|
1405
1515
|
}
|
|
1406
1516
|
async function sidebarAuthority() {
|
|
1407
1517
|
const ids = [];
|
|
1408
|
-
let
|
|
1518
|
+
let entries = [];
|
|
1409
1519
|
try {
|
|
1410
|
-
|
|
1520
|
+
entries = await persistence.listEntries();
|
|
1411
1521
|
} catch (e) {
|
|
1412
|
-
|
|
1522
|
+
entries = [];
|
|
1413
1523
|
}
|
|
1414
|
-
if (!Array.isArray(
|
|
1415
|
-
for (const
|
|
1524
|
+
if (!Array.isArray(entries)) entries = [];
|
|
1525
|
+
for (const entry of entries) ids.push(entry.id);
|
|
1416
1526
|
const sessions = ctx.get("sessions");
|
|
1417
1527
|
try {
|
|
1418
1528
|
if (sessions) sessions.list().forEach((session) => {
|
|
@@ -1423,7 +1533,7 @@ function apply(ctx) {
|
|
|
1423
1533
|
}
|
|
1424
1534
|
const store = await readTrashStore();
|
|
1425
1535
|
if (ids.length) {
|
|
1426
|
-
const usage = await collectUsage(
|
|
1536
|
+
const usage = await collectUsage(entries);
|
|
1427
1537
|
const statsById = new Map(ids.map((id) => [id, { mtimeMs: usage.mtimeById.get(id), size: usage.sizeById.get(id) }]));
|
|
1428
1538
|
const { cached, missing } = metaCache.partition(ids, statsById);
|
|
1429
1539
|
const persisted = await hydrateFromPersist(missing, statsById);
|
|
@@ -1466,14 +1576,14 @@ function apply(ctx) {
|
|
|
1466
1576
|
events = [];
|
|
1467
1577
|
}
|
|
1468
1578
|
} else {
|
|
1469
|
-
const r = await
|
|
1579
|
+
const r = await persistence.readSession(sid, 0);
|
|
1470
1580
|
if (!r || !r.meta) throw new Error("\u627E\u4E0D\u5230\u8BE5\u4F1A\u8BDD\u7684\u8BB0\u5F55\uFF08\u4F1A\u8BDD\u4E0D\u5B58\u5728\uFF09");
|
|
1471
1581
|
meta = r.meta;
|
|
1472
1582
|
events = Array.isArray(r.events) ? r.events : [];
|
|
1473
1583
|
}
|
|
1474
1584
|
let sizeBytes = null;
|
|
1475
1585
|
try {
|
|
1476
|
-
const loc =
|
|
1586
|
+
const loc = persistence.locate(meta);
|
|
1477
1587
|
if (loc && typeof loc.path === "string" && loc.path) {
|
|
1478
1588
|
const st = await stat(loc.path);
|
|
1479
1589
|
if (st && typeof st.size === "number") sizeBytes = st.size;
|
|
@@ -1558,7 +1668,8 @@ function apply(ctx) {
|
|
|
1558
1668
|
const subagentSet = /* @__PURE__ */ new Set();
|
|
1559
1669
|
try {
|
|
1560
1670
|
if (typeof sp.list === "function") {
|
|
1561
|
-
for (const
|
|
1671
|
+
for (const entry of await persistence.listEntries()) {
|
|
1672
|
+
const h = entry.header;
|
|
1562
1673
|
if (String(h.parentSession) !== String(sid)) continue;
|
|
1563
1674
|
if (h.origin === "subagent") subagentSet.add(h.id);
|
|
1564
1675
|
else childrenSet.add(h.id);
|
|
@@ -1595,6 +1706,11 @@ function apply(ctx) {
|
|
|
1595
1706
|
authorityTitleCache.set(String(session.id), event.data.title);
|
|
1596
1707
|
}
|
|
1597
1708
|
}));
|
|
1709
|
+
disposers.push(ctx.webServer.register({
|
|
1710
|
+
kind: "exact",
|
|
1711
|
+
path: "/archived-sessions/capabilities",
|
|
1712
|
+
handler: async (req, res) => json(res, capabilities)
|
|
1713
|
+
}));
|
|
1598
1714
|
disposers.push(ctx.webServer.register({
|
|
1599
1715
|
kind: "exact",
|
|
1600
1716
|
path: "/archived-sessions/list",
|
|
@@ -1605,8 +1721,8 @@ function apply(ctx) {
|
|
|
1605
1721
|
let materialized = /* @__PURE__ */ new Set();
|
|
1606
1722
|
let live = ctx.get("sessions");
|
|
1607
1723
|
try {
|
|
1608
|
-
const
|
|
1609
|
-
materialized = new Set(
|
|
1724
|
+
const entries = await persistence.listEntries();
|
|
1725
|
+
materialized = new Set(entries.map((entry) => entry.id));
|
|
1610
1726
|
} catch (e) {
|
|
1611
1727
|
}
|
|
1612
1728
|
const trashStore = await readTrashStore();
|
|
@@ -1657,12 +1773,12 @@ function apply(ctx) {
|
|
|
1657
1773
|
try {
|
|
1658
1774
|
results.push({ sessionId: sid, ok: true, ...await restoreOne(sid) });
|
|
1659
1775
|
} catch (e) {
|
|
1660
|
-
results.push({ sessionId: sid, ok: false, error: String(e && e.message || e) });
|
|
1776
|
+
results.push({ sessionId: sid, ok: false, code: e && e.code, error: String(e && e.message || e) });
|
|
1661
1777
|
}
|
|
1662
1778
|
}
|
|
1663
1779
|
json(res, { ok: true, restored: results.filter((r) => r.ok).length, results });
|
|
1664
1780
|
} catch (e) {
|
|
1665
|
-
json(res, { ok: false, error: String(e && e.message || e) },
|
|
1781
|
+
json(res, { ok: false, code: e && e.code, error: String(e && e.message || e) }, errorStatus(e));
|
|
1666
1782
|
}
|
|
1667
1783
|
}
|
|
1668
1784
|
}));
|
|
@@ -1701,7 +1817,7 @@ function apply(ctx) {
|
|
|
1701
1817
|
}
|
|
1702
1818
|
json(res, { ok: true, deleted: results.filter((r) => r.ok).length, results });
|
|
1703
1819
|
} catch (e) {
|
|
1704
|
-
json(res, { ok: false, error: String(e && e.message || e) },
|
|
1820
|
+
json(res, { ok: false, code: e && e.code, error: String(e && e.message || e) }, errorStatus(e));
|
|
1705
1821
|
}
|
|
1706
1822
|
}
|
|
1707
1823
|
}));
|
|
@@ -1740,11 +1856,19 @@ function apply(ctx) {
|
|
|
1740
1856
|
try {
|
|
1741
1857
|
const items = await readTrash();
|
|
1742
1858
|
const results = await Promise.all(items.map(async (item) => {
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1859
|
+
if (typeof item.originalPath !== "string" || !item.originalPath) {
|
|
1860
|
+
return { sessionId: item.sessionId, status: "unverified", originalPath: null };
|
|
1861
|
+
}
|
|
1862
|
+
const exists = await stat(item.originalPath).then(() => true).catch(() => false);
|
|
1863
|
+
return { sessionId: item.sessionId, status: exists ? "ok" : "missing", originalPath: item.originalPath };
|
|
1746
1864
|
}));
|
|
1747
|
-
json(res, {
|
|
1865
|
+
json(res, {
|
|
1866
|
+
ok: true,
|
|
1867
|
+
healthy: results.filter((r) => r.status === "ok").length,
|
|
1868
|
+
missing: results.filter((r) => r.status === "missing").length,
|
|
1869
|
+
unverified: results.filter((r) => r.status === "unverified").length,
|
|
1870
|
+
results
|
|
1871
|
+
});
|
|
1748
1872
|
} catch (e) {
|
|
1749
1873
|
json(res, { ok: false, error: String(e && e.message || e) }, errorStatus(e));
|
|
1750
1874
|
}
|
|
@@ -1762,7 +1886,7 @@ function apply(ctx) {
|
|
|
1762
1886
|
metaCache.invalidate(sid);
|
|
1763
1887
|
json(res, out);
|
|
1764
1888
|
} catch (e) {
|
|
1765
|
-
json(res, { ok: false, error: String(e && e.message || e) },
|
|
1889
|
+
json(res, { ok: false, code: e && e.code, error: String(e && e.message || e) }, errorStatus(e));
|
|
1766
1890
|
}
|
|
1767
1891
|
}
|
|
1768
1892
|
}));
|
|
@@ -1780,7 +1904,7 @@ function apply(ctx) {
|
|
|
1780
1904
|
});
|
|
1781
1905
|
json(res, out);
|
|
1782
1906
|
} catch (e) {
|
|
1783
|
-
json(res, { ok: false, error: String(e && e.message || e) },
|
|
1907
|
+
json(res, { ok: false, code: e && e.code, error: String(e && e.message || e) }, errorStatus(e));
|
|
1784
1908
|
}
|
|
1785
1909
|
}
|
|
1786
1910
|
}));
|
|
@@ -1805,7 +1929,7 @@ function apply(ctx) {
|
|
|
1805
1929
|
}
|
|
1806
1930
|
json(res, { ok: true, purged: results.filter((r) => r.ok).length, results });
|
|
1807
1931
|
} catch (e) {
|
|
1808
|
-
json(res, { ok: false, error: String(e && e.message || e) },
|
|
1932
|
+
json(res, { ok: false, code: e && e.code, error: String(e && e.message || e) }, errorStatus(e));
|
|
1809
1933
|
}
|
|
1810
1934
|
}
|
|
1811
1935
|
}));
|
|
@@ -1847,7 +1971,7 @@ function apply(ctx) {
|
|
|
1847
1971
|
const url = new URL(req.url, "http://localhost");
|
|
1848
1972
|
const sid = url.searchParams.get("sessionId");
|
|
1849
1973
|
requireSessionId(sid);
|
|
1850
|
-
const r = await
|
|
1974
|
+
const r = await persistence.readSession(sid, 0);
|
|
1851
1975
|
if (!r || !r.meta) {
|
|
1852
1976
|
const error = new Error("\u65E0\u6CD5\u8BFB\u53D6\u8BE5\u4F1A\u8BDD\u7684\u65E5\u5FD7");
|
|
1853
1977
|
error.status = 404;
|
|
@@ -1905,7 +2029,7 @@ function apply(ctx) {
|
|
|
1905
2029
|
}
|
|
1906
2030
|
json(res, { sessionId: sid, ...moved });
|
|
1907
2031
|
} catch (e) {
|
|
1908
|
-
json(res, { ok: false, error: String(e && e.message || e) },
|
|
2032
|
+
json(res, { ok: false, code: e && e.code, error: String(e && e.message || e) }, errorStatus(e));
|
|
1909
2033
|
}
|
|
1910
2034
|
}
|
|
1911
2035
|
}));
|