codesesh 1.0.5 → 1.0.7
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 +1 -0
- package/dist/{chunk-PAP2Q3WV.js → chunk-DE6UJMOY.js} +2 -2
- package/dist/{chunk-YQFEGFWD.js → chunk-EYZ73CYP.js} +2 -2
- package/dist/{chunk-NBJJGH5P.js → chunk-QHWSZFRM.js} +118 -74
- package/dist/chunk-QHWSZFRM.js.map +1 -0
- package/dist/{chunk-WUYSZAYR.js → chunk-SII3M66U.js} +13 -6
- package/dist/chunk-SII3M66U.js.map +1 -0
- package/dist/{chunk-TS3IWH5U.js → chunk-VVCSQU5B.js} +120 -20
- package/dist/chunk-VVCSQU5B.js.map +1 -0
- package/dist/{chunk-FCYCBGEL.js → chunk-WIWK7BXS.js} +3 -3
- package/dist/{chunk-XKZSX5BM.js → chunk-YEQTRALH.js} +3 -3
- package/dist/{discovery-D23RV7FY.js → discovery-4WAEYSTR.js} +7 -5
- package/dist/index.js +217 -150
- package/dist/index.js.map +1 -1
- package/dist/project-identity-worker.js +4 -4
- package/dist/scan-refresh-worker.js +6 -6
- package/dist/search-index-worker.js +6 -6
- package/dist/session-detail-worker.js +6 -6
- package/dist/smart-tag-worker.js +3 -3
- package/dist/web/assets/CustomTimeWindowDialog-CVURkiVO.js +1 -0
- package/dist/web/assets/InteractiveReceipt-DGC-xV7U.js +1 -0
- package/dist/web/assets/OverviewScreen-DoXrZ5qp.js +1 -0
- package/dist/web/assets/{PrismHighlighter-LWITDffT.js → PrismHighlighter-02695Lmx.js} +1 -1
- package/dist/web/assets/Projects-DZiYh6hp.js +1 -0
- package/dist/web/assets/SearchResultsPanel-CAQe8Di0.js +1 -0
- package/dist/web/assets/SessionDetail-Da8EBygt.js +53 -0
- package/dist/web/assets/api-ToidoNW6.js +1 -0
- package/dist/web/assets/index-Bl8pbRFj.js +1423 -0
- package/dist/web/assets/index-CRI1m3xN.css +1 -0
- package/dist/web/assets/session-indexes-D5gps7K8.js +4 -0
- package/dist/web/assets/translate-BDFu3ZiK.js +2 -0
- package/dist/web/assets/utils-BIZi2up3.js +1 -0
- package/dist/web/index.html +7 -7
- package/package.json +3 -3
- package/dist/chunk-NBJJGH5P.js.map +0 -1
- package/dist/chunk-TS3IWH5U.js.map +0 -1
- package/dist/chunk-WUYSZAYR.js.map +0 -1
- package/dist/web/assets/CustomTimeWindowDialog-C9XTZRm0.js +0 -1
- package/dist/web/assets/InteractiveReceipt-Sca1smpv.js +0 -1
- package/dist/web/assets/OverviewScreen-Vq6BQR9_.js +0 -1
- package/dist/web/assets/Projects-CwicV3Dk.js +0 -1
- package/dist/web/assets/SearchResultsPanel-DCO0Ak0c.js +0 -1
- package/dist/web/assets/SessionDetail-mdmTQgo1.js +0 -53
- package/dist/web/assets/api-CXVT9XcZ.js +0 -1
- package/dist/web/assets/contract-BS78VBCV.js +0 -2
- package/dist/web/assets/index-C5cyw58A.css +0 -1
- package/dist/web/assets/index-H2cT-6c6.js +0 -1423
- package/dist/web/assets/session-indexes-yyyWpKLf.js +0 -4
- package/dist/web/assets/utils-C7BqyxxV.js +0 -1
- /package/dist/{chunk-PAP2Q3WV.js.map → chunk-DE6UJMOY.js.map} +0 -0
- /package/dist/{chunk-YQFEGFWD.js.map → chunk-EYZ73CYP.js.map} +0 -0
- /package/dist/{chunk-FCYCBGEL.js.map → chunk-WIWK7BXS.js.map} +0 -0
- /package/dist/{chunk-XKZSX5BM.js.map → chunk-YEQTRALH.js.map} +0 -0
- /package/dist/{discovery-D23RV7FY.js.map → discovery-4WAEYSTR.js.map} +0 -0
package/dist/index.js
CHANGED
|
@@ -4,19 +4,19 @@ import {
|
|
|
4
4
|
buildDashboard,
|
|
5
5
|
getSessionActivityTime,
|
|
6
6
|
summarizeProjects
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-WIWK7BXS.js";
|
|
8
8
|
import {
|
|
9
9
|
AGENT_UNAVAILABLE_DURING_SCAN_ERROR_CODE,
|
|
10
10
|
AgentUnavailableDuringScanError
|
|
11
11
|
} from "./chunk-RF3EEWPH.js";
|
|
12
12
|
import {
|
|
13
13
|
terminateWorkerAfterLogDrain
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-EYZ73CYP.js";
|
|
15
15
|
import "./chunk-QH2HOXJH.js";
|
|
16
16
|
import {
|
|
17
17
|
appLogger,
|
|
18
18
|
logSearchIndexSync
|
|
19
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-DE6UJMOY.js";
|
|
20
20
|
import {
|
|
21
21
|
attachMissingProjectIdentities,
|
|
22
22
|
beginAgentRefresh,
|
|
@@ -29,6 +29,7 @@ import {
|
|
|
29
29
|
getAnalyticsRevision,
|
|
30
30
|
getSearchProjectDirectory,
|
|
31
31
|
listCachedProjectGroups,
|
|
32
|
+
listDashboardActiveHours,
|
|
32
33
|
listDashboardCostFacts,
|
|
33
34
|
listFileActivity,
|
|
34
35
|
loadCachedSessionHeads,
|
|
@@ -50,18 +51,18 @@ import {
|
|
|
50
51
|
sessionMatchesSearchCost,
|
|
51
52
|
sessionSignature,
|
|
52
53
|
sortSessions
|
|
53
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-VVCSQU5B.js";
|
|
54
55
|
import {
|
|
55
56
|
PROJECT_IDENTITY_RESOLVER_REVISION,
|
|
56
57
|
createProjectScopeMatcher,
|
|
57
58
|
createProjectScopeMatcherFromIdentity,
|
|
58
59
|
matchesProjectScope,
|
|
59
60
|
normalizeProjectDirectory
|
|
60
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-YEQTRALH.js";
|
|
61
62
|
import {
|
|
62
63
|
createRegisteredAgents,
|
|
63
64
|
getAgentInfoMap
|
|
64
|
-
} from "./chunk-
|
|
65
|
+
} from "./chunk-SII3M66U.js";
|
|
65
66
|
import {
|
|
66
67
|
CODESESH_OPERATION_ID_HEADER,
|
|
67
68
|
CODESESH_REQUEST_ID_HEADER,
|
|
@@ -96,7 +97,7 @@ import {
|
|
|
96
97
|
tableExists,
|
|
97
98
|
toPublicReferencedSessionHead,
|
|
98
99
|
toPublicSessionHead
|
|
99
|
-
} from "./chunk-
|
|
100
|
+
} from "./chunk-QHWSZFRM.js";
|
|
100
101
|
|
|
101
102
|
// src/index.ts
|
|
102
103
|
import { defineCommand, runMain } from "citty";
|
|
@@ -574,14 +575,8 @@ function parseDateWindowRequest(c, endpoint, defaults) {
|
|
|
574
575
|
|
|
575
576
|
// src/api/snapshot-pagination.ts
|
|
576
577
|
import { createHash, randomUUID } from "crypto";
|
|
577
|
-
var
|
|
578
|
-
|
|
579
|
-
const existing = identityVersions.get(identity);
|
|
580
|
-
if (existing) return existing;
|
|
581
|
-
const version = randomUUID();
|
|
582
|
-
identityVersions.set(identity, version);
|
|
583
|
-
return version;
|
|
584
|
-
}
|
|
578
|
+
var SNAPSHOT_TTL_MS = 6e4;
|
|
579
|
+
var SNAPSHOT_LIMIT = 32;
|
|
585
580
|
function queryFingerprint(params) {
|
|
586
581
|
const canonical = new URLSearchParams(params);
|
|
587
582
|
canonical.delete("cursor");
|
|
@@ -598,7 +593,7 @@ function decodeCursor(cursor) {
|
|
|
598
593
|
const value = JSON.parse(
|
|
599
594
|
Buffer.from(cursor, "base64url").toString("utf8")
|
|
600
595
|
);
|
|
601
|
-
if (value.version !== 1 || typeof value.snapshot !== "string" ||
|
|
596
|
+
if (value.version !== 1 || typeof value.snapshot !== "string" || !Number.isSafeInteger(value.offset) || value.offset <= 0) {
|
|
602
597
|
return null;
|
|
603
598
|
}
|
|
604
599
|
return value;
|
|
@@ -606,26 +601,47 @@ function decodeCursor(cursor) {
|
|
|
606
601
|
return null;
|
|
607
602
|
}
|
|
608
603
|
}
|
|
609
|
-
function
|
|
610
|
-
const
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
604
|
+
function createSnapshotPaginator() {
|
|
605
|
+
const snapshotsBySource = /* @__PURE__ */ new WeakMap();
|
|
606
|
+
return function paginateSnapshot(source, request, load) {
|
|
607
|
+
const snapshots = snapshotsBySource.get(source) ?? /* @__PURE__ */ new Map();
|
|
608
|
+
const now = Date.now();
|
|
609
|
+
for (const [id, snapshot2] of snapshots) {
|
|
610
|
+
if (snapshot2.expiresAt <= now) snapshots.delete(id);
|
|
611
|
+
}
|
|
612
|
+
const query = queryFingerprint(request.query);
|
|
613
|
+
let snapshot;
|
|
614
|
+
let snapshotId;
|
|
615
|
+
let offset = 0;
|
|
616
|
+
if (request.cursor) {
|
|
617
|
+
const cursor = decodeCursor(request.cursor);
|
|
618
|
+
if (!cursor) return { kind: "invalid_cursor" };
|
|
619
|
+
const retained = snapshots.get(cursor.snapshot);
|
|
620
|
+
if (!retained) return { kind: "stale_snapshot" };
|
|
621
|
+
if (retained.query !== query || cursor.offset >= retained.items.length) {
|
|
622
|
+
return { kind: "invalid_cursor" };
|
|
623
|
+
}
|
|
624
|
+
snapshot = retained;
|
|
625
|
+
snapshotId = cursor.snapshot;
|
|
626
|
+
offset = cursor.offset;
|
|
627
|
+
} else {
|
|
628
|
+
const loaded = load();
|
|
629
|
+
snapshot = { ...loaded, items: [...loaded.items], query, expiresAt: now + SNAPSHOT_TTL_MS };
|
|
630
|
+
snapshotId = randomUUID();
|
|
619
631
|
}
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
632
|
+
const end = Math.min(offset + request.limit, snapshot.items.length);
|
|
633
|
+
const nextCursor = end < snapshot.items.length ? encodeCursor({ version: 1, snapshot: snapshotId, offset: end }) : void 0;
|
|
634
|
+
if (!request.cursor && nextCursor) {
|
|
635
|
+
if (snapshots.size >= SNAPSHOT_LIMIT) snapshots.delete(snapshots.keys().next().value);
|
|
636
|
+
snapshots.set(snapshotId, snapshot);
|
|
637
|
+
snapshotsBySource.set(source, snapshots);
|
|
638
|
+
}
|
|
639
|
+
return {
|
|
640
|
+
kind: "page",
|
|
641
|
+
items: snapshot.items.slice(offset, end),
|
|
642
|
+
view: snapshot.view,
|
|
643
|
+
...nextCursor ? { nextCursor } : {}
|
|
644
|
+
};
|
|
629
645
|
};
|
|
630
646
|
}
|
|
631
647
|
|
|
@@ -663,18 +679,20 @@ function getSnapshotSessionTree(source, sessions) {
|
|
|
663
679
|
const cache = getSnapshotAggregationCache(source, sessions);
|
|
664
680
|
return cache.sessionTree ??= buildSessionTree(sessions);
|
|
665
681
|
}
|
|
666
|
-
function
|
|
667
|
-
const
|
|
682
|
+
function getSnapshotCostFacts(source, sessions, from, to, cacheTo, analyticsRevision) {
|
|
683
|
+
const costFrom = from === 0 ? void 0 : from;
|
|
684
|
+
const build = () => listDashboardCostFacts({ from: costFrom, to });
|
|
668
685
|
if (analyticsRevision === null) return build();
|
|
669
686
|
return getSnapshotAggregation(
|
|
670
687
|
source,
|
|
671
688
|
sessions,
|
|
672
|
-
["
|
|
689
|
+
["cost-facts", costFrom, cacheTo, analyticsRevision],
|
|
673
690
|
build
|
|
674
691
|
);
|
|
675
692
|
}
|
|
676
|
-
function getDashboardStorageAggregation(source, sessions, scope, from, to, cacheTo, analyticsRevision) {
|
|
693
|
+
function getDashboardStorageAggregation(source, sessions, scope, from, to, cacheTo, analyticsRevision, timeZone) {
|
|
677
694
|
const build = () => ({
|
|
695
|
+
activeHours: listDashboardActiveHours({ ...scope, from, to, timeZone }, source.queryScope),
|
|
678
696
|
recentFileActivities: listFileActivity(
|
|
679
697
|
{
|
|
680
698
|
agent: scope.agent,
|
|
@@ -705,6 +723,7 @@ function getDashboardStorageAggregation(source, sessions, scope, from, to, cache
|
|
|
705
723
|
sessions,
|
|
706
724
|
[
|
|
707
725
|
"dashboard-storage",
|
|
726
|
+
timeZone,
|
|
708
727
|
scope.agent,
|
|
709
728
|
scope.projectKind,
|
|
710
729
|
scope.projectKey,
|
|
@@ -718,6 +737,7 @@ function getDashboardStorageAggregation(source, sessions, scope, from, to, cache
|
|
|
718
737
|
}
|
|
719
738
|
|
|
720
739
|
// src/api/catalog-handlers.ts
|
|
740
|
+
var paginateProjects = createSnapshotPaginator();
|
|
721
741
|
function handleGetConfig(c, defaults) {
|
|
722
742
|
const payload = {
|
|
723
743
|
window: {
|
|
@@ -770,46 +790,54 @@ function handleGetProjects(c, scanSource, defaults = {}) {
|
|
|
770
790
|
const window = parseDateWindowRequest(c, "projects", defaults);
|
|
771
791
|
if (window.kind === "rejected") return window.response;
|
|
772
792
|
const { from, to } = window;
|
|
773
|
-
const
|
|
774
|
-
|
|
793
|
+
const loadSnapshot = () => {
|
|
794
|
+
const analyticsRevision = getAnalyticsRevision();
|
|
795
|
+
const catalog = getSnapshotAggregation(
|
|
796
|
+
scanSource,
|
|
797
|
+
scanResult.sessions,
|
|
798
|
+
["projects", from, to, analyticsRevision],
|
|
799
|
+
() => {
|
|
800
|
+
const tree = getSnapshotSessionTree(scanSource, scanResult.sessions);
|
|
801
|
+
const costFacts = (from == null || from === 0) && to == null ? getSnapshotCostFacts(scanSource, scanResult.sessions, from, to, to, analyticsRevision) : listDashboardCostFacts({ from, to, includeModelCosts: false });
|
|
802
|
+
const projects2 = attachProjectMetricsFromTree(
|
|
803
|
+
listCachedProjectGroups(scanResult.sessions),
|
|
804
|
+
tree,
|
|
805
|
+
from,
|
|
806
|
+
to,
|
|
807
|
+
costFacts
|
|
808
|
+
).filter(
|
|
809
|
+
(project) => project.sessionCount > 0 || project.messages > 0 || project.tokens > 0 || project.cost > 0
|
|
810
|
+
);
|
|
811
|
+
return { projects: projects2, summary: summarizeProjects(projects2) };
|
|
812
|
+
}
|
|
813
|
+
);
|
|
814
|
+
const projects = projectIdentity ? catalog.projects.filter(
|
|
815
|
+
(project) => project.identityKind === projectIdentity.kind && project.identityKey === projectIdentity.key
|
|
816
|
+
) : catalog.projects;
|
|
817
|
+
return {
|
|
818
|
+
items: projects,
|
|
819
|
+
view: projectIdentity ? summarizeProjects(projects) : catalog.summary
|
|
820
|
+
};
|
|
821
|
+
};
|
|
822
|
+
const page = paginateProjects(
|
|
775
823
|
scanSource,
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
listCachedProjectGroups(scanResult.sessions),
|
|
783
|
-
tree,
|
|
784
|
-
from,
|
|
785
|
-
to,
|
|
786
|
-
costFacts
|
|
787
|
-
).filter(
|
|
788
|
-
(project) => project.sessionCount > 0 || project.messages > 0 || project.tokens > 0 || project.cost > 0
|
|
789
|
-
);
|
|
790
|
-
return { projects: projects2, summary: summarizeProjects(projects2) };
|
|
791
|
-
}
|
|
824
|
+
{
|
|
825
|
+
cursor: params.get("cursor") ?? void 0,
|
|
826
|
+
limit: limit.value,
|
|
827
|
+
query: params
|
|
828
|
+
},
|
|
829
|
+
loadSnapshot
|
|
792
830
|
);
|
|
793
|
-
const projects = projectIdentity ? catalog.projects.filter(
|
|
794
|
-
(project) => project.identityKind === projectIdentity.kind && project.identityKey === projectIdentity.key
|
|
795
|
-
) : catalog.projects;
|
|
796
|
-
const page = paginateSnapshot(projects, {
|
|
797
|
-
cursor: params.get("cursor") ?? void 0,
|
|
798
|
-
limit: limit.value,
|
|
799
|
-
query: params,
|
|
800
|
-
snapshotIdentity: scanResult.sessions,
|
|
801
|
-
viewIdentity: catalog.projects
|
|
802
|
-
});
|
|
803
831
|
if (page.kind === "invalid_cursor") {
|
|
804
832
|
reportInvalidQueryParameter("projects", "cursor", "rejected");
|
|
805
833
|
return c.json({ error: "cursor is invalid for this request" }, 400);
|
|
806
834
|
}
|
|
807
835
|
if (page.kind === "stale_snapshot") {
|
|
808
|
-
return c.json({ error: "project snapshot
|
|
836
|
+
return c.json({ error: "project snapshot expired; restart pagination" }, 409);
|
|
809
837
|
}
|
|
810
838
|
return c.json({
|
|
811
839
|
projects: page.items,
|
|
812
|
-
summary:
|
|
840
|
+
summary: page.view,
|
|
813
841
|
...page.nextCursor ? { nextCursor: page.nextCursor } : {}
|
|
814
842
|
});
|
|
815
843
|
}
|
|
@@ -1453,12 +1481,13 @@ function readAliasView() {
|
|
|
1453
1481
|
}
|
|
1454
1482
|
}
|
|
1455
1483
|
var EMPTY_ALIAS_VIEW = buildAliasView(/* @__PURE__ */ new Map());
|
|
1484
|
+
var ALIAS_VIEW_TTL_MS = 1e3;
|
|
1456
1485
|
var cachedView = null;
|
|
1457
1486
|
function loadAliasView() {
|
|
1458
|
-
if (cachedView) return cachedView;
|
|
1487
|
+
if (cachedView && Date.now() < cachedView.expiresAt) return cachedView.view;
|
|
1459
1488
|
const loaded = readAliasView();
|
|
1460
1489
|
if (!loaded) return EMPTY_ALIAS_VIEW;
|
|
1461
|
-
cachedView = loaded;
|
|
1490
|
+
cachedView = { view: loaded, expiresAt: Date.now() + ALIAS_VIEW_TTL_MS };
|
|
1462
1491
|
return loaded;
|
|
1463
1492
|
}
|
|
1464
1493
|
function invalidateAliasView() {
|
|
@@ -1518,6 +1547,14 @@ function findAliasSearchResults(query, options, scanResult, aliases, context = {
|
|
|
1518
1547
|
|
|
1519
1548
|
// src/api/dashboard-handler.ts
|
|
1520
1549
|
function handleGetDashboard(c, scanSource, defaults = {}) {
|
|
1550
|
+
let timeZone;
|
|
1551
|
+
try {
|
|
1552
|
+
timeZone = new Intl.DateTimeFormat("en", {
|
|
1553
|
+
timeZone: optionalQueryValue(c.req.query("timeZone")) ?? Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
1554
|
+
}).resolvedOptions().timeZone;
|
|
1555
|
+
} catch {
|
|
1556
|
+
return c.json({ error: "timeZone must be a valid IANA time zone" }, 400);
|
|
1557
|
+
}
|
|
1521
1558
|
const scanResult = scanSource.getSnapshot();
|
|
1522
1559
|
const projectIdentity = parseProjectIdentityFilter(
|
|
1523
1560
|
c.req.query("projectKind"),
|
|
@@ -1543,12 +1580,12 @@ function handleGetDashboard(c, scanSource, defaults = {}) {
|
|
|
1543
1580
|
const fixedTo = dateWindow.to;
|
|
1544
1581
|
const cacheTo = fixedTo ?? startOfCalendarDay(to);
|
|
1545
1582
|
const analyticsRevision = getAnalyticsRevision();
|
|
1546
|
-
const costFacts =
|
|
1583
|
+
const costFacts = getSnapshotCostFacts(
|
|
1547
1584
|
scanSource,
|
|
1548
1585
|
scanResult.sessions,
|
|
1549
1586
|
compare?.from ?? from,
|
|
1550
|
-
to,
|
|
1551
|
-
cacheTo,
|
|
1587
|
+
from == null && fixedTo == null ? void 0 : to,
|
|
1588
|
+
from == null && fixedTo == null ? void 0 : cacheTo,
|
|
1552
1589
|
analyticsRevision
|
|
1553
1590
|
);
|
|
1554
1591
|
const aggregate = getSnapshotAggregation(
|
|
@@ -1586,7 +1623,8 @@ function handleGetDashboard(c, scanSource, defaults = {}) {
|
|
|
1586
1623
|
from,
|
|
1587
1624
|
to,
|
|
1588
1625
|
cacheTo,
|
|
1589
|
-
analyticsRevision
|
|
1626
|
+
analyticsRevision,
|
|
1627
|
+
timeZone
|
|
1590
1628
|
);
|
|
1591
1629
|
const data = {
|
|
1592
1630
|
...aggregate,
|
|
@@ -1932,6 +1970,7 @@ function createSessionDetailJsonResponse(data, messages) {
|
|
|
1932
1970
|
}
|
|
1933
1971
|
|
|
1934
1972
|
// src/api/session-handlers.ts
|
|
1973
|
+
var paginateSessions = createSnapshotPaginator();
|
|
1935
1974
|
function getSessionHeadReference(session) {
|
|
1936
1975
|
return session.reference;
|
|
1937
1976
|
}
|
|
@@ -1973,64 +2012,72 @@ async function handleGetSessions(c, scanSource, defaults = {}, resolver) {
|
|
|
1973
2012
|
if (sessionQuery.agent.kind === "unknown") {
|
|
1974
2013
|
reportInvalidQueryParameter("sessions", "agent", "empty_result");
|
|
1975
2014
|
}
|
|
1976
|
-
const
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2015
|
+
const loadSnapshot = () => {
|
|
2016
|
+
const agentFilter = sessionQuery.agent.kind === "known" ? sessionQuery.agent.agentName : sessionQuery.agent.kind;
|
|
2017
|
+
let sessions2 = getSnapshotAggregation(
|
|
2018
|
+
scanSource,
|
|
2019
|
+
scanResult.sessions,
|
|
2020
|
+
[
|
|
2021
|
+
"sessions",
|
|
2022
|
+
agentFilter,
|
|
2023
|
+
projectIdentity?.kind,
|
|
2024
|
+
projectIdentity?.key,
|
|
2025
|
+
projectScope?.identity.kind,
|
|
2026
|
+
projectScope?.identity.key,
|
|
2027
|
+
projectScope?.path,
|
|
2028
|
+
tag,
|
|
2029
|
+
from,
|
|
2030
|
+
to
|
|
2031
|
+
],
|
|
2032
|
+
() => {
|
|
2033
|
+
let filtered = sessionQuery.agent.kind === "all" ? scanResult.sessions : sessionQuery.agent.kind === "known" ? scanResult.byAgent[sessionQuery.agent.agentName] ?? [] : [];
|
|
2034
|
+
if (projectIdentity) {
|
|
2035
|
+
filtered = filtered.filter(
|
|
2036
|
+
(session) => matchesProjectIdentity(session.project_identity, projectIdentity)
|
|
2037
|
+
);
|
|
2038
|
+
} else if (projectScope) {
|
|
2039
|
+
filtered = filtered.filter(
|
|
2040
|
+
(session) => matchesProjectScope(session, projectScope)
|
|
2041
|
+
);
|
|
2042
|
+
}
|
|
2043
|
+
filtered = filterSessionsByActivityWindow(filtered, from, to);
|
|
2044
|
+
return tag ? filtered.filter((session) => session.smart_tags?.includes(tag)) : filtered;
|
|
2000
2045
|
}
|
|
2001
|
-
|
|
2002
|
-
|
|
2046
|
+
);
|
|
2047
|
+
const aliases2 = loadAliasView();
|
|
2048
|
+
if (q) {
|
|
2049
|
+
sessions2 = sessions2.filter((session) => {
|
|
2050
|
+
const alias = aliases2.get(getSessionHeadReference(session));
|
|
2051
|
+
return session.title.toLowerCase().includes(q) || alias?.toLowerCase().includes(q);
|
|
2052
|
+
});
|
|
2003
2053
|
}
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
if (q) {
|
|
2007
|
-
sessions = sessions.filter((session) => {
|
|
2008
|
-
const alias = aliases.get(getSessionHeadReference(session));
|
|
2009
|
-
return session.title.toLowerCase().includes(q) || alias?.toLowerCase().includes(q);
|
|
2010
|
-
});
|
|
2011
|
-
}
|
|
2054
|
+
return { items: sessions2, view: aliases2 };
|
|
2055
|
+
};
|
|
2012
2056
|
if (paginationRequested) {
|
|
2013
|
-
const page =
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2057
|
+
const page = paginateSessions(
|
|
2058
|
+
scanSource,
|
|
2059
|
+
{
|
|
2060
|
+
cursor: params.get("cursor") ?? void 0,
|
|
2061
|
+
limit: sessionQuery.limit.value,
|
|
2062
|
+
query: params
|
|
2063
|
+
},
|
|
2064
|
+
loadSnapshot
|
|
2065
|
+
);
|
|
2020
2066
|
if (page.kind === "invalid_cursor") {
|
|
2021
2067
|
reportInvalidQueryParameter("sessions", "cursor", "rejected");
|
|
2022
2068
|
return c.json({ error: "cursor is invalid for this request" }, 400);
|
|
2023
2069
|
}
|
|
2024
2070
|
if (page.kind === "stale_snapshot") {
|
|
2025
|
-
return c.json({ error: "session snapshot
|
|
2071
|
+
return c.json({ error: "session snapshot expired; restart pagination" }, 409);
|
|
2026
2072
|
}
|
|
2027
2073
|
return c.json({
|
|
2028
2074
|
sessions: page.items.map(
|
|
2029
|
-
(session) => toPublicSessionHead(
|
|
2075
|
+
(session) => toPublicSessionHead(page.view.decorate(session, getSessionHeadReference(session)))
|
|
2030
2076
|
),
|
|
2031
2077
|
...page.nextCursor ? { nextCursor: page.nextCursor } : {}
|
|
2032
2078
|
});
|
|
2033
2079
|
}
|
|
2080
|
+
const { items: sessions, view: aliases } = loadSnapshot();
|
|
2034
2081
|
return c.json({
|
|
2035
2082
|
sessions: sessions.map(
|
|
2036
2083
|
(session) => toPublicSessionHead(aliases.decorate(session, getSessionHeadReference(session)))
|
|
@@ -2061,7 +2108,8 @@ async function handleGetSessionData(c, scanSource, loadDetail = materializeSessi
|
|
|
2061
2108
|
session_id: sessionId,
|
|
2062
2109
|
duration_ms: Math.round(performance.now() - startedAt)
|
|
2063
2110
|
});
|
|
2064
|
-
|
|
2111
|
+
c.header("Retry-After", "1");
|
|
2112
|
+
return c.json({ error: "Session detail not ready; retry later" }, 503);
|
|
2065
2113
|
}
|
|
2066
2114
|
appLogger.info("api.session_data", {
|
|
2067
2115
|
agent: agentName,
|
|
@@ -2248,7 +2296,7 @@ function handleGetBookmarks(c, scanSource) {
|
|
|
2248
2296
|
storageAvailable: true
|
|
2249
2297
|
});
|
|
2250
2298
|
},
|
|
2251
|
-
() => c.json({
|
|
2299
|
+
() => c.json({ error: "Bookmark storage is unavailable" }, 503)
|
|
2252
2300
|
);
|
|
2253
2301
|
}
|
|
2254
2302
|
function isKnownAgentKey(agentKey) {
|
|
@@ -2548,7 +2596,19 @@ function createSseResponse(eventSource, requestSignal, shutdownSignal, closeConn
|
|
|
2548
2596
|
buffer.enqueue("connected", { timestamp: Date.now() });
|
|
2549
2597
|
buffer.enqueueScanStatus(eventSource.getScanStatus());
|
|
2550
2598
|
unsubscribeSessions = eventSource.subscribe((event) => {
|
|
2551
|
-
|
|
2599
|
+
if (isClosed) return;
|
|
2600
|
+
const aliases = loadAliasView();
|
|
2601
|
+
buffer?.enqueue(event.type, {
|
|
2602
|
+
...event,
|
|
2603
|
+
changedSessionHeads: event.changedSessionHeads.map((change) => ({
|
|
2604
|
+
...change,
|
|
2605
|
+
session: aliases.decorate(change.session, change.reference)
|
|
2606
|
+
})),
|
|
2607
|
+
projectionRelatedSessionHeads: event.projectionRelatedSessionHeads?.map((change) => ({
|
|
2608
|
+
...change,
|
|
2609
|
+
session: aliases.decorate(change.session, change.reference)
|
|
2610
|
+
}))
|
|
2611
|
+
});
|
|
2552
2612
|
});
|
|
2553
2613
|
unsubscribeScanStatus = eventSource.subscribeScanStatus((event) => {
|
|
2554
2614
|
buffer?.enqueueScanStatus(event);
|
|
@@ -5588,31 +5648,31 @@ var AgentSyncEngine = class {
|
|
|
5588
5648
|
try {
|
|
5589
5649
|
const { result } = workerRun;
|
|
5590
5650
|
const sessions2 = attachMissingProjectIdentities(result.sessions);
|
|
5651
|
+
const persistenceDiff = buildSessionPersistenceDiff(baseline, sessions2, {
|
|
5652
|
+
// Worker-reported IDs also preserve metadata-only pricing repairs.
|
|
5653
|
+
candidateChangedIds: result.changedIds ?? [],
|
|
5654
|
+
completeness: result.completeness,
|
|
5655
|
+
explicitRemovedSessionIds: result.explicitRemovedSessionIds
|
|
5656
|
+
});
|
|
5657
|
+
const strategy = this.refreshStrategyBase(sessions2, result.completeness, scope, {
|
|
5658
|
+
checkDuration,
|
|
5659
|
+
scanDuration: performance.now() - scanStartedAt,
|
|
5660
|
+
sourceFailures: result.sourceFailures ?? [],
|
|
5661
|
+
workerRun,
|
|
5662
|
+
pendingAgentState: {
|
|
5663
|
+
meta: result.meta,
|
|
5664
|
+
refreshedAt: checkResult.timestamp,
|
|
5665
|
+
refreshTransaction
|
|
5666
|
+
}
|
|
5667
|
+
});
|
|
5668
|
+
if (persistenceDiff.changedSessions.length === 0 && persistenceDiff.removedSessionIds.length === 0 && (result.sourceFailures?.length ?? 0) === 0) {
|
|
5669
|
+
this.logUnchangedRefresh(agent.name, refreshStartedAt);
|
|
5670
|
+
return { ...strategy, status: "unchanged" };
|
|
5671
|
+
}
|
|
5591
5672
|
return {
|
|
5592
|
-
...
|
|
5593
|
-
checkDuration,
|
|
5594
|
-
scanDuration: performance.now() - scanStartedAt,
|
|
5595
|
-
sourceFailures: result.sourceFailures ?? [],
|
|
5596
|
-
workerRun,
|
|
5597
|
-
pendingAgentState: {
|
|
5598
|
-
meta: result.meta,
|
|
5599
|
-
refreshedAt: checkResult.timestamp,
|
|
5600
|
-
refreshTransaction
|
|
5601
|
-
}
|
|
5602
|
-
}),
|
|
5673
|
+
...strategy,
|
|
5603
5674
|
status: "continue",
|
|
5604
|
-
publication: {
|
|
5605
|
-
kind: "changes",
|
|
5606
|
-
// Meta-only changes (e.g. a pricing capture epoch bump) leave the head
|
|
5607
|
-
// signature intact; without the worker-reported ids they would never
|
|
5608
|
-
// persist and checkForChanges would rescan on every startup.
|
|
5609
|
-
diff: buildSessionPersistenceDiff(baseline, sessions2, {
|
|
5610
|
-
candidateChangedIds: result.changedIds ?? [],
|
|
5611
|
-
completeness: result.completeness,
|
|
5612
|
-
explicitRemovedSessionIds: result.explicitRemovedSessionIds
|
|
5613
|
-
}),
|
|
5614
|
-
candidateChangedIds: []
|
|
5615
|
-
}
|
|
5675
|
+
publication: { kind: "changes", diff: persistenceDiff, candidateChangedIds: [] }
|
|
5616
5676
|
};
|
|
5617
5677
|
} catch (error) {
|
|
5618
5678
|
workerRun.discard();
|
|
@@ -5835,7 +5895,7 @@ var AgentSyncEngine = class {
|
|
|
5835
5895
|
|
|
5836
5896
|
// src/session-watcher.ts
|
|
5837
5897
|
import { existsSync as existsSync3, readdirSync, statSync, watch } from "fs";
|
|
5838
|
-
import { dirname as dirname2, isAbsolute, join as join2, relative, resolve as resolve2 } from "path";
|
|
5898
|
+
import { basename, dirname as dirname2, isAbsolute, join as join2, relative, resolve as resolve2 } from "path";
|
|
5839
5899
|
var WRITE_STABILITY_THRESHOLD_MS = 250;
|
|
5840
5900
|
var WRITE_STABILITY_POLL_MS = 100;
|
|
5841
5901
|
function toAbsolutePath(path) {
|
|
@@ -5941,7 +6001,11 @@ var SessionWatcher = class {
|
|
|
5941
6001
|
const targetPath = toAbsolutePath(target.path);
|
|
5942
6002
|
const scopes = scopesByRoot.get(rootPath) ?? [];
|
|
5943
6003
|
if (!scopes.some((scope) => scope.agentName === agent.name && scope.targetPath === targetPath)) {
|
|
5944
|
-
scopes.push({
|
|
6004
|
+
scopes.push({
|
|
6005
|
+
agentName: agent.name,
|
|
6006
|
+
targetPath,
|
|
6007
|
+
ignoredFileNames: target.ignoredFileNames
|
|
6008
|
+
});
|
|
5945
6009
|
}
|
|
5946
6010
|
scopesByRoot.set(rootPath, scopes);
|
|
5947
6011
|
}
|
|
@@ -6060,7 +6124,9 @@ var SessionWatcher = class {
|
|
|
6060
6124
|
handleWatchEvent(watchPath, scopes, eventType, filename) {
|
|
6061
6125
|
const changedPath = resolveWatchEventPath(watchPath, filename);
|
|
6062
6126
|
const agentNames = new Set(
|
|
6063
|
-
scopes.filter(
|
|
6127
|
+
scopes.filter(
|
|
6128
|
+
(scope) => isRelatedPath(changedPath, scope.targetPath) && !(scope.ignoredFileNames?.includes(basename(changedPath)) && changedPath !== scope.targetPath && isSameOrChildPath(scope.targetPath, changedPath))
|
|
6129
|
+
).map((scope) => scope.agentName)
|
|
6064
6130
|
);
|
|
6065
6131
|
if (agentNames.size === 0) {
|
|
6066
6132
|
return;
|
|
@@ -6712,7 +6778,8 @@ function startPricingRefresh(timeoutMs = REFRESH_TIMEOUT_MS) {
|
|
|
6712
6778
|
}
|
|
6713
6779
|
);
|
|
6714
6780
|
return {
|
|
6715
|
-
|
|
6781
|
+
async ready() {
|
|
6782
|
+
await completion;
|
|
6716
6783
|
if (publishPendingPricing()) appLogger.info("pricing.refresh.published", {});
|
|
6717
6784
|
},
|
|
6718
6785
|
async cancel() {
|
|
@@ -6886,7 +6953,7 @@ var main = defineCommand({
|
|
|
6886
6953
|
log_path: appLogger.getLogPath()
|
|
6887
6954
|
});
|
|
6888
6955
|
if (clearCache) {
|
|
6889
|
-
const { clearCache: clear } = await import("./discovery-
|
|
6956
|
+
const { clearCache: clear } = await import("./discovery-4WAEYSTR.js");
|
|
6890
6957
|
clear();
|
|
6891
6958
|
appLogger.info("cache.clear");
|
|
6892
6959
|
console.log("Cache cleared.");
|
|
@@ -6915,6 +6982,7 @@ var main = defineCommand({
|
|
|
6915
6982
|
{ currentWorkingDirectory: process.cwd() }
|
|
6916
6983
|
);
|
|
6917
6984
|
const { from: listDefaultFrom, to: listDefaultTo, days: listDefaultDays } = listWindow;
|
|
6985
|
+
await pricingRefresh.ready();
|
|
6918
6986
|
const store = new LiveScanStore({
|
|
6919
6987
|
watchEnabled: !jsonOnly,
|
|
6920
6988
|
scanOptions,
|
|
@@ -6978,7 +7046,6 @@ var main = defineCommand({
|
|
|
6978
7046
|
}
|
|
6979
7047
|
const { url } = app;
|
|
6980
7048
|
if (!jsonOnly) {
|
|
6981
|
-
pricingRefresh.publish();
|
|
6982
7049
|
store.startBackgroundRefresh();
|
|
6983
7050
|
}
|
|
6984
7051
|
let shuttingDown = false;
|