sentinelayer-cli 0.31.2 → 0.31.4
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/package.json +1 -1
- package/src/commands/session.js +36 -4
- package/src/session/recap.js +67 -21
package/package.json
CHANGED
package/src/commands/session.js
CHANGED
|
@@ -641,6 +641,28 @@ function buildSessionActionEvents(sessionId, actions = []) {
|
|
|
641
641
|
.filter(Boolean);
|
|
642
642
|
}
|
|
643
643
|
|
|
644
|
+
function filterSessionActionEventsForTranscriptWindow(actionEvents = [], transcriptEvents = []) {
|
|
645
|
+
if (!Array.isArray(actionEvents) || actionEvents.length === 0) return [];
|
|
646
|
+
if (!Array.isArray(transcriptEvents) || transcriptEvents.length === 0) return [];
|
|
647
|
+
const targetSequences = new Set();
|
|
648
|
+
const targetCursors = new Set();
|
|
649
|
+
for (const event of transcriptEvents) {
|
|
650
|
+
const sequence = eventSequenceNumber(event);
|
|
651
|
+
if (sequence > 0) targetSequences.add(sequence);
|
|
652
|
+
const cursor = normalizeString(event?.cursor);
|
|
653
|
+
if (cursor) targetCursors.add(cursor);
|
|
654
|
+
}
|
|
655
|
+
return actionEvents.filter((event) => {
|
|
656
|
+
const payload = event?.payload || {};
|
|
657
|
+
const sequence = Number(payload.targetSequenceId || 0);
|
|
658
|
+
if (Number.isFinite(sequence) && sequence > 0 && targetSequences.has(Math.floor(sequence))) {
|
|
659
|
+
return true;
|
|
660
|
+
}
|
|
661
|
+
const cursor = normalizeString(payload.targetCursor);
|
|
662
|
+
return Boolean(cursor && targetCursors.has(cursor));
|
|
663
|
+
});
|
|
664
|
+
}
|
|
665
|
+
|
|
644
666
|
function readProjectionUnacknowledgedHumanMessages(remoteActions = null) {
|
|
645
667
|
const messages = remoteActions?.projection?.unacknowledgedHumanMessages;
|
|
646
668
|
return Array.isArray(messages)
|
|
@@ -5530,7 +5552,7 @@ export function registerSessionCommand(program) {
|
|
|
5530
5552
|
}
|
|
5531
5553
|
}
|
|
5532
5554
|
}
|
|
5533
|
-
const
|
|
5555
|
+
const rawActionEvents = remoteActions?.ok
|
|
5534
5556
|
? buildSessionActionEvents(normalizedSessionId, remoteActions.actions)
|
|
5535
5557
|
: [];
|
|
5536
5558
|
const unacknowledgedHumanMessages = remoteActions?.ok
|
|
@@ -5540,10 +5562,20 @@ export function registerSessionCommand(program) {
|
|
|
5540
5562
|
? readProjectionRecentHumanActivity(remoteActions)
|
|
5541
5563
|
: [];
|
|
5542
5564
|
const dedupedDisplayEvents = dedupeSessionEvents(displayEvents);
|
|
5565
|
+
const remoteWindowRead = Boolean(options.remote && beforeSequence);
|
|
5566
|
+
const remoteWindowEvents = remoteTail?.ok
|
|
5567
|
+
? dedupeSessionEvents(Array.isArray(remoteTailAppendEvents) ? remoteTailAppendEvents : [])
|
|
5568
|
+
: [];
|
|
5569
|
+
const sourceEvents = remoteWindowRead && remoteTail?.ok
|
|
5570
|
+
? remoteWindowEvents
|
|
5571
|
+
: dedupedDisplayEvents;
|
|
5543
5572
|
const transcriptEvents = includeControlEvents
|
|
5544
|
-
?
|
|
5545
|
-
:
|
|
5546
|
-
const hiddenControlEventCount =
|
|
5573
|
+
? sourceEvents
|
|
5574
|
+
: sourceEvents.filter((event) => !isSessionControlEvent(event));
|
|
5575
|
+
const hiddenControlEventCount = sourceEvents.length - transcriptEvents.length;
|
|
5576
|
+
const actionEvents = remoteWindowRead
|
|
5577
|
+
? filterSessionActionEventsForTranscriptWindow(rawActionEvents, transcriptEvents)
|
|
5578
|
+
: rawActionEvents;
|
|
5547
5579
|
const events = mergeSessionActionEvents(transcriptEvents, actionEvents).slice(-tail);
|
|
5548
5580
|
const autoView = recordSessionReadViews(normalizedSessionId, events, {
|
|
5549
5581
|
targetPath,
|
package/src/session/recap.js
CHANGED
|
@@ -4,6 +4,7 @@ import process from "node:process";
|
|
|
4
4
|
|
|
5
5
|
import { createAgentEvent } from "../events/schema.js";
|
|
6
6
|
import { dedupeSessionEvents } from "./event-identity.js";
|
|
7
|
+
import { summarizeListeners } from "./listeners.js";
|
|
7
8
|
import { resolveSessionPaths } from "./paths.js";
|
|
8
9
|
import { appendToStream, readStream } from "./stream.js";
|
|
9
10
|
import { getSession } from "./store.js";
|
|
@@ -28,6 +29,10 @@ const RECAP_SOURCE_IGNORED_EVENTS = new Set([
|
|
|
28
29
|
"daemon_alert",
|
|
29
30
|
"session_ack",
|
|
30
31
|
"session_checkpoint",
|
|
32
|
+
"session_listen_error",
|
|
33
|
+
"session_listener_heartbeat",
|
|
34
|
+
"session_listener_started",
|
|
35
|
+
"session_listener_stopped",
|
|
31
36
|
"session_reaction",
|
|
32
37
|
"session_recap",
|
|
33
38
|
"session_usage",
|
|
@@ -648,7 +653,9 @@ function buildRecapKey(sessionId, targetPath) {
|
|
|
648
653
|
}
|
|
649
654
|
|
|
650
655
|
function buildRecapText({
|
|
651
|
-
|
|
656
|
+
recentActors = [],
|
|
657
|
+
liveListeners = [],
|
|
658
|
+
listenerCount = 0,
|
|
652
659
|
totalFindings = 0,
|
|
653
660
|
activeLocks = 0,
|
|
654
661
|
pendingTasks = 0,
|
|
@@ -657,10 +664,20 @@ function buildRecapText({
|
|
|
657
664
|
usageSummary = normalizeUsageSummary(),
|
|
658
665
|
snippets = [],
|
|
659
666
|
} = {}) {
|
|
660
|
-
const
|
|
661
|
-
|
|
662
|
-
? `${
|
|
663
|
-
|
|
667
|
+
const listenerText =
|
|
668
|
+
liveListeners.length > 0
|
|
669
|
+
? `${liveListeners.length} live listener${liveListeners.length === 1 ? "" : "s"} (${liveListeners
|
|
670
|
+
.slice(0, 3)
|
|
671
|
+
.join(", ")})`
|
|
672
|
+
: listenerCount > 0
|
|
673
|
+
? "no live listeners"
|
|
674
|
+
: "listener status unknown";
|
|
675
|
+
const actorText =
|
|
676
|
+
recentActors.length > 0
|
|
677
|
+
? `${recentActors.length} recent actor${recentActors.length === 1 ? "" : "s"} (${recentActors
|
|
678
|
+
.slice(0, 3)
|
|
679
|
+
.join(", ")})`
|
|
680
|
+
: "no recent peer activity";
|
|
664
681
|
const findingText = `${totalFindings} finding${totalFindings === 1 ? "" : "s"} logged`;
|
|
665
682
|
const lockText = `${activeLocks} file lock${activeLocks === 1 ? "" : "s"} active`;
|
|
666
683
|
const pendingText =
|
|
@@ -669,7 +686,7 @@ function buildRecapText({
|
|
|
669
686
|
const usageText = buildUsageLedgerText(usageSummary);
|
|
670
687
|
const workPlanText = buildWorkPlanText(workPlan);
|
|
671
688
|
const snippetText = snippets.length > 0 ? `Recent: ${snippets.join(" | ")}` : "";
|
|
672
|
-
return `While you were away: ${
|
|
689
|
+
return `While you were away: ${listenerText}; ${actorText}. ${findingText}. ${lockText}. ${pendingText} ${taskText}. ${workPlanText} ${usageText} ${snippetText}`.replace(
|
|
673
690
|
/\s+/g,
|
|
674
691
|
" "
|
|
675
692
|
).trim();
|
|
@@ -840,18 +857,27 @@ function buildAgentJoinBriefingText({ recap = "", forAgent = "" } = {}) {
|
|
|
840
857
|
function buildPeriodicText(recap = {}) {
|
|
841
858
|
const summary = recap.summary && typeof recap.summary === "object" ? recap.summary : {};
|
|
842
859
|
const elapsedMinutes = Number(summary.elapsedMinutes || 0);
|
|
843
|
-
const
|
|
860
|
+
const recentActors = Number(summary.recentActors ?? summary.activeAgents ?? 0);
|
|
861
|
+
const liveListeners = Number(summary.liveListeners ?? summary.liveListenerCount ?? 0);
|
|
862
|
+
const listenerCount = Number(summary.listenerCount || 0);
|
|
844
863
|
const totalFindings = Number(summary.totalFindingsCount || 0);
|
|
845
864
|
const activeLocks = Number(summary.activeLocks || 0);
|
|
846
865
|
const lastActor = normalizeString(summary.lastActorId);
|
|
847
866
|
const actorText = lastActor ? `${lastActor} active` : "no active actor";
|
|
867
|
+
const listenerText =
|
|
868
|
+
liveListeners > 0
|
|
869
|
+
? `${liveListeners} live listener${liveListeners === 1 ? "" : "s"}`
|
|
870
|
+
: listenerCount > 0
|
|
871
|
+
? "no live listeners"
|
|
872
|
+
: "listener status unknown";
|
|
873
|
+
const recentActorText = `${recentActors} recent actor${recentActors === 1 ? "" : "s"}`;
|
|
848
874
|
const taskText = buildTaskLedgerText(summary.taskLedger);
|
|
849
875
|
const workPlanText = buildWorkPlanText(summary.workPlan);
|
|
850
876
|
const usageText = buildUsageLedgerText({
|
|
851
877
|
totals: summary.usageTotals,
|
|
852
878
|
topAgents: summary.usageTopAgents,
|
|
853
879
|
});
|
|
854
|
-
return `Session active for ${elapsedMinutes}m. ${
|
|
880
|
+
return `Session active for ${elapsedMinutes}m. ${listenerText}. ${recentActorText}. ${totalFindings} findings. ${activeLocks} locks. ${taskText}. ${workPlanText} ${usageText} ${actorText}.`.replace(
|
|
855
881
|
/\s+/g,
|
|
856
882
|
" ",
|
|
857
883
|
).trim();
|
|
@@ -899,19 +925,28 @@ export async function buildSessionRecap(
|
|
|
899
925
|
return !normalizedForAgentId || agentId.toLowerCase() !== normalizedForAgentId.toLowerCase();
|
|
900
926
|
});
|
|
901
927
|
|
|
902
|
-
const
|
|
903
|
-
|
|
928
|
+
const listenerRows = summarizeListeners(sortedEvents, {
|
|
929
|
+
nowMs: toEpoch(normalizedNow, normalizedNow),
|
|
930
|
+
});
|
|
931
|
+
const liveListenerRows = listenerRows.filter(
|
|
932
|
+
(row) => row.status === "active" || row.status === "idle",
|
|
933
|
+
);
|
|
934
|
+
const liveListenerIds = liveListenerRows.map((row) => row.agentId).filter(Boolean);
|
|
935
|
+
|
|
936
|
+
const actorEvents = visibleEvents.filter(isMeaningfulRecapSourceEvent);
|
|
937
|
+
const recentActorSet = new Set();
|
|
938
|
+
for (const event of actorEvents) {
|
|
904
939
|
const agentId = normalizeString(event.agent?.id || event.agentId);
|
|
905
940
|
if (agentId && agentId !== SENTI_AGENT_ID) {
|
|
906
|
-
|
|
941
|
+
recentActorSet.add(agentId);
|
|
907
942
|
}
|
|
908
943
|
}
|
|
909
|
-
const
|
|
944
|
+
const recentActors = [...recentActorSet].sort((left, right) => left.localeCompare(right));
|
|
910
945
|
|
|
911
|
-
const findingSummary = buildFindingSummary(
|
|
946
|
+
const findingSummary = buildFindingSummary(actorEvents);
|
|
912
947
|
const totalFindingsCount =
|
|
913
948
|
findingSummary.P0 + findingSummary.P1 + findingSummary.P2 + findingSummary.P3;
|
|
914
|
-
const activeLocks = countActiveLocks(
|
|
949
|
+
const activeLocks = countActiveLocks(actorEvents);
|
|
915
950
|
const pendingTasks = await readPendingTasks(normalizedSessionId, {
|
|
916
951
|
forAgentId: normalizedForAgentId,
|
|
917
952
|
targetPath: normalizedTargetPath,
|
|
@@ -922,17 +957,19 @@ export async function buildSessionRecap(
|
|
|
922
957
|
const workPlan = await readWorkPlanSummary({
|
|
923
958
|
targetPath: normalizedTargetPath,
|
|
924
959
|
});
|
|
925
|
-
const snippets = summarizeRecentActivity(
|
|
960
|
+
const snippets = summarizeRecentActivity(actorEvents, {
|
|
926
961
|
forAgentId: normalizedForAgentId,
|
|
927
962
|
limit: 2,
|
|
928
963
|
});
|
|
929
|
-
const windowElapsedMinutes = buildElapsedMinutes(
|
|
930
|
-
const elapsedMinutes = buildElapsedMinutes(
|
|
964
|
+
const windowElapsedMinutes = buildElapsedMinutes(actorEvents, normalizedNow);
|
|
965
|
+
const elapsedMinutes = buildElapsedMinutes(actorEvents, normalizedNow, {
|
|
931
966
|
startedAt: sessionMetadata?.createdAt,
|
|
932
967
|
});
|
|
933
|
-
const latestEvent =
|
|
968
|
+
const latestEvent = actorEvents.length > 0 ? actorEvents[actorEvents.length - 1] : null;
|
|
934
969
|
const recapText = buildRecapText({
|
|
935
|
-
|
|
970
|
+
recentActors,
|
|
971
|
+
liveListeners: liveListenerIds,
|
|
972
|
+
listenerCount: listenerRows.length,
|
|
936
973
|
totalFindings: totalFindingsCount,
|
|
937
974
|
activeLocks,
|
|
938
975
|
pendingTasks,
|
|
@@ -951,8 +988,17 @@ export async function buildSessionRecap(
|
|
|
951
988
|
text: recapText,
|
|
952
989
|
recap: recapText,
|
|
953
990
|
summary: {
|
|
954
|
-
|
|
955
|
-
|
|
991
|
+
// Back-compat: historical consumers read activeAgents, but this count is
|
|
992
|
+
// recent transcript actors, not live listener presence.
|
|
993
|
+
activeAgents: recentActors.length,
|
|
994
|
+
activeAgentIds: recentActors,
|
|
995
|
+
recentActors: recentActors.length,
|
|
996
|
+
recentActorIds: recentActors,
|
|
997
|
+
liveListeners: liveListenerIds.length,
|
|
998
|
+
liveListenerIds,
|
|
999
|
+
liveListenerCount: liveListenerIds.length,
|
|
1000
|
+
listenerCount: listenerRows.length,
|
|
1001
|
+
listenerStatus: listenerRows,
|
|
956
1002
|
totalFindings: findingSummary,
|
|
957
1003
|
totalFindingsCount,
|
|
958
1004
|
activeLocks,
|