codesesh 0.9.1 → 0.11.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.md +2 -1
- package/dist/{chunk-5UOLRSFH.js → chunk-BIXOP5QX.js} +2103 -2145
- package/dist/chunk-BIXOP5QX.js.map +1 -0
- package/dist/{dist-VEIV33FR.js → dist-T737I76S.js} +30 -2
- package/dist/index.js +469 -636
- package/dist/index.js.map +1 -1
- package/dist/scan-refresh-worker.js +7 -13
- package/dist/scan-refresh-worker.js.map +1 -1
- package/dist/search-index-worker.js +1 -1
- package/dist/smart-tag-worker.js +1 -1
- package/dist/web/assets/index-DlZEB-Op.css +2 -0
- package/dist/web/assets/index-O6YSX0s1.js +113 -0
- package/dist/web/assets/vendor-CR3FdUHs.js +40 -0
- package/dist/web/icon/agent/zcode.svg +1 -0
- package/dist/web/index.html +3 -3
- package/package.json +4 -3
- package/dist/chunk-5UOLRSFH.js.map +0 -1
- package/dist/web/assets/index-BHmQBGNx.css +0 -2
- package/dist/web/assets/index-CT4gLIAq.js +0 -111
- package/dist/web/assets/vendor-Da5am_Td.js +0 -40
- /package/dist/{dist-VEIV33FR.js.map → dist-T737I76S.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
3
|
BookmarkStorageUnavailableError,
|
|
4
|
+
FileSystemSessionSource,
|
|
5
|
+
attachMissingProjectIdentities,
|
|
6
|
+
buildAgentCacheMeta,
|
|
7
|
+
buildDashboard,
|
|
4
8
|
classifySessionTags,
|
|
5
9
|
computeIdentity,
|
|
10
|
+
computeSessionDiff,
|
|
6
11
|
createProjectScopeMatcher,
|
|
7
12
|
createRegisteredAgents,
|
|
8
13
|
deleteBookmark,
|
|
@@ -10,7 +15,10 @@ import {
|
|
|
10
15
|
filterSessions,
|
|
11
16
|
getAgentInfoMap,
|
|
12
17
|
getCursorDataPath,
|
|
18
|
+
getSessionActivityTime,
|
|
19
|
+
getSessionAgentName,
|
|
13
20
|
getSmartTagSourceTimestamp,
|
|
21
|
+
getTotalTokens,
|
|
14
22
|
importBookmarks,
|
|
15
23
|
isAgentCacheInitialized,
|
|
16
24
|
listBookmarks,
|
|
@@ -28,8 +36,11 @@ import {
|
|
|
28
36
|
scanSessions,
|
|
29
37
|
searchFileActivitySessions,
|
|
30
38
|
searchSessions,
|
|
39
|
+
sessionSignature,
|
|
40
|
+
sortSessions,
|
|
41
|
+
startOfLocalDay,
|
|
31
42
|
upsertBookmark
|
|
32
|
-
} from "./chunk-
|
|
43
|
+
} from "./chunk-BIXOP5QX.js";
|
|
33
44
|
|
|
34
45
|
// src/index.ts
|
|
35
46
|
import { defineCommand, runMain } from "citty";
|
|
@@ -195,7 +206,6 @@ function logSearchIndexSync(context, result, data = {}) {
|
|
|
195
206
|
}
|
|
196
207
|
|
|
197
208
|
// src/api/handlers.ts
|
|
198
|
-
var DASHBOARD_RECENT_LIMIT = 10;
|
|
199
209
|
function isRecord(value) {
|
|
200
210
|
return typeof value === "object" && value !== null;
|
|
201
211
|
}
|
|
@@ -219,15 +229,6 @@ function parseBookmarkPayload(value) {
|
|
|
219
229
|
stats: value.stats
|
|
220
230
|
};
|
|
221
231
|
}
|
|
222
|
-
function getTotalTokens(stats) {
|
|
223
|
-
return stats.total_tokens ?? stats.total_input_tokens + stats.total_output_tokens;
|
|
224
|
-
}
|
|
225
|
-
function getSessionAgentName(session) {
|
|
226
|
-
return session.slug.split("/")[0]?.toLowerCase() || "unknown";
|
|
227
|
-
}
|
|
228
|
-
function getSessionActivityTime(session) {
|
|
229
|
-
return session.time_updated ?? session.time_created;
|
|
230
|
-
}
|
|
231
232
|
function parseDateParam(value, fallback) {
|
|
232
233
|
if (value == null) return fallback;
|
|
233
234
|
const ts = new Date(value).getTime();
|
|
@@ -682,18 +683,6 @@ function handleDeleteBookmark(c) {
|
|
|
682
683
|
throw error;
|
|
683
684
|
}
|
|
684
685
|
}
|
|
685
|
-
function toLocalDateKey(ts) {
|
|
686
|
-
const d = new Date(ts);
|
|
687
|
-
const year = d.getFullYear();
|
|
688
|
-
const month = `${d.getMonth() + 1}`.padStart(2, "0");
|
|
689
|
-
const day = `${d.getDate()}`.padStart(2, "0");
|
|
690
|
-
return `${year}-${month}-${day}`;
|
|
691
|
-
}
|
|
692
|
-
function startOfLocalDay(ts) {
|
|
693
|
-
const d = new Date(ts);
|
|
694
|
-
d.setHours(0, 0, 0, 0);
|
|
695
|
-
return d.getTime();
|
|
696
|
-
}
|
|
697
686
|
function resolveDashboardWindow(defaults, queryDays, queryFrom, queryTo) {
|
|
698
687
|
const now = Date.now();
|
|
699
688
|
const toTs = parseDateParam(queryTo, defaults.to) ?? now;
|
|
@@ -732,138 +721,17 @@ function handleGetDashboard(c, scanSource, defaults = {}) {
|
|
|
732
721
|
projectKind: optionalQueryValue(c.req.query("projectKind")),
|
|
733
722
|
projectKey: optionalQueryValue(c.req.query("projectKey"))
|
|
734
723
|
};
|
|
735
|
-
const agentMetrics = /* @__PURE__ */ new Map();
|
|
736
|
-
const agentMetricKeyByName = /* @__PURE__ */ new Map();
|
|
737
|
-
for (const name of Object.keys(scanResult.byAgent)) {
|
|
738
|
-
if (scope.agent && name.toLowerCase() !== scope.agent) continue;
|
|
739
|
-
agentMetrics.set(name, { sessions: 0, messages: 0, tokens: 0 });
|
|
740
|
-
agentMetricKeyByName.set(name.toLowerCase(), name);
|
|
741
|
-
}
|
|
742
724
|
const agentInfo = getAgentInfoMap({});
|
|
743
725
|
const agentInfoMap = new Map(agentInfo.map((a) => [a.name, a]));
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
const recentCandidates = [];
|
|
751
|
-
const modelAgg = /* @__PURE__ */ new Map();
|
|
752
|
-
const dailyMap = /* @__PURE__ */ new Map();
|
|
753
|
-
const dailyTokenMap = /* @__PURE__ */ new Map();
|
|
754
|
-
if (from != null) {
|
|
755
|
-
const bucketStart = startOfLocalDay(from);
|
|
756
|
-
const bucketDays = Math.floor((startOfLocalDay(to) - bucketStart) / 864e5) + 1;
|
|
757
|
-
for (let i = 0; i < bucketDays; i += 1) {
|
|
758
|
-
const ts = bucketStart + i * 864e5;
|
|
759
|
-
const key = toLocalDateKey(ts);
|
|
760
|
-
dailyMap.set(key, { date: key, sessions: 0, messages: 0 });
|
|
761
|
-
dailyTokenMap.set(key, { date: key, input: 0, output: 0, cache_read: 0, cache_create: 0 });
|
|
762
|
-
}
|
|
763
|
-
}
|
|
764
|
-
for (const session of scanResult.sessions) {
|
|
765
|
-
const agentName = getSessionAgentName(session);
|
|
766
|
-
if (scope.agent && agentName !== scope.agent) continue;
|
|
767
|
-
if (scope.projectKey) {
|
|
768
|
-
const identity = session.project_identity;
|
|
769
|
-
if (!identity || identity.key !== scope.projectKey) continue;
|
|
770
|
-
if (scope.projectKind && identity.kind !== scope.projectKind) continue;
|
|
771
|
-
}
|
|
772
|
-
const activity = getSessionActivityTime(session);
|
|
773
|
-
if (from != null && activity < from) continue;
|
|
774
|
-
if (activity > to) continue;
|
|
775
|
-
const messageCount = session.stats.message_count;
|
|
776
|
-
const sessionTokens = getTotalTokens(session.stats);
|
|
777
|
-
totalSessions += 1;
|
|
778
|
-
totalMessages += messageCount;
|
|
779
|
-
totalTokens += sessionTokens;
|
|
780
|
-
totalCost += session.stats.total_cost ?? 0;
|
|
781
|
-
if (session.stats.cost_source === "estimated") hasEstimatedCost = true;
|
|
782
|
-
if (activity > latestActivity) latestActivity = activity;
|
|
783
|
-
const metricKey = agentMetricKeyByName.get(agentName);
|
|
784
|
-
if (metricKey) {
|
|
785
|
-
const metric = agentMetrics.get(metricKey);
|
|
786
|
-
metric.sessions += 1;
|
|
787
|
-
metric.messages += messageCount;
|
|
788
|
-
metric.tokens += sessionTokens;
|
|
789
|
-
}
|
|
790
|
-
const key = toLocalDateKey(activity);
|
|
791
|
-
let bucket = dailyMap.get(key);
|
|
792
|
-
if (!bucket) {
|
|
793
|
-
bucket = { date: key, sessions: 0, messages: 0 };
|
|
794
|
-
dailyMap.set(key, bucket);
|
|
795
|
-
}
|
|
796
|
-
bucket.sessions += 1;
|
|
797
|
-
bucket.messages += messageCount;
|
|
798
|
-
let tokenBucket = dailyTokenMap.get(key);
|
|
799
|
-
if (!tokenBucket) {
|
|
800
|
-
tokenBucket = { date: key, input: 0, output: 0, cache_read: 0, cache_create: 0 };
|
|
801
|
-
dailyTokenMap.set(key, tokenBucket);
|
|
802
|
-
}
|
|
803
|
-
const cacheRead = session.stats.total_cache_read_tokens ?? 0;
|
|
804
|
-
const cacheCreate = session.stats.total_cache_create_tokens ?? 0;
|
|
805
|
-
const pureInput = session.stats.total_input_tokens - cacheRead - cacheCreate;
|
|
806
|
-
tokenBucket.input += Math.max(0, pureInput);
|
|
807
|
-
tokenBucket.output += session.stats.total_output_tokens;
|
|
808
|
-
tokenBucket.cache_read += cacheRead;
|
|
809
|
-
tokenBucket.cache_create += cacheCreate;
|
|
810
|
-
if (session.model_usage) {
|
|
811
|
-
for (const [model, tokens] of Object.entries(session.model_usage)) {
|
|
812
|
-
const entry = modelAgg.get(model);
|
|
813
|
-
if (entry) {
|
|
814
|
-
entry.tokens += tokens;
|
|
815
|
-
entry.sessions += 1;
|
|
816
|
-
} else {
|
|
817
|
-
modelAgg.set(model, { tokens, sessions: 1 });
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
let recentIndex = recentCandidates.length;
|
|
822
|
-
for (let i = 0; i < recentCandidates.length; i += 1) {
|
|
823
|
-
if (activity > recentCandidates[i].activity) {
|
|
824
|
-
recentIndex = i;
|
|
825
|
-
break;
|
|
826
|
-
}
|
|
827
|
-
}
|
|
828
|
-
if (recentIndex < DASHBOARD_RECENT_LIMIT) {
|
|
829
|
-
recentCandidates.splice(recentIndex, 0, { session, activity });
|
|
830
|
-
if (recentCandidates.length > DASHBOARD_RECENT_LIMIT) recentCandidates.pop();
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
const perAgent = [...agentMetrics.entries()].map(([name, metrics]) => {
|
|
834
|
-
const info = agentInfoMap.get(name);
|
|
835
|
-
return {
|
|
836
|
-
name,
|
|
837
|
-
displayName: info?.displayName ?? name,
|
|
838
|
-
icon: info?.icon ?? "",
|
|
839
|
-
sessions: metrics.sessions,
|
|
840
|
-
messages: metrics.messages,
|
|
841
|
-
tokens: metrics.tokens
|
|
842
|
-
};
|
|
843
|
-
}).filter((item) => item.sessions > 0).sort((a, b) => b.sessions - a.sessions);
|
|
844
|
-
const dailyActivity = [...dailyMap.values()].sort((a, b) => a.date.localeCompare(b.date));
|
|
845
|
-
const dailyTokenActivity = [...dailyTokenMap.values()].sort(
|
|
846
|
-
(a, b) => a.date.localeCompare(b.date)
|
|
847
|
-
);
|
|
848
|
-
const modelDistribution = [...modelAgg.entries()].map(([model, { tokens, sessions: count }]) => ({ model, tokens, sessions: count })).sort((a, b) => b.tokens - a.tokens);
|
|
849
|
-
const recentSessions = recentCandidates.map(({ session }) => {
|
|
850
|
-
const agentKey = getSessionAgentName(session);
|
|
851
|
-
return { ...session, agentName: agentKey };
|
|
726
|
+
const aggregate = buildDashboard(scanResult.sessions, {
|
|
727
|
+
byAgentNames: Object.keys(scanResult.byAgent),
|
|
728
|
+
scope,
|
|
729
|
+
from,
|
|
730
|
+
to,
|
|
731
|
+
agentInfoMap
|
|
852
732
|
});
|
|
853
733
|
const data = {
|
|
854
|
-
|
|
855
|
-
sessions: totalSessions,
|
|
856
|
-
messages: totalMessages,
|
|
857
|
-
tokens: totalTokens,
|
|
858
|
-
cost: totalCost,
|
|
859
|
-
cost_source: totalCost > 0 ? hasEstimatedCost ? "estimated" : "recorded" : void 0,
|
|
860
|
-
latestActivity: latestActivity || void 0
|
|
861
|
-
},
|
|
862
|
-
perAgent,
|
|
863
|
-
dailyActivity,
|
|
864
|
-
dailyTokenActivity,
|
|
865
|
-
modelDistribution,
|
|
866
|
-
recentSessions,
|
|
734
|
+
...aggregate,
|
|
867
735
|
recentFileActivities: listFileActivity({
|
|
868
736
|
agent: scope.agent,
|
|
869
737
|
projectKey: scope.projectKey,
|
|
@@ -1078,112 +946,15 @@ async function createServer(port, store, options = {}) {
|
|
|
1078
946
|
}
|
|
1079
947
|
|
|
1080
948
|
// src/live-scan.ts
|
|
1081
|
-
import { existsSync as
|
|
1082
|
-
import { dirname as dirname2, isAbsolute, join as join2, relative, resolve as resolve2 } from "path";
|
|
949
|
+
import { existsSync as existsSync4 } from "fs";
|
|
1083
950
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1084
951
|
import { Worker } from "worker_threads";
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
952
|
+
|
|
953
|
+
// src/session-watcher.ts
|
|
954
|
+
import { existsSync as existsSync3, readdirSync as readdirSync2, statSync as statSync2, watch } from "fs";
|
|
955
|
+
import { dirname as dirname2, isAbsolute, join as join2, relative, resolve as resolve2 } from "path";
|
|
1088
956
|
var WRITE_STABILITY_THRESHOLD_MS = 250;
|
|
1089
957
|
var WRITE_STABILITY_POLL_MS = 100;
|
|
1090
|
-
var NEW_SESSION_EVENT_WINDOW_MS = 250;
|
|
1091
|
-
var SEARCH_INDEX_BULK_PENDING_PATH_THRESHOLD = 100;
|
|
1092
|
-
function sortSessions(sessions) {
|
|
1093
|
-
return [...sessions].sort(
|
|
1094
|
-
(a, b) => (b.time_updated ?? b.time_created) - (a.time_updated ?? a.time_created)
|
|
1095
|
-
);
|
|
1096
|
-
}
|
|
1097
|
-
function sessionSignature(session) {
|
|
1098
|
-
return JSON.stringify([
|
|
1099
|
-
session.title,
|
|
1100
|
-
session.directory,
|
|
1101
|
-
session.time_created,
|
|
1102
|
-
session.time_updated ?? session.time_created,
|
|
1103
|
-
session.stats.message_count,
|
|
1104
|
-
session.stats.total_input_tokens,
|
|
1105
|
-
session.stats.total_output_tokens,
|
|
1106
|
-
session.stats.total_cost,
|
|
1107
|
-
session.stats.total_tokens ?? 0
|
|
1108
|
-
]);
|
|
1109
|
-
}
|
|
1110
|
-
function buildAgentCacheMeta(agent, sessionIds) {
|
|
1111
|
-
const metaMap = agent.getSessionMetaMap?.();
|
|
1112
|
-
const meta = {};
|
|
1113
|
-
if (!metaMap) return meta;
|
|
1114
|
-
for (const [id, data] of metaMap.entries()) {
|
|
1115
|
-
if (sessionIds && !sessionIds.has(id)) continue;
|
|
1116
|
-
meta[id] = { id, ...data };
|
|
1117
|
-
}
|
|
1118
|
-
return meta;
|
|
1119
|
-
}
|
|
1120
|
-
function attachMissingProjectIdentities(sessions) {
|
|
1121
|
-
const identities = /* @__PURE__ */ new Map();
|
|
1122
|
-
return sessions.map((session) => {
|
|
1123
|
-
if (session.project_identity) return session;
|
|
1124
|
-
const directory = session.directory || "";
|
|
1125
|
-
let identity = identities.get(directory);
|
|
1126
|
-
if (!identity) {
|
|
1127
|
-
identity = computeIdentity(directory, realFs);
|
|
1128
|
-
identities.set(directory, identity);
|
|
1129
|
-
}
|
|
1130
|
-
return { ...session, project_identity: identity };
|
|
1131
|
-
});
|
|
1132
|
-
}
|
|
1133
|
-
function buildRefreshDiff(agentName, previousSessions, nextSessions, candidateChangedIds = []) {
|
|
1134
|
-
const previousMap = new Map(previousSessions.map((session) => [session.id, session]));
|
|
1135
|
-
const nextMap = new Map(nextSessions.map((session) => [session.id, session]));
|
|
1136
|
-
const candidateChangedIdSet = new Set(candidateChangedIds);
|
|
1137
|
-
const changedSessions = [];
|
|
1138
|
-
const removedSessionIds = [];
|
|
1139
|
-
let newSessions = 0;
|
|
1140
|
-
let updatedSessions = 0;
|
|
1141
|
-
let removedSessions = 0;
|
|
1142
|
-
nextSessions.forEach((session, index) => {
|
|
1143
|
-
const id = session.id;
|
|
1144
|
-
const previous = previousMap.get(id);
|
|
1145
|
-
if (!previous) {
|
|
1146
|
-
newSessions += 1;
|
|
1147
|
-
changedSessions.push({ session, sortIndex: index });
|
|
1148
|
-
return;
|
|
1149
|
-
}
|
|
1150
|
-
const hasSignatureChange = sessionSignature(previous) !== sessionSignature(session);
|
|
1151
|
-
const hasContentChange = candidateChangedIdSet.has(id);
|
|
1152
|
-
if (hasSignatureChange || hasContentChange) {
|
|
1153
|
-
updatedSessions += 1;
|
|
1154
|
-
}
|
|
1155
|
-
if (hasContentChange || hasSignatureChange) {
|
|
1156
|
-
changedSessions.push({ session, sortIndex: index });
|
|
1157
|
-
}
|
|
1158
|
-
});
|
|
1159
|
-
for (const id of previousMap.keys()) {
|
|
1160
|
-
if (!nextMap.has(id)) {
|
|
1161
|
-
removedSessions += 1;
|
|
1162
|
-
removedSessionIds.push(id);
|
|
1163
|
-
}
|
|
1164
|
-
}
|
|
1165
|
-
if (newSessions === 0 && updatedSessions === 0 && removedSessions === 0) {
|
|
1166
|
-
return { event: null, changedSessions, removedSessionIds };
|
|
1167
|
-
}
|
|
1168
|
-
return {
|
|
1169
|
-
changedSessions,
|
|
1170
|
-
removedSessionIds,
|
|
1171
|
-
event: {
|
|
1172
|
-
type: "sessions-updated",
|
|
1173
|
-
changedAgents: [agentName],
|
|
1174
|
-
newSessions,
|
|
1175
|
-
updatedSessions,
|
|
1176
|
-
removedSessions,
|
|
1177
|
-
totalSessions: nextSessions.length,
|
|
1178
|
-
timestamp: Date.now(),
|
|
1179
|
-
changedSessionHeads: changedSessions.map(({ session }) => ({ agentName, session })),
|
|
1180
|
-
removedSessionRefs: removedSessionIds.map((sessionId) => ({ agentName, sessionId }))
|
|
1181
|
-
}
|
|
1182
|
-
};
|
|
1183
|
-
}
|
|
1184
|
-
function restoreAgentCacheMeta(agent, meta) {
|
|
1185
|
-
agent.setSessionMetaMap?.(new Map(Object.entries(meta)));
|
|
1186
|
-
}
|
|
1187
958
|
function toAbsolutePath(path) {
|
|
1188
959
|
return isAbsolute(path) ? path : resolve2(path);
|
|
1189
960
|
}
|
|
@@ -1225,36 +996,6 @@ function isSameOrChildPath(parentPath, childPath) {
|
|
|
1225
996
|
function isRelatedPath(changedPath, targetPath) {
|
|
1226
997
|
return isSameOrChildPath(targetPath, changedPath) || isSameOrChildPath(changedPath, targetPath);
|
|
1227
998
|
}
|
|
1228
|
-
function mergeEvents(previous, next) {
|
|
1229
|
-
const changedSessionHeads = /* @__PURE__ */ new Map();
|
|
1230
|
-
const removedSessionRefs = /* @__PURE__ */ new Map();
|
|
1231
|
-
const sessionKey = (agentName, sessionId) => `${agentName}\0${sessionId}`;
|
|
1232
|
-
const addChanged = (item) => {
|
|
1233
|
-
const key = sessionKey(item.agentName, item.session.id);
|
|
1234
|
-
removedSessionRefs.delete(key);
|
|
1235
|
-
changedSessionHeads.set(key, item);
|
|
1236
|
-
};
|
|
1237
|
-
const addRemoved = (item) => {
|
|
1238
|
-
const key = sessionKey(item.agentName, item.sessionId);
|
|
1239
|
-
changedSessionHeads.delete(key);
|
|
1240
|
-
removedSessionRefs.set(key, item);
|
|
1241
|
-
};
|
|
1242
|
-
for (const item of previous.changedSessionHeads) addChanged(item);
|
|
1243
|
-
for (const item of previous.removedSessionRefs) addRemoved(item);
|
|
1244
|
-
for (const item of next.changedSessionHeads) addChanged(item);
|
|
1245
|
-
for (const item of next.removedSessionRefs) addRemoved(item);
|
|
1246
|
-
return {
|
|
1247
|
-
type: "sessions-updated",
|
|
1248
|
-
changedAgents: Array.from(/* @__PURE__ */ new Set([...previous.changedAgents, ...next.changedAgents])),
|
|
1249
|
-
newSessions: previous.newSessions + next.newSessions,
|
|
1250
|
-
updatedSessions: previous.updatedSessions + next.updatedSessions,
|
|
1251
|
-
removedSessions: previous.removedSessions + next.removedSessions,
|
|
1252
|
-
totalSessions: next.totalSessions,
|
|
1253
|
-
timestamp: next.timestamp,
|
|
1254
|
-
changedSessionHeads: [...changedSessionHeads.values()],
|
|
1255
|
-
removedSessionRefs: [...removedSessionRefs.values()]
|
|
1256
|
-
};
|
|
1257
|
-
}
|
|
1258
999
|
function mergeScopes(target, scopes) {
|
|
1259
1000
|
for (const scope of scopes) {
|
|
1260
1001
|
if (!target.some(
|
|
@@ -1308,169 +1049,452 @@ function resolveAgentWatchTargets(agentName) {
|
|
|
1308
1049
|
{ root: roots.opencodeRoot, path: join2(roots.opencodeRoot, "opencode.db") },
|
|
1309
1050
|
{ root: "data/opencode", path: "data/opencode/opencode.db" }
|
|
1310
1051
|
];
|
|
1052
|
+
case "zcode":
|
|
1053
|
+
return roots.zcodeRoot ? [{ root: roots.zcodeRoot, path: join2(roots.zcodeRoot, "cli", "db", "db.sqlite") }] : [];
|
|
1311
1054
|
default:
|
|
1312
1055
|
return [];
|
|
1313
1056
|
}
|
|
1314
1057
|
}
|
|
1315
|
-
var
|
|
1316
|
-
constructor(watchEnabled = true, scanOptions = {}, startupScanOptions = {}, storeOptions = {}) {
|
|
1317
|
-
this.watchEnabled = watchEnabled;
|
|
1318
|
-
this.scanOptions = scanOptions;
|
|
1319
|
-
this.startupScanOptions = startupScanOptions;
|
|
1320
|
-
this.storeOptions = storeOptions;
|
|
1321
|
-
}
|
|
1322
|
-
watchEnabled;
|
|
1323
|
-
scanOptions;
|
|
1324
|
-
startupScanOptions;
|
|
1325
|
-
storeOptions;
|
|
1326
|
-
agents = [];
|
|
1327
|
-
byAgent = {};
|
|
1328
|
-
sessions = [];
|
|
1329
|
-
listeners = /* @__PURE__ */ new Set();
|
|
1330
|
-
scanStatusListeners = /* @__PURE__ */ new Set();
|
|
1331
|
-
scanStatus = {
|
|
1332
|
-
active: false,
|
|
1333
|
-
phase: "idle",
|
|
1334
|
-
pendingAgents: [],
|
|
1335
|
-
scanningAgents: [],
|
|
1336
|
-
completedAgents: [],
|
|
1337
|
-
agentStatuses: {},
|
|
1338
|
-
totalAgents: 0,
|
|
1339
|
-
updatedAt: Date.now()
|
|
1340
|
-
};
|
|
1341
|
-
refreshTimers = /* @__PURE__ */ new Map();
|
|
1342
|
-
refreshTimestamps = /* @__PURE__ */ new Map();
|
|
1343
|
-
refreshInFlight = /* @__PURE__ */ new Set();
|
|
1344
|
-
pendingRefreshes = /* @__PURE__ */ new Set();
|
|
1345
|
-
pendingRefreshPathCounts = /* @__PURE__ */ new Map();
|
|
1058
|
+
var SessionWatcher = class {
|
|
1346
1059
|
watchers = [];
|
|
1347
1060
|
fallbackWatchScopes = /* @__PURE__ */ new Map();
|
|
1348
1061
|
stablePaths = /* @__PURE__ */ new Map();
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
pendingSearchIndexJobs = [];
|
|
1354
|
-
shuttingDown = false;
|
|
1355
|
-
async initialize() {
|
|
1356
|
-
const startedAt = performance.now();
|
|
1357
|
-
const deferInitialRefresh = this.storeOptions.deferInitialRefresh === true;
|
|
1358
|
-
appLogger.info("scan.initial.start", {
|
|
1359
|
-
watch_enabled: this.watchEnabled,
|
|
1360
|
-
agents: this.scanOptions.agents,
|
|
1361
|
-
use_cache: this.scanOptions.useCache ?? true,
|
|
1362
|
-
startup_from: this.startupScanOptions.from,
|
|
1363
|
-
startup_to: this.startupScanOptions.to,
|
|
1364
|
-
deferred: deferInitialRefresh || void 0
|
|
1365
|
-
});
|
|
1366
|
-
const initialResult = await scanSessions({
|
|
1367
|
-
...this.scanOptions,
|
|
1368
|
-
...deferInitialRefresh ? this.startupScanOptions : {},
|
|
1369
|
-
useCache: this.scanOptions.useCache ?? true,
|
|
1370
|
-
smartRefresh: false,
|
|
1371
|
-
cacheOnly: deferInitialRefresh,
|
|
1372
|
-
writeCache: deferInitialRefresh ? false : this.scanOptions.writeCache,
|
|
1373
|
-
smartTagWorkerUrl: this.getSmartTagWorkerUrl() ?? void 0,
|
|
1374
|
-
includeSmartTags: deferInitialRefresh ? false : void 0
|
|
1375
|
-
});
|
|
1376
|
-
this.applyScanResult(initialResult);
|
|
1377
|
-
const indexStartedAt = performance.now();
|
|
1378
|
-
if (!deferInitialRefresh) {
|
|
1379
|
-
await this.enqueueSearchIndexJobs(
|
|
1380
|
-
"scan.initial",
|
|
1381
|
-
this.buildFullSearchIndexJobs("scan.initial")
|
|
1382
|
-
);
|
|
1383
|
-
}
|
|
1384
|
-
const indexDuration = performance.now() - indexStartedAt;
|
|
1385
|
-
appLogger.info("scan.initial.done", {
|
|
1386
|
-
duration_ms: Math.round(performance.now() - startedAt),
|
|
1387
|
-
index_ms: deferInitialRefresh ? void 0 : Math.round(indexDuration),
|
|
1388
|
-
deferred: deferInitialRefresh || void 0,
|
|
1389
|
-
sessions: this.sessions.length,
|
|
1390
|
-
agents: Object.fromEntries(
|
|
1391
|
-
Object.entries(this.byAgent).map(([key, value]) => [key, value.length])
|
|
1392
|
-
),
|
|
1393
|
-
agent_timings: initialResult.timings ? Object.fromEntries(
|
|
1394
|
-
Object.entries(initialResult.timings).map(([name, t]) => [
|
|
1395
|
-
name,
|
|
1396
|
-
{
|
|
1397
|
-
total_ms: Math.round(t.total),
|
|
1398
|
-
cache_load_ms: t.cacheLoad != null ? Math.round(t.cacheLoad) : void 0,
|
|
1399
|
-
check_changes_ms: t.checkChanges != null ? Math.round(t.checkChanges) : void 0,
|
|
1400
|
-
scan_ms: t.scan != null ? Math.round(t.scan) : void 0,
|
|
1401
|
-
identity_ms: t.identity != null ? Math.round(t.identity) : void 0,
|
|
1402
|
-
tags_ms: t.tags != null ? Math.round(t.tags) : void 0
|
|
1403
|
-
}
|
|
1404
|
-
])
|
|
1405
|
-
) : void 0
|
|
1406
|
-
});
|
|
1407
|
-
if (this.watchEnabled) {
|
|
1408
|
-
this.startWatching();
|
|
1409
|
-
}
|
|
1410
|
-
}
|
|
1411
|
-
startBackgroundRefresh() {
|
|
1412
|
-
if (this.backgroundRefreshTimer) {
|
|
1413
|
-
return;
|
|
1414
|
-
}
|
|
1415
|
-
const agentNames = this.agents.map((agent) => agent.name);
|
|
1416
|
-
this.startScanBatch(agentNames, "scanning");
|
|
1417
|
-
this.backgroundRefreshTimer = setTimeout(() => {
|
|
1418
|
-
this.backgroundRefreshTimer = null;
|
|
1419
|
-
for (const agentName of agentNames) {
|
|
1420
|
-
this.scheduleRefresh(agentName, 0);
|
|
1421
|
-
}
|
|
1422
|
-
if (agentNames.length === 0) {
|
|
1423
|
-
this.finishScanBatch();
|
|
1424
|
-
}
|
|
1425
|
-
}, 0);
|
|
1426
|
-
}
|
|
1427
|
-
getSnapshot() {
|
|
1428
|
-
return {
|
|
1429
|
-
sessions: this.sessions,
|
|
1430
|
-
byAgent: this.byAgent,
|
|
1431
|
-
agents: this.agents
|
|
1432
|
-
};
|
|
1433
|
-
}
|
|
1434
|
-
getScanStatus() {
|
|
1435
|
-
return {
|
|
1436
|
-
type: "scan-status",
|
|
1437
|
-
...this.scanStatus,
|
|
1438
|
-
pendingAgents: [...this.scanStatus.pendingAgents],
|
|
1439
|
-
scanningAgents: [...this.scanStatus.scanningAgents],
|
|
1440
|
-
completedAgents: [...this.scanStatus.completedAgents],
|
|
1441
|
-
agentStatuses: Object.fromEntries(
|
|
1442
|
-
Object.entries(this.scanStatus.agentStatuses).map(([agentName, status]) => [
|
|
1443
|
-
agentName,
|
|
1444
|
-
{ ...status }
|
|
1445
|
-
])
|
|
1446
|
-
)
|
|
1447
|
-
};
|
|
1448
|
-
}
|
|
1449
|
-
subscribe(listener) {
|
|
1450
|
-
this.listeners.add(listener);
|
|
1451
|
-
return () => {
|
|
1452
|
-
this.listeners.delete(listener);
|
|
1453
|
-
};
|
|
1454
|
-
}
|
|
1455
|
-
subscribeScanStatus(listener) {
|
|
1456
|
-
this.scanStatusListeners.add(listener);
|
|
1062
|
+
listeners = /* @__PURE__ */ new Set();
|
|
1063
|
+
/** Register a listener fired (after write-stability polling) with the changed agent set. */
|
|
1064
|
+
onAgentsChanged(cb) {
|
|
1065
|
+
this.listeners.add(cb);
|
|
1457
1066
|
return () => {
|
|
1458
|
-
this.
|
|
1067
|
+
this.listeners.delete(cb);
|
|
1459
1068
|
};
|
|
1460
1069
|
}
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1070
|
+
/** Begin watching the given agent names' data directories. */
|
|
1071
|
+
start(agentNames) {
|
|
1072
|
+
const scopesByRoot = /* @__PURE__ */ new Map();
|
|
1073
|
+
for (const agentName of agentNames) {
|
|
1074
|
+
const watchTargets = resolveAgentWatchTargets(agentName);
|
|
1075
|
+
if (watchTargets.length === 0) {
|
|
1076
|
+
appLogger.debug("watch.skip", { agent: agentName });
|
|
1077
|
+
continue;
|
|
1078
|
+
}
|
|
1079
|
+
for (const target of watchTargets) {
|
|
1080
|
+
const watchRootPath = closestWatchablePath(target.root ?? target.path);
|
|
1081
|
+
if (!watchRootPath) continue;
|
|
1082
|
+
let rootPath;
|
|
1083
|
+
try {
|
|
1084
|
+
rootPath = getWatchRoot(watchRootPath);
|
|
1085
|
+
} catch (error) {
|
|
1086
|
+
this.reportWatchError("watch.resolve.error", { path: watchRootPath, error });
|
|
1087
|
+
continue;
|
|
1088
|
+
}
|
|
1089
|
+
const targetPath = toAbsolutePath(target.path);
|
|
1090
|
+
const scopes = scopesByRoot.get(rootPath) ?? [];
|
|
1091
|
+
if (!scopes.some((scope) => scope.agentName === agentName && scope.targetPath === targetPath)) {
|
|
1092
|
+
scopes.push({ agentName, targetPath });
|
|
1093
|
+
}
|
|
1094
|
+
scopesByRoot.set(rootPath, scopes);
|
|
1471
1095
|
}
|
|
1472
1096
|
}
|
|
1473
|
-
|
|
1097
|
+
for (const [rootPath, scopes] of scopesByRoot.entries()) {
|
|
1098
|
+
const agents = Array.from(new Set(scopes.map((scope) => scope.agentName)));
|
|
1099
|
+
appLogger.info("watch.start", {
|
|
1100
|
+
root: rootPath,
|
|
1101
|
+
agents,
|
|
1102
|
+
targets: scopes.map((scope) => ({
|
|
1103
|
+
agent: scope.agentName,
|
|
1104
|
+
path: scope.targetPath
|
|
1105
|
+
}))
|
|
1106
|
+
});
|
|
1107
|
+
if (isRecursiveWatchSupported()) {
|
|
1108
|
+
const started = this.watchDirectory(rootPath, scopes, true);
|
|
1109
|
+
if (started) {
|
|
1110
|
+
continue;
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
this.watchDirectoryTree(rootPath, scopes);
|
|
1114
|
+
}
|
|
1115
|
+
}
|
|
1116
|
+
/** Stop all watchers and clear pending stability polls. */
|
|
1117
|
+
async dispose() {
|
|
1118
|
+
for (const state of this.stablePaths.values()) {
|
|
1119
|
+
if (state.timer) {
|
|
1120
|
+
clearTimeout(state.timer);
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
this.stablePaths.clear();
|
|
1124
|
+
await Promise.all(this.watchers.map((watcher) => watcher.close()));
|
|
1125
|
+
this.watchers = [];
|
|
1126
|
+
this.fallbackWatchScopes.clear();
|
|
1127
|
+
this.listeners.clear();
|
|
1128
|
+
}
|
|
1129
|
+
watchDirectory(path, scopes, recursive) {
|
|
1130
|
+
try {
|
|
1131
|
+
const watcher = watch(path, { recursive }, (eventType, filename) => {
|
|
1132
|
+
queueMicrotask(() => {
|
|
1133
|
+
try {
|
|
1134
|
+
const activeScopes = recursive ? scopes : this.fallbackWatchScopes.get(path) ?? scopes;
|
|
1135
|
+
this.handleWatchEvent(path, activeScopes, eventType, filename);
|
|
1136
|
+
if (!recursive) {
|
|
1137
|
+
this.watchNewDirectories(path, filename, activeScopes);
|
|
1138
|
+
}
|
|
1139
|
+
} catch (error) {
|
|
1140
|
+
this.reportWatchError("watch.event.error", { path, recursive, error });
|
|
1141
|
+
}
|
|
1142
|
+
});
|
|
1143
|
+
});
|
|
1144
|
+
watcher.on("error", (error) => {
|
|
1145
|
+
this.reportWatchError("watch.error", { path, recursive, error });
|
|
1146
|
+
});
|
|
1147
|
+
this.watchers.push(watcher);
|
|
1148
|
+
return true;
|
|
1149
|
+
} catch (error) {
|
|
1150
|
+
if (recursive && isRecursiveWatchUnavailable(error)) {
|
|
1151
|
+
appLogger.warn("watch.recursive_unavailable", { path, error });
|
|
1152
|
+
return false;
|
|
1153
|
+
}
|
|
1154
|
+
this.reportWatchError("watch.start.error", { path, recursive, error });
|
|
1155
|
+
return false;
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
watchDirectoryTree(rootPath, scopes) {
|
|
1159
|
+
const pending = [rootPath];
|
|
1160
|
+
while (pending.length > 0) {
|
|
1161
|
+
const dirPath = pending.pop();
|
|
1162
|
+
this.watchFallbackDirectory(dirPath, scopes);
|
|
1163
|
+
try {
|
|
1164
|
+
for (const entry of readdirSync2(dirPath, { withFileTypes: true })) {
|
|
1165
|
+
if (entry.isDirectory()) {
|
|
1166
|
+
pending.push(join2(dirPath, entry.name));
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
} catch (error) {
|
|
1170
|
+
this.reportWatchError("watch.scan.error", { path: dirPath, error });
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
}
|
|
1174
|
+
watchFallbackDirectory(path, scopes) {
|
|
1175
|
+
const existingScopes = this.fallbackWatchScopes.get(path);
|
|
1176
|
+
if (existingScopes) {
|
|
1177
|
+
mergeScopes(existingScopes, scopes);
|
|
1178
|
+
return;
|
|
1179
|
+
}
|
|
1180
|
+
const storedScopes = [...scopes];
|
|
1181
|
+
this.fallbackWatchScopes.set(path, storedScopes);
|
|
1182
|
+
if (!this.watchDirectory(path, storedScopes, false)) {
|
|
1183
|
+
this.fallbackWatchScopes.delete(path);
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
watchNewDirectories(watchPath, filename, scopes) {
|
|
1187
|
+
const path = resolveWatchEventPath(watchPath, filename);
|
|
1188
|
+
try {
|
|
1189
|
+
if (statSync2(path).isDirectory()) {
|
|
1190
|
+
this.watchDirectoryTree(path, scopes);
|
|
1191
|
+
}
|
|
1192
|
+
} catch {
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
handleWatchEvent(watchPath, scopes, eventType, filename) {
|
|
1196
|
+
const changedPath = resolveWatchEventPath(watchPath, filename);
|
|
1197
|
+
const agentNames = new Set(
|
|
1198
|
+
scopes.filter((scope) => isRelatedPath(changedPath, scope.targetPath)).map((scope) => scope.agentName)
|
|
1199
|
+
);
|
|
1200
|
+
if (agentNames.size === 0) {
|
|
1201
|
+
return;
|
|
1202
|
+
}
|
|
1203
|
+
appLogger.debug("watch.event", {
|
|
1204
|
+
event: eventType,
|
|
1205
|
+
path: changedPath,
|
|
1206
|
+
agents: Array.from(agentNames)
|
|
1207
|
+
});
|
|
1208
|
+
this.waitForStablePath(changedPath, agentNames);
|
|
1209
|
+
}
|
|
1210
|
+
waitForStablePath(path, agentNames) {
|
|
1211
|
+
const existing = this.stablePaths.get(path);
|
|
1212
|
+
if (existing) {
|
|
1213
|
+
for (const agentName of agentNames) {
|
|
1214
|
+
existing.agentNames.add(agentName);
|
|
1215
|
+
}
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
const state = {
|
|
1219
|
+
path,
|
|
1220
|
+
agentNames: new Set(agentNames),
|
|
1221
|
+
lastMtimeMs: null,
|
|
1222
|
+
lastSize: null,
|
|
1223
|
+
stableSince: Date.now(),
|
|
1224
|
+
timer: null
|
|
1225
|
+
};
|
|
1226
|
+
this.stablePaths.set(path, state);
|
|
1227
|
+
this.pollStablePath(path);
|
|
1228
|
+
}
|
|
1229
|
+
pollStablePath(path) {
|
|
1230
|
+
const state = this.stablePaths.get(path);
|
|
1231
|
+
if (!state) {
|
|
1232
|
+
return;
|
|
1233
|
+
}
|
|
1234
|
+
let size;
|
|
1235
|
+
let mtimeMs;
|
|
1236
|
+
try {
|
|
1237
|
+
const stat = statSync2(path);
|
|
1238
|
+
size = stat.size;
|
|
1239
|
+
mtimeMs = stat.mtimeMs;
|
|
1240
|
+
} catch {
|
|
1241
|
+
this.stablePaths.delete(path);
|
|
1242
|
+
this.emitAgentsChanged(state.agentNames);
|
|
1243
|
+
return;
|
|
1244
|
+
}
|
|
1245
|
+
const now = Date.now();
|
|
1246
|
+
const unchanged = state.lastSize === size && state.lastMtimeMs === mtimeMs;
|
|
1247
|
+
if (!unchanged) {
|
|
1248
|
+
state.lastSize = size;
|
|
1249
|
+
state.lastMtimeMs = mtimeMs;
|
|
1250
|
+
state.stableSince = now;
|
|
1251
|
+
}
|
|
1252
|
+
if (unchanged && now - state.stableSince >= WRITE_STABILITY_THRESHOLD_MS) {
|
|
1253
|
+
this.stablePaths.delete(path);
|
|
1254
|
+
this.emitAgentsChanged(state.agentNames);
|
|
1255
|
+
return;
|
|
1256
|
+
}
|
|
1257
|
+
state.timer = setTimeout(() => this.pollStablePath(path), WRITE_STABILITY_POLL_MS);
|
|
1258
|
+
}
|
|
1259
|
+
emitAgentsChanged(agentNames) {
|
|
1260
|
+
if (agentNames.size === 0) return;
|
|
1261
|
+
for (const listener of this.listeners) {
|
|
1262
|
+
listener(new Set(agentNames));
|
|
1263
|
+
}
|
|
1264
|
+
}
|
|
1265
|
+
reportWatchError(event, data) {
|
|
1266
|
+
appLogger.error(event, data);
|
|
1267
|
+
console.error("[watch] File watcher failed:", data.error);
|
|
1268
|
+
}
|
|
1269
|
+
};
|
|
1270
|
+
|
|
1271
|
+
// src/live-scan.ts
|
|
1272
|
+
var REFRESH_DEBOUNCE_MS = 200;
|
|
1273
|
+
var EMPTY_AGENT_REFRESH_DEBOUNCE_MS = 3e4;
|
|
1274
|
+
var PENDING_REFRESH_DELAY_MS = 100;
|
|
1275
|
+
var NEW_SESSION_EVENT_WINDOW_MS = 250;
|
|
1276
|
+
var SEARCH_INDEX_BULK_PENDING_PATH_THRESHOLD = 100;
|
|
1277
|
+
function buildRefreshDiff(agentName, previousSessions, nextSessions, candidateChangedIds = []) {
|
|
1278
|
+
const { changes, removedSessionIds, counts } = computeSessionDiff(
|
|
1279
|
+
previousSessions,
|
|
1280
|
+
nextSessions,
|
|
1281
|
+
candidateChangedIds,
|
|
1282
|
+
sessionSignature
|
|
1283
|
+
);
|
|
1284
|
+
if (counts.new === 0 && counts.updated === 0 && counts.removed === 0) {
|
|
1285
|
+
return { event: null, changedSessions: changes, removedSessionIds };
|
|
1286
|
+
}
|
|
1287
|
+
return {
|
|
1288
|
+
changedSessions: changes,
|
|
1289
|
+
removedSessionIds,
|
|
1290
|
+
event: {
|
|
1291
|
+
type: "sessions-updated",
|
|
1292
|
+
changedAgents: [agentName],
|
|
1293
|
+
newSessions: counts.new,
|
|
1294
|
+
updatedSessions: counts.updated,
|
|
1295
|
+
removedSessions: counts.removed,
|
|
1296
|
+
totalSessions: nextSessions.length,
|
|
1297
|
+
timestamp: Date.now(),
|
|
1298
|
+
changedSessionHeads: changes.map(({ session }) => ({ agentName, session })),
|
|
1299
|
+
removedSessionRefs: removedSessionIds.map((sessionId) => ({ agentName, sessionId }))
|
|
1300
|
+
}
|
|
1301
|
+
};
|
|
1302
|
+
}
|
|
1303
|
+
function restoreAgentCacheMeta(agent, meta) {
|
|
1304
|
+
agent.setSessionMetaMap(new Map(Object.entries(meta)));
|
|
1305
|
+
}
|
|
1306
|
+
function mergeEvents(previous, next) {
|
|
1307
|
+
const changedSessionHeads = /* @__PURE__ */ new Map();
|
|
1308
|
+
const removedSessionRefs = /* @__PURE__ */ new Map();
|
|
1309
|
+
const sessionKey = (agentName, sessionId) => `${agentName}\0${sessionId}`;
|
|
1310
|
+
const addChanged = (item) => {
|
|
1311
|
+
const key = sessionKey(item.agentName, item.session.id);
|
|
1312
|
+
removedSessionRefs.delete(key);
|
|
1313
|
+
changedSessionHeads.set(key, item);
|
|
1314
|
+
};
|
|
1315
|
+
const addRemoved = (item) => {
|
|
1316
|
+
const key = sessionKey(item.agentName, item.sessionId);
|
|
1317
|
+
changedSessionHeads.delete(key);
|
|
1318
|
+
removedSessionRefs.set(key, item);
|
|
1319
|
+
};
|
|
1320
|
+
for (const item of previous.changedSessionHeads) addChanged(item);
|
|
1321
|
+
for (const item of previous.removedSessionRefs) addRemoved(item);
|
|
1322
|
+
for (const item of next.changedSessionHeads) addChanged(item);
|
|
1323
|
+
for (const item of next.removedSessionRefs) addRemoved(item);
|
|
1324
|
+
return {
|
|
1325
|
+
type: "sessions-updated",
|
|
1326
|
+
changedAgents: Array.from(/* @__PURE__ */ new Set([...previous.changedAgents, ...next.changedAgents])),
|
|
1327
|
+
newSessions: previous.newSessions + next.newSessions,
|
|
1328
|
+
updatedSessions: previous.updatedSessions + next.updatedSessions,
|
|
1329
|
+
removedSessions: previous.removedSessions + next.removedSessions,
|
|
1330
|
+
totalSessions: next.totalSessions,
|
|
1331
|
+
timestamp: next.timestamp,
|
|
1332
|
+
changedSessionHeads: [...changedSessionHeads.values()],
|
|
1333
|
+
removedSessionRefs: [...removedSessionRefs.values()]
|
|
1334
|
+
};
|
|
1335
|
+
}
|
|
1336
|
+
var LiveScanStore = class {
|
|
1337
|
+
constructor(watchEnabled = true, scanOptions = {}, startupScanOptions = {}, storeOptions = {}) {
|
|
1338
|
+
this.watchEnabled = watchEnabled;
|
|
1339
|
+
this.scanOptions = scanOptions;
|
|
1340
|
+
this.startupScanOptions = startupScanOptions;
|
|
1341
|
+
this.storeOptions = storeOptions;
|
|
1342
|
+
}
|
|
1343
|
+
watchEnabled;
|
|
1344
|
+
scanOptions;
|
|
1345
|
+
startupScanOptions;
|
|
1346
|
+
storeOptions;
|
|
1347
|
+
agents = [];
|
|
1348
|
+
byAgent = {};
|
|
1349
|
+
sessions = [];
|
|
1350
|
+
listeners = /* @__PURE__ */ new Set();
|
|
1351
|
+
scanStatusListeners = /* @__PURE__ */ new Set();
|
|
1352
|
+
scanStatus = {
|
|
1353
|
+
active: false,
|
|
1354
|
+
phase: "idle",
|
|
1355
|
+
pendingAgents: [],
|
|
1356
|
+
scanningAgents: [],
|
|
1357
|
+
completedAgents: [],
|
|
1358
|
+
agentStatuses: {},
|
|
1359
|
+
totalAgents: 0,
|
|
1360
|
+
updatedAt: Date.now()
|
|
1361
|
+
};
|
|
1362
|
+
refreshTimers = /* @__PURE__ */ new Map();
|
|
1363
|
+
refreshTimestamps = /* @__PURE__ */ new Map();
|
|
1364
|
+
refreshInFlight = /* @__PURE__ */ new Set();
|
|
1365
|
+
pendingRefreshes = /* @__PURE__ */ new Set();
|
|
1366
|
+
pendingRefreshPathCounts = /* @__PURE__ */ new Map();
|
|
1367
|
+
watcher = null;
|
|
1368
|
+
pendingEvent = null;
|
|
1369
|
+
pendingEventTimer = null;
|
|
1370
|
+
backgroundRefreshTimer = null;
|
|
1371
|
+
searchIndexWorker = null;
|
|
1372
|
+
pendingSearchIndexJobs = [];
|
|
1373
|
+
shuttingDown = false;
|
|
1374
|
+
async initialize() {
|
|
1375
|
+
const startedAt = performance.now();
|
|
1376
|
+
const deferInitialRefresh = this.storeOptions.deferInitialRefresh === true;
|
|
1377
|
+
appLogger.info("scan.initial.start", {
|
|
1378
|
+
watch_enabled: this.watchEnabled,
|
|
1379
|
+
agents: this.scanOptions.agents,
|
|
1380
|
+
use_cache: this.scanOptions.useCache ?? true,
|
|
1381
|
+
startup_from: this.startupScanOptions.from,
|
|
1382
|
+
startup_to: this.startupScanOptions.to,
|
|
1383
|
+
deferred: deferInitialRefresh || void 0
|
|
1384
|
+
});
|
|
1385
|
+
const initialResult = await scanSessions({
|
|
1386
|
+
...this.scanOptions,
|
|
1387
|
+
...deferInitialRefresh ? this.startupScanOptions : {},
|
|
1388
|
+
useCache: this.scanOptions.useCache ?? true,
|
|
1389
|
+
smartRefresh: false,
|
|
1390
|
+
cacheOnly: deferInitialRefresh,
|
|
1391
|
+
writeCache: deferInitialRefresh ? false : this.scanOptions.writeCache,
|
|
1392
|
+
smartTagWorkerUrl: this.getSmartTagWorkerUrl() ?? void 0,
|
|
1393
|
+
includeSmartTags: deferInitialRefresh ? false : void 0
|
|
1394
|
+
});
|
|
1395
|
+
this.applyScanResult(initialResult);
|
|
1396
|
+
const indexStartedAt = performance.now();
|
|
1397
|
+
if (!deferInitialRefresh) {
|
|
1398
|
+
await this.enqueueSearchIndexJobs(
|
|
1399
|
+
"scan.initial",
|
|
1400
|
+
this.buildFullSearchIndexJobs("scan.initial")
|
|
1401
|
+
);
|
|
1402
|
+
}
|
|
1403
|
+
const indexDuration = performance.now() - indexStartedAt;
|
|
1404
|
+
appLogger.info("scan.initial.done", {
|
|
1405
|
+
duration_ms: Math.round(performance.now() - startedAt),
|
|
1406
|
+
index_ms: deferInitialRefresh ? void 0 : Math.round(indexDuration),
|
|
1407
|
+
deferred: deferInitialRefresh || void 0,
|
|
1408
|
+
sessions: this.sessions.length,
|
|
1409
|
+
agents: Object.fromEntries(
|
|
1410
|
+
Object.entries(this.byAgent).map(([key, value]) => [key, value.length])
|
|
1411
|
+
),
|
|
1412
|
+
agent_timings: initialResult.timings ? Object.fromEntries(
|
|
1413
|
+
Object.entries(initialResult.timings).map(([name, t]) => [
|
|
1414
|
+
name,
|
|
1415
|
+
{
|
|
1416
|
+
total_ms: Math.round(t.total),
|
|
1417
|
+
cache_load_ms: t.cacheLoad != null ? Math.round(t.cacheLoad) : void 0,
|
|
1418
|
+
check_changes_ms: t.checkChanges != null ? Math.round(t.checkChanges) : void 0,
|
|
1419
|
+
scan_ms: t.scan != null ? Math.round(t.scan) : void 0,
|
|
1420
|
+
identity_ms: t.identity != null ? Math.round(t.identity) : void 0,
|
|
1421
|
+
tags_ms: t.tags != null ? Math.round(t.tags) : void 0
|
|
1422
|
+
}
|
|
1423
|
+
])
|
|
1424
|
+
) : void 0
|
|
1425
|
+
});
|
|
1426
|
+
if (this.watchEnabled) {
|
|
1427
|
+
this.watcher = new SessionWatcher();
|
|
1428
|
+
this.watcher.onAgentsChanged((agentNames) => {
|
|
1429
|
+
for (const agentName of agentNames) {
|
|
1430
|
+
this.pendingRefreshPathCounts.set(
|
|
1431
|
+
agentName,
|
|
1432
|
+
(this.pendingRefreshPathCounts.get(agentName) ?? 0) + 1
|
|
1433
|
+
);
|
|
1434
|
+
const delayMs = (this.byAgent[agentName]?.length ?? 0) === 0 ? EMPTY_AGENT_REFRESH_DEBOUNCE_MS : REFRESH_DEBOUNCE_MS;
|
|
1435
|
+
this.scheduleRefresh(agentName, delayMs);
|
|
1436
|
+
}
|
|
1437
|
+
});
|
|
1438
|
+
this.watcher.start(this.agents.map((agent) => agent.name));
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
startBackgroundRefresh() {
|
|
1442
|
+
if (this.backgroundRefreshTimer) {
|
|
1443
|
+
return;
|
|
1444
|
+
}
|
|
1445
|
+
const agentNames = this.agents.map((agent) => agent.name);
|
|
1446
|
+
this.startScanBatch(agentNames, "scanning");
|
|
1447
|
+
this.backgroundRefreshTimer = setTimeout(() => {
|
|
1448
|
+
this.backgroundRefreshTimer = null;
|
|
1449
|
+
for (const agentName of agentNames) {
|
|
1450
|
+
this.scheduleRefresh(agentName, 0);
|
|
1451
|
+
}
|
|
1452
|
+
if (agentNames.length === 0) {
|
|
1453
|
+
this.finishScanBatch();
|
|
1454
|
+
}
|
|
1455
|
+
}, 0);
|
|
1456
|
+
}
|
|
1457
|
+
getSnapshot() {
|
|
1458
|
+
return {
|
|
1459
|
+
sessions: this.sessions,
|
|
1460
|
+
byAgent: this.byAgent,
|
|
1461
|
+
agents: this.agents
|
|
1462
|
+
};
|
|
1463
|
+
}
|
|
1464
|
+
getScanStatus() {
|
|
1465
|
+
return {
|
|
1466
|
+
type: "scan-status",
|
|
1467
|
+
...this.scanStatus,
|
|
1468
|
+
pendingAgents: [...this.scanStatus.pendingAgents],
|
|
1469
|
+
scanningAgents: [...this.scanStatus.scanningAgents],
|
|
1470
|
+
completedAgents: [...this.scanStatus.completedAgents],
|
|
1471
|
+
agentStatuses: Object.fromEntries(
|
|
1472
|
+
Object.entries(this.scanStatus.agentStatuses).map(([agentName, status]) => [
|
|
1473
|
+
agentName,
|
|
1474
|
+
{ ...status }
|
|
1475
|
+
])
|
|
1476
|
+
)
|
|
1477
|
+
};
|
|
1478
|
+
}
|
|
1479
|
+
subscribe(listener) {
|
|
1480
|
+
this.listeners.add(listener);
|
|
1481
|
+
return () => {
|
|
1482
|
+
this.listeners.delete(listener);
|
|
1483
|
+
};
|
|
1484
|
+
}
|
|
1485
|
+
subscribeScanStatus(listener) {
|
|
1486
|
+
this.scanStatusListeners.add(listener);
|
|
1487
|
+
return () => {
|
|
1488
|
+
this.scanStatusListeners.delete(listener);
|
|
1489
|
+
};
|
|
1490
|
+
}
|
|
1491
|
+
async shutdown() {
|
|
1492
|
+
this.shuttingDown = true;
|
|
1493
|
+
for (const timer of this.refreshTimers.values()) {
|
|
1494
|
+
clearTimeout(timer);
|
|
1495
|
+
}
|
|
1496
|
+
this.refreshTimers.clear();
|
|
1497
|
+
this.pendingRefreshPathCounts.clear();
|
|
1474
1498
|
if (this.pendingEventTimer) {
|
|
1475
1499
|
clearTimeout(this.pendingEventTimer);
|
|
1476
1500
|
this.pendingEventTimer = null;
|
|
@@ -1488,9 +1512,10 @@ var LiveScanStore = class {
|
|
|
1488
1512
|
}
|
|
1489
1513
|
this.pendingSearchIndexJobs = [];
|
|
1490
1514
|
this.pendingEvent = null;
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1515
|
+
if (this.watcher) {
|
|
1516
|
+
await this.watcher.dispose();
|
|
1517
|
+
this.watcher = null;
|
|
1518
|
+
}
|
|
1494
1519
|
}
|
|
1495
1520
|
emit(event) {
|
|
1496
1521
|
if (this.pendingEvent || event.newSessions > 0) {
|
|
@@ -1674,14 +1699,14 @@ var LiveScanStore = class {
|
|
|
1674
1699
|
}
|
|
1675
1700
|
getSearchIndexWorkerUrl() {
|
|
1676
1701
|
const workerUrl = new URL("./search-index-worker.js", import.meta.url);
|
|
1677
|
-
if (workerUrl.protocol === "file:" && !
|
|
1702
|
+
if (workerUrl.protocol === "file:" && !existsSync4(fileURLToPath2(workerUrl))) {
|
|
1678
1703
|
return null;
|
|
1679
1704
|
}
|
|
1680
1705
|
return workerUrl;
|
|
1681
1706
|
}
|
|
1682
1707
|
getSmartTagWorkerUrl() {
|
|
1683
1708
|
const workerUrl = new URL("./smart-tag-worker.js", import.meta.url);
|
|
1684
|
-
if (workerUrl.protocol === "file:" && !
|
|
1709
|
+
if (workerUrl.protocol === "file:" && !existsSync4(fileURLToPath2(workerUrl))) {
|
|
1685
1710
|
return null;
|
|
1686
1711
|
}
|
|
1687
1712
|
return workerUrl;
|
|
@@ -1861,9 +1886,6 @@ var LiveScanStore = class {
|
|
|
1861
1886
|
applyFilters(sessions) {
|
|
1862
1887
|
return filterSessions(sessions, { ...this.scanOptions, ...this.startupScanOptions });
|
|
1863
1888
|
}
|
|
1864
|
-
canSyncSources(agent) {
|
|
1865
|
-
return Boolean(agent.listSessionSources && agent.scanSessionSource);
|
|
1866
|
-
}
|
|
1867
1889
|
async refreshInitialIndex() {
|
|
1868
1890
|
const startedAt = performance.now();
|
|
1869
1891
|
const context = "scan.initial.background";
|
|
@@ -1881,195 +1903,6 @@ var LiveScanStore = class {
|
|
|
1881
1903
|
console.error("[search] Background index sync failed:", error);
|
|
1882
1904
|
}
|
|
1883
1905
|
}
|
|
1884
|
-
startWatching() {
|
|
1885
|
-
const scopesByRoot = /* @__PURE__ */ new Map();
|
|
1886
|
-
for (const agent of this.agents) {
|
|
1887
|
-
const watchTargets = resolveAgentWatchTargets(agent.name);
|
|
1888
|
-
if (watchTargets.length === 0) {
|
|
1889
|
-
appLogger.debug("watch.skip", { agent: agent.name });
|
|
1890
|
-
continue;
|
|
1891
|
-
}
|
|
1892
|
-
for (const target of watchTargets) {
|
|
1893
|
-
const watchRootPath = closestWatchablePath(target.root ?? target.path);
|
|
1894
|
-
if (!watchRootPath) continue;
|
|
1895
|
-
let rootPath;
|
|
1896
|
-
try {
|
|
1897
|
-
rootPath = getWatchRoot(watchRootPath);
|
|
1898
|
-
} catch (error) {
|
|
1899
|
-
this.reportWatchError("watch.resolve.error", { path: watchRootPath, error });
|
|
1900
|
-
continue;
|
|
1901
|
-
}
|
|
1902
|
-
const targetPath = toAbsolutePath(target.path);
|
|
1903
|
-
const scopes = scopesByRoot.get(rootPath) ?? [];
|
|
1904
|
-
if (!scopes.some((scope) => scope.agentName === agent.name && scope.targetPath === targetPath)) {
|
|
1905
|
-
scopes.push({ agentName: agent.name, targetPath });
|
|
1906
|
-
}
|
|
1907
|
-
scopesByRoot.set(rootPath, scopes);
|
|
1908
|
-
}
|
|
1909
|
-
}
|
|
1910
|
-
for (const [rootPath, scopes] of scopesByRoot.entries()) {
|
|
1911
|
-
const agents = Array.from(new Set(scopes.map((scope) => scope.agentName)));
|
|
1912
|
-
appLogger.info("watch.start", {
|
|
1913
|
-
root: rootPath,
|
|
1914
|
-
agents,
|
|
1915
|
-
targets: scopes.map((scope) => ({
|
|
1916
|
-
agent: scope.agentName,
|
|
1917
|
-
path: scope.targetPath
|
|
1918
|
-
}))
|
|
1919
|
-
});
|
|
1920
|
-
if (isRecursiveWatchSupported()) {
|
|
1921
|
-
const started = this.watchDirectory(rootPath, scopes, true);
|
|
1922
|
-
if (started) {
|
|
1923
|
-
continue;
|
|
1924
|
-
}
|
|
1925
|
-
}
|
|
1926
|
-
this.watchDirectoryTree(rootPath, scopes);
|
|
1927
|
-
}
|
|
1928
|
-
}
|
|
1929
|
-
watchDirectory(path, scopes, recursive) {
|
|
1930
|
-
try {
|
|
1931
|
-
const watcher = watch(path, { recursive }, (eventType, filename) => {
|
|
1932
|
-
queueMicrotask(() => {
|
|
1933
|
-
try {
|
|
1934
|
-
const activeScopes = recursive ? scopes : this.fallbackWatchScopes.get(path) ?? scopes;
|
|
1935
|
-
this.handleWatchEvent(path, activeScopes, eventType, filename);
|
|
1936
|
-
if (!recursive) {
|
|
1937
|
-
this.watchNewDirectories(path, filename, activeScopes);
|
|
1938
|
-
}
|
|
1939
|
-
} catch (error) {
|
|
1940
|
-
this.reportWatchError("watch.event.error", { path, recursive, error });
|
|
1941
|
-
}
|
|
1942
|
-
});
|
|
1943
|
-
});
|
|
1944
|
-
watcher.on("error", (error) => {
|
|
1945
|
-
this.reportWatchError("watch.error", { path, recursive, error });
|
|
1946
|
-
});
|
|
1947
|
-
this.watchers.push(watcher);
|
|
1948
|
-
return true;
|
|
1949
|
-
} catch (error) {
|
|
1950
|
-
if (recursive && isRecursiveWatchUnavailable(error)) {
|
|
1951
|
-
appLogger.warn("watch.recursive_unavailable", { path, error });
|
|
1952
|
-
return false;
|
|
1953
|
-
}
|
|
1954
|
-
this.reportWatchError("watch.start.error", { path, recursive, error });
|
|
1955
|
-
return false;
|
|
1956
|
-
}
|
|
1957
|
-
}
|
|
1958
|
-
watchDirectoryTree(rootPath, scopes) {
|
|
1959
|
-
const pending = [rootPath];
|
|
1960
|
-
while (pending.length > 0) {
|
|
1961
|
-
const dirPath = pending.pop();
|
|
1962
|
-
this.watchFallbackDirectory(dirPath, scopes);
|
|
1963
|
-
try {
|
|
1964
|
-
for (const entry of readdirSync2(dirPath, { withFileTypes: true })) {
|
|
1965
|
-
if (entry.isDirectory()) {
|
|
1966
|
-
pending.push(join2(dirPath, entry.name));
|
|
1967
|
-
}
|
|
1968
|
-
}
|
|
1969
|
-
} catch (error) {
|
|
1970
|
-
this.reportWatchError("watch.scan.error", { path: dirPath, error });
|
|
1971
|
-
}
|
|
1972
|
-
}
|
|
1973
|
-
}
|
|
1974
|
-
watchFallbackDirectory(path, scopes) {
|
|
1975
|
-
const existingScopes = this.fallbackWatchScopes.get(path);
|
|
1976
|
-
if (existingScopes) {
|
|
1977
|
-
mergeScopes(existingScopes, scopes);
|
|
1978
|
-
return;
|
|
1979
|
-
}
|
|
1980
|
-
const storedScopes = [...scopes];
|
|
1981
|
-
this.fallbackWatchScopes.set(path, storedScopes);
|
|
1982
|
-
if (!this.watchDirectory(path, storedScopes, false)) {
|
|
1983
|
-
this.fallbackWatchScopes.delete(path);
|
|
1984
|
-
}
|
|
1985
|
-
}
|
|
1986
|
-
watchNewDirectories(watchPath, filename, scopes) {
|
|
1987
|
-
const path = resolveWatchEventPath(watchPath, filename);
|
|
1988
|
-
try {
|
|
1989
|
-
if (statSync2(path).isDirectory()) {
|
|
1990
|
-
this.watchDirectoryTree(path, scopes);
|
|
1991
|
-
}
|
|
1992
|
-
} catch {
|
|
1993
|
-
}
|
|
1994
|
-
}
|
|
1995
|
-
handleWatchEvent(watchPath, scopes, eventType, filename) {
|
|
1996
|
-
const changedPath = resolveWatchEventPath(watchPath, filename);
|
|
1997
|
-
const agentNames = new Set(
|
|
1998
|
-
scopes.filter((scope) => isRelatedPath(changedPath, scope.targetPath)).map((scope) => scope.agentName)
|
|
1999
|
-
);
|
|
2000
|
-
if (agentNames.size === 0) {
|
|
2001
|
-
return;
|
|
2002
|
-
}
|
|
2003
|
-
appLogger.debug("watch.event", {
|
|
2004
|
-
event: eventType,
|
|
2005
|
-
path: changedPath,
|
|
2006
|
-
agents: Array.from(agentNames)
|
|
2007
|
-
});
|
|
2008
|
-
this.waitForStablePath(changedPath, agentNames);
|
|
2009
|
-
}
|
|
2010
|
-
waitForStablePath(path, agentNames) {
|
|
2011
|
-
const existing = this.stablePaths.get(path);
|
|
2012
|
-
if (existing) {
|
|
2013
|
-
for (const agentName of agentNames) {
|
|
2014
|
-
existing.agentNames.add(agentName);
|
|
2015
|
-
}
|
|
2016
|
-
return;
|
|
2017
|
-
}
|
|
2018
|
-
const state = {
|
|
2019
|
-
path,
|
|
2020
|
-
agentNames: new Set(agentNames),
|
|
2021
|
-
lastMtimeMs: null,
|
|
2022
|
-
lastSize: null,
|
|
2023
|
-
stableSince: Date.now(),
|
|
2024
|
-
timer: null
|
|
2025
|
-
};
|
|
2026
|
-
this.stablePaths.set(path, state);
|
|
2027
|
-
this.pollStablePath(path);
|
|
2028
|
-
}
|
|
2029
|
-
pollStablePath(path) {
|
|
2030
|
-
const state = this.stablePaths.get(path);
|
|
2031
|
-
if (!state) {
|
|
2032
|
-
return;
|
|
2033
|
-
}
|
|
2034
|
-
let size;
|
|
2035
|
-
let mtimeMs;
|
|
2036
|
-
try {
|
|
2037
|
-
const stat = statSync2(path);
|
|
2038
|
-
size = stat.size;
|
|
2039
|
-
mtimeMs = stat.mtimeMs;
|
|
2040
|
-
} catch {
|
|
2041
|
-
this.stablePaths.delete(path);
|
|
2042
|
-
this.scheduleRefreshForAgents(state.agentNames);
|
|
2043
|
-
return;
|
|
2044
|
-
}
|
|
2045
|
-
const now = Date.now();
|
|
2046
|
-
const unchanged = state.lastSize === size && state.lastMtimeMs === mtimeMs;
|
|
2047
|
-
if (!unchanged) {
|
|
2048
|
-
state.lastSize = size;
|
|
2049
|
-
state.lastMtimeMs = mtimeMs;
|
|
2050
|
-
state.stableSince = now;
|
|
2051
|
-
}
|
|
2052
|
-
if (unchanged && now - state.stableSince >= WRITE_STABILITY_THRESHOLD_MS) {
|
|
2053
|
-
this.stablePaths.delete(path);
|
|
2054
|
-
this.scheduleRefreshForAgents(state.agentNames);
|
|
2055
|
-
return;
|
|
2056
|
-
}
|
|
2057
|
-
state.timer = setTimeout(() => this.pollStablePath(path), WRITE_STABILITY_POLL_MS);
|
|
2058
|
-
}
|
|
2059
|
-
scheduleRefreshForAgents(agentNames) {
|
|
2060
|
-
for (const agentName of agentNames) {
|
|
2061
|
-
this.pendingRefreshPathCounts.set(
|
|
2062
|
-
agentName,
|
|
2063
|
-
(this.pendingRefreshPathCounts.get(agentName) ?? 0) + 1
|
|
2064
|
-
);
|
|
2065
|
-
const delayMs = (this.byAgent[agentName]?.length ?? 0) === 0 ? EMPTY_AGENT_REFRESH_DEBOUNCE_MS : REFRESH_DEBOUNCE_MS;
|
|
2066
|
-
this.scheduleRefresh(agentName, delayMs);
|
|
2067
|
-
}
|
|
2068
|
-
}
|
|
2069
|
-
reportWatchError(event, data) {
|
|
2070
|
-
appLogger.error(event, data);
|
|
2071
|
-
console.error("[watch] File watcher failed:", data.error);
|
|
2072
|
-
}
|
|
2073
1906
|
scheduleRefresh(agentName, delayMs = REFRESH_DEBOUNCE_MS) {
|
|
2074
1907
|
appLogger.debug("scan.refresh.schedule", { agent: agentName, delay_ms: delayMs });
|
|
2075
1908
|
const existing = this.refreshTimers.get(agentName);
|
|
@@ -2149,7 +1982,7 @@ var LiveScanStore = class {
|
|
|
2149
1982
|
nextSessions = fullScanSessions;
|
|
2150
1983
|
scanDuration = performance.now() - scanStartedAt;
|
|
2151
1984
|
this.refreshTimestamps.set(agentName, Date.now());
|
|
2152
|
-
} else if (cached &&
|
|
1985
|
+
} else if (cached && agent instanceof FileSystemSessionSource) {
|
|
2153
1986
|
const scanStartedAt = performance.now();
|
|
2154
1987
|
const result = await this.scanAgentInWorker(
|
|
2155
1988
|
agent,
|
|
@@ -2162,7 +1995,7 @@ var LiveScanStore = class {
|
|
|
2162
1995
|
}
|
|
2163
1996
|
);
|
|
2164
1997
|
nextSessions = result.sessions;
|
|
2165
|
-
agent.setSessionMetaMap
|
|
1998
|
+
agent.setSessionMetaMap(new Map(Object.entries(result.meta)));
|
|
2166
1999
|
preciseChangedIds = result.changedIds ?? [];
|
|
2167
2000
|
usedIncrementalScan = true;
|
|
2168
2001
|
persistenceDiff = buildRefreshDiff(
|
|
@@ -2179,7 +2012,7 @@ var LiveScanStore = class {
|
|
|
2179
2012
|
duration_ms: Math.round(performance.now() - startedAt)
|
|
2180
2013
|
});
|
|
2181
2014
|
}
|
|
2182
|
-
} else if (refreshBaseline.length > 0
|
|
2015
|
+
} else if (refreshBaseline.length > 0) {
|
|
2183
2016
|
const checkStartedAt = performance.now();
|
|
2184
2017
|
const checkResult = await Promise.resolve(
|
|
2185
2018
|
agent.checkForChanges(cacheTimestamp, refreshBaseline)
|
|
@@ -2212,7 +2045,7 @@ var LiveScanStore = class {
|
|
|
2212
2045
|
const scanStartedAt = performance.now();
|
|
2213
2046
|
const result = await this.scanAgentInWorker(agent, previousSessions, null, {});
|
|
2214
2047
|
nextSessions = result.sessions;
|
|
2215
|
-
agent.setSessionMetaMap
|
|
2048
|
+
agent.setSessionMetaMap(new Map(Object.entries(result.meta)));
|
|
2216
2049
|
fullScanSessions = attachMissingProjectIdentities(nextSessions);
|
|
2217
2050
|
nextSessions = fullScanSessions;
|
|
2218
2051
|
scanDuration = performance.now() - scanStartedAt;
|
|
@@ -2445,7 +2278,7 @@ var main = defineCommand({
|
|
|
2445
2278
|
log_path: appLogger.getLogPath()
|
|
2446
2279
|
});
|
|
2447
2280
|
if (clearCache) {
|
|
2448
|
-
const { clearCache: clear } = await import("./dist-
|
|
2281
|
+
const { clearCache: clear } = await import("./dist-T737I76S.js");
|
|
2449
2282
|
clear();
|
|
2450
2283
|
appLogger.info("cache.clear");
|
|
2451
2284
|
console.log("Cache cleared.");
|