sentinelayer-cli 0.17.0 → 0.17.1
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 +16 -6
- package/package.json +3 -2
- package/src/commands/legacy-args.js +1 -0
- package/src/commands/omargate.js +1 -0
- package/src/commands/session.js +302 -25
- package/src/events/schema.js +21 -0
- package/src/legacy-cli.js +16 -0
- package/src/review/investor-dd-devtestbot.js +83 -8
- package/src/review/investor-dd-file-loop.js +83 -6
- package/src/review/investor-dd-orchestrator.js +42 -1
- package/src/review/investor-dd-progress.js +351 -0
- package/src/review/investor-dd-usage.js +227 -0
- package/src/session/daemon.js +341 -2
- package/src/session/recap.js +288 -69
- package/src/session/sync.js +1 -4
package/src/session/recap.js
CHANGED
|
@@ -17,6 +17,19 @@ const DEFAULT_RECAP_INTERVAL_MS = 300_000;
|
|
|
17
17
|
const DEFAULT_RECAP_INACTIVITY_MS = 600_000;
|
|
18
18
|
const DEFAULT_RECAP_ACTIVITY_THRESHOLD = 5;
|
|
19
19
|
const DEFAULT_TASK_SUMMARY_LIMIT = 3;
|
|
20
|
+
const RECAP_SOURCE_IGNORED_EVENTS = new Set([
|
|
21
|
+
"agent_heartbeat",
|
|
22
|
+
"agent_join",
|
|
23
|
+
"agent_status",
|
|
24
|
+
"context_briefing",
|
|
25
|
+
"daemon_alert",
|
|
26
|
+
"session_ack",
|
|
27
|
+
"session_checkpoint",
|
|
28
|
+
"session_reaction",
|
|
29
|
+
"session_recap",
|
|
30
|
+
"session_usage",
|
|
31
|
+
"session_view",
|
|
32
|
+
]);
|
|
20
33
|
const ACTIVE_TASK_STATUSES = new Set(["PENDING", "ACCEPTED", "BLOCKED"]);
|
|
21
34
|
const TASK_STATUS_KEYS = {
|
|
22
35
|
PENDING: "pending",
|
|
@@ -64,6 +77,184 @@ function isRecapEvent(event = {}) {
|
|
|
64
77
|
return payload.ephemeral === true && normalizeString(payload.style) === RECAP_STYLE;
|
|
65
78
|
}
|
|
66
79
|
|
|
80
|
+
function eventSequenceId(event = {}) {
|
|
81
|
+
const parsed = Number(event.sequenceId ?? event.sequence_id);
|
|
82
|
+
if (!Number.isFinite(parsed) || parsed <= 0) {
|
|
83
|
+
return null;
|
|
84
|
+
}
|
|
85
|
+
return Math.floor(parsed);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function eventCursor(event = {}) {
|
|
89
|
+
return normalizeString(event.cursor || event.eventId || event.idempotencyToken || event.ts);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function isMeaningfulRecapSourceEvent(event = {}) {
|
|
93
|
+
if (isRecapEvent(event)) {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
const eventName = normalizeString(event.event).toLowerCase();
|
|
97
|
+
if (!eventName || RECAP_SOURCE_IGNORED_EVENTS.has(eventName)) {
|
|
98
|
+
return false;
|
|
99
|
+
}
|
|
100
|
+
return true;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function isEventAfterRecapAnchor(event = {}, state = {}) {
|
|
104
|
+
const anchorSequence = Number(state.lastSourceSequenceId);
|
|
105
|
+
const sequence = eventSequenceId(event);
|
|
106
|
+
if (Number.isFinite(anchorSequence) && anchorSequence > 0 && sequence !== null) {
|
|
107
|
+
return sequence > anchorSequence;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const anchorAt = normalizeString(state.lastSourceEventAt);
|
|
111
|
+
if (!anchorAt) {
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
const anchorEpoch = toEpoch(anchorAt, anchorAt);
|
|
115
|
+
const eventEpoch = toEpoch(event.ts, anchorAt);
|
|
116
|
+
if (eventEpoch > anchorEpoch) {
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
if (eventEpoch < anchorEpoch) {
|
|
120
|
+
return false;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
const anchorCursor = normalizeString(state.lastSourceCursor);
|
|
124
|
+
if (!anchorCursor) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
return eventCursor(event) !== anchorCursor;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function rememberRecapSource(state, event = {}, nowIso = new Date().toISOString()) {
|
|
131
|
+
state.lastSourceEventAt = normalizeIsoTimestamp(event.ts, nowIso);
|
|
132
|
+
state.lastSourceSequenceId = eventSequenceId(event);
|
|
133
|
+
state.lastSourceCursor = eventCursor(event);
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function resolvePeriodicRecapTrigger(state, events = [], nowIso = new Date().toISOString()) {
|
|
137
|
+
const sortedEvents = sortEventsByConversationTime(events, nowIso);
|
|
138
|
+
const sourceEvents = sortedEvents.filter(isMeaningfulRecapSourceEvent);
|
|
139
|
+
const unrecappedSourceEvents = sourceEvents.filter((event) => isEventAfterRecapAnchor(event, state));
|
|
140
|
+
const latestSourceEvent = sourceEvents.length > 0 ? sourceEvents[sourceEvents.length - 1] : null;
|
|
141
|
+
const latestUnrecappedSourceEvent =
|
|
142
|
+
unrecappedSourceEvents.length > 0
|
|
143
|
+
? unrecappedSourceEvents[unrecappedSourceEvents.length - 1]
|
|
144
|
+
: null;
|
|
145
|
+
const nowEpoch = toEpoch(nowIso, nowIso);
|
|
146
|
+
const latestSourceEventAt = latestSourceEvent
|
|
147
|
+
? normalizeIsoTimestamp(latestSourceEvent.ts, nowIso)
|
|
148
|
+
: null;
|
|
149
|
+
const latestUnrecappedSourceEventAt = latestUnrecappedSourceEvent
|
|
150
|
+
? normalizeIsoTimestamp(latestUnrecappedSourceEvent.ts, nowIso)
|
|
151
|
+
: null;
|
|
152
|
+
const sourceIdleMs = latestSourceEvent
|
|
153
|
+
? Math.max(0, nowEpoch - toEpoch(latestSourceEvent.ts, nowIso))
|
|
154
|
+
: null;
|
|
155
|
+
const unrecappedSourceIdleMs = latestUnrecappedSourceEvent
|
|
156
|
+
? Math.max(0, nowEpoch - toEpoch(latestUnrecappedSourceEvent.ts, nowIso))
|
|
157
|
+
: null;
|
|
158
|
+
const sinceLastRecapMs = state.lastRecapAt
|
|
159
|
+
? Math.max(0, nowEpoch - toEpoch(state.lastRecapAt, nowIso))
|
|
160
|
+
: null;
|
|
161
|
+
const policy = {
|
|
162
|
+
intervalMs: state.intervalMs,
|
|
163
|
+
inactivityMs: state.inactivityMs,
|
|
164
|
+
activityThreshold: state.newEventThreshold,
|
|
165
|
+
sourceEventCount: unrecappedSourceEvents.length,
|
|
166
|
+
totalSourceEventCount: sourceEvents.length,
|
|
167
|
+
latestSourceEventAt,
|
|
168
|
+
latestUnrecappedSourceEventAt,
|
|
169
|
+
sourceIdleMs,
|
|
170
|
+
unrecappedSourceIdleMs,
|
|
171
|
+
lastRecapAt: state.lastRecapAt,
|
|
172
|
+
lastSourceEventAt: state.lastSourceEventAt,
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
if (!latestSourceEvent) {
|
|
176
|
+
return {
|
|
177
|
+
shouldEmit: false,
|
|
178
|
+
shouldStop: false,
|
|
179
|
+
stopAfterEmit: false,
|
|
180
|
+
mode: "",
|
|
181
|
+
reason: "recap_no_source_events",
|
|
182
|
+
sourceEvent: null,
|
|
183
|
+
policy,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (!latestUnrecappedSourceEvent) {
|
|
188
|
+
return {
|
|
189
|
+
shouldEmit: false,
|
|
190
|
+
shouldStop: sourceIdleMs !== null && sourceIdleMs >= state.inactivityMs,
|
|
191
|
+
stopAfterEmit: false,
|
|
192
|
+
mode: "",
|
|
193
|
+
reason: "recap_no_new_source_events",
|
|
194
|
+
sourceEvent: null,
|
|
195
|
+
policy,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
if (unrecappedSourceIdleMs !== null && unrecappedSourceIdleMs >= state.inactivityMs) {
|
|
200
|
+
return {
|
|
201
|
+
shouldEmit: true,
|
|
202
|
+
shouldStop: false,
|
|
203
|
+
stopAfterEmit: true,
|
|
204
|
+
mode: "inactivity",
|
|
205
|
+
reason: "",
|
|
206
|
+
sourceEvent: latestUnrecappedSourceEvent,
|
|
207
|
+
policy,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (!state.lastRecapAt) {
|
|
212
|
+
return {
|
|
213
|
+
shouldEmit: true,
|
|
214
|
+
shouldStop: false,
|
|
215
|
+
stopAfterEmit: false,
|
|
216
|
+
mode: "initial",
|
|
217
|
+
reason: "",
|
|
218
|
+
sourceEvent: latestUnrecappedSourceEvent,
|
|
219
|
+
policy,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (unrecappedSourceEvents.length >= state.newEventThreshold) {
|
|
224
|
+
return {
|
|
225
|
+
shouldEmit: true,
|
|
226
|
+
shouldStop: false,
|
|
227
|
+
stopAfterEmit: false,
|
|
228
|
+
mode: "activity_threshold",
|
|
229
|
+
reason: "",
|
|
230
|
+
sourceEvent: latestUnrecappedSourceEvent,
|
|
231
|
+
policy,
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (sinceLastRecapMs !== null && sinceLastRecapMs >= state.intervalMs) {
|
|
236
|
+
return {
|
|
237
|
+
shouldEmit: true,
|
|
238
|
+
shouldStop: false,
|
|
239
|
+
stopAfterEmit: false,
|
|
240
|
+
mode: "periodic",
|
|
241
|
+
reason: "",
|
|
242
|
+
sourceEvent: latestUnrecappedSourceEvent,
|
|
243
|
+
policy,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return {
|
|
248
|
+
shouldEmit: false,
|
|
249
|
+
shouldStop: false,
|
|
250
|
+
stopAfterEmit: false,
|
|
251
|
+
mode: "",
|
|
252
|
+
reason: "recap_cadence_wait",
|
|
253
|
+
sourceEvent: latestUnrecappedSourceEvent,
|
|
254
|
+
policy,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
|
|
67
258
|
function parseFindingSeverity(text = "") {
|
|
68
259
|
const normalized = normalizeString(text);
|
|
69
260
|
if (!normalized) {
|
|
@@ -704,8 +895,8 @@ export async function shouldEmitRecap(
|
|
|
704
895
|
tail: 0,
|
|
705
896
|
since: normalizeString(lastReadAt) || null,
|
|
706
897
|
});
|
|
707
|
-
const
|
|
708
|
-
if (
|
|
898
|
+
const isRelevantSourceEvent = (event = {}) => {
|
|
899
|
+
if (!isMeaningfulRecapSourceEvent(event)) {
|
|
709
900
|
return false;
|
|
710
901
|
}
|
|
711
902
|
const sourceAgent = normalizeString(event.agent?.id || event.agentId).toLowerCase();
|
|
@@ -713,20 +904,23 @@ export async function shouldEmitRecap(
|
|
|
713
904
|
return true;
|
|
714
905
|
}
|
|
715
906
|
return sourceAgent !== normalizedAgentId;
|
|
716
|
-
}
|
|
717
|
-
|
|
907
|
+
};
|
|
908
|
+
const relevantSinceRead = eventsSinceRead.filter(isRelevantSourceEvent);
|
|
909
|
+
if (relevantSinceRead.length >= threshold) {
|
|
718
910
|
return true;
|
|
719
911
|
}
|
|
720
912
|
|
|
721
913
|
const latest = await readStream(normalizedSessionId, {
|
|
722
914
|
targetPath,
|
|
723
|
-
tail:
|
|
915
|
+
tail: 200,
|
|
724
916
|
});
|
|
725
|
-
const
|
|
726
|
-
|
|
917
|
+
const latestRelevant = sortEventsByConversationTime(latest, normalizedNow)
|
|
918
|
+
.filter(isRelevantSourceEvent)
|
|
919
|
+
.at(-1);
|
|
920
|
+
if (!latestRelevant) {
|
|
727
921
|
return false;
|
|
728
922
|
}
|
|
729
|
-
const idleMs = Math.max(0, toEpoch(normalizedNow, normalizedNow) - toEpoch(
|
|
923
|
+
const idleMs = Math.max(0, toEpoch(normalizedNow, normalizedNow) - toEpoch(latestRelevant.ts, normalizedNow));
|
|
730
924
|
return idleMs >= normalizedInactivityMs;
|
|
731
925
|
}
|
|
732
926
|
|
|
@@ -735,6 +929,7 @@ export function emitPeriodicRecap(
|
|
|
735
929
|
{
|
|
736
930
|
intervalMs = DEFAULT_RECAP_INTERVAL_MS,
|
|
737
931
|
inactivityMs = DEFAULT_RECAP_INACTIVITY_MS,
|
|
932
|
+
newEventThreshold = DEFAULT_RECAP_ACTIVITY_THRESHOLD,
|
|
738
933
|
maxEvents = DEFAULT_RECAP_MAX_EVENTS,
|
|
739
934
|
targetPath = process.cwd(),
|
|
740
935
|
nowProvider = () => new Date().toISOString(),
|
|
@@ -751,6 +946,10 @@ export function emitPeriodicRecap(
|
|
|
751
946
|
inactivityMs,
|
|
752
947
|
DEFAULT_RECAP_INACTIVITY_MS
|
|
753
948
|
);
|
|
949
|
+
const normalizedNewEventThreshold = normalizePositiveInteger(
|
|
950
|
+
newEventThreshold,
|
|
951
|
+
DEFAULT_RECAP_ACTIVITY_THRESHOLD
|
|
952
|
+
);
|
|
754
953
|
const normalizedMaxEvents = normalizePositiveInteger(maxEvents, DEFAULT_RECAP_MAX_EVENTS);
|
|
755
954
|
const key = buildRecapKey(normalizedSessionId, normalizedTargetPath);
|
|
756
955
|
const existing = ACTIVE_RECAP_EMITTERS.get(key);
|
|
@@ -764,13 +963,18 @@ export function emitPeriodicRecap(
|
|
|
764
963
|
startedAt: normalizeIsoTimestamp(nowProvider(), new Date().toISOString()),
|
|
765
964
|
intervalMs: normalizedIntervalMs,
|
|
766
965
|
inactivityMs: normalizedInactivityMs,
|
|
966
|
+
newEventThreshold: normalizedNewEventThreshold,
|
|
767
967
|
maxEvents: normalizedMaxEvents,
|
|
768
968
|
targetPath: normalizedTargetPath,
|
|
769
969
|
sessionId: normalizedSessionId,
|
|
770
970
|
timer: null,
|
|
971
|
+
inFlight: false,
|
|
771
972
|
lastRecapAt: null,
|
|
772
973
|
lastSourceEventAt: null,
|
|
974
|
+
lastSourceSequenceId: null,
|
|
975
|
+
lastSourceCursor: null,
|
|
773
976
|
lastRecapEvent: null,
|
|
977
|
+
lastDecision: null,
|
|
774
978
|
stoppedReason: null,
|
|
775
979
|
};
|
|
776
980
|
|
|
@@ -794,77 +998,87 @@ export function emitPeriodicRecap(
|
|
|
794
998
|
sessionId: state.sessionId,
|
|
795
999
|
reason: state.stoppedReason,
|
|
796
1000
|
lastRecapAt: state.lastRecapAt,
|
|
1001
|
+
lastDecision: state.lastDecision,
|
|
797
1002
|
};
|
|
798
1003
|
};
|
|
799
1004
|
|
|
800
|
-
const tickNow = async () => {
|
|
801
|
-
if (!state.running) {
|
|
802
|
-
return null;
|
|
803
|
-
}
|
|
804
|
-
const nowIso = normalizeIsoTimestamp(nowProvider(), new Date().toISOString());
|
|
805
|
-
const nowEpoch = toEpoch(nowIso, nowIso);
|
|
806
|
-
const events = await readStream(state.sessionId, {
|
|
807
|
-
targetPath: state.targetPath,
|
|
808
|
-
tail: state.maxEvents,
|
|
809
|
-
});
|
|
810
|
-
const nonRecapEvents = events.filter((event) => !isRecapEvent(event));
|
|
811
|
-
const latestSourceEvent = nonRecapEvents.length > 0 ? nonRecapEvents[nonRecapEvents.length - 1] : null;
|
|
812
|
-
if (!latestSourceEvent) {
|
|
813
|
-
return null;
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
const latestSourceEpoch = toEpoch(latestSourceEvent.ts, nowIso);
|
|
817
|
-
const idleMs = Math.max(0, nowEpoch - latestSourceEpoch);
|
|
818
|
-
if (idleMs >= state.inactivityMs) {
|
|
819
|
-
stop("inactive");
|
|
1005
|
+
const tickNow = async (overrideNowIso = "") => {
|
|
1006
|
+
if (!state.running || state.inFlight) {
|
|
820
1007
|
return null;
|
|
821
1008
|
}
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
const
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
1009
|
+
state.inFlight = true;
|
|
1010
|
+
try {
|
|
1011
|
+
const nowIso = normalizeIsoTimestamp(
|
|
1012
|
+
overrideNowIso || nowProvider(),
|
|
1013
|
+
new Date().toISOString()
|
|
1014
|
+
);
|
|
1015
|
+
const events = await readStream(state.sessionId, {
|
|
1016
|
+
targetPath: state.targetPath,
|
|
1017
|
+
tail: state.maxEvents,
|
|
1018
|
+
});
|
|
1019
|
+
const trigger = resolvePeriodicRecapTrigger(state, events, nowIso);
|
|
1020
|
+
state.lastDecision = {
|
|
1021
|
+
emitted: false,
|
|
1022
|
+
mode: trigger.mode,
|
|
1023
|
+
reason: trigger.reason,
|
|
1024
|
+
policy: trigger.policy,
|
|
1025
|
+
};
|
|
1026
|
+
if (!trigger.shouldEmit) {
|
|
1027
|
+
if (trigger.shouldStop) {
|
|
1028
|
+
stop("inactive");
|
|
1029
|
+
}
|
|
832
1030
|
return null;
|
|
833
1031
|
}
|
|
834
|
-
}
|
|
835
1032
|
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
1033
|
+
const recap = await buildSessionRecap(state.sessionId, {
|
|
1034
|
+
targetPath: state.targetPath,
|
|
1035
|
+
maxEvents: state.maxEvents,
|
|
1036
|
+
nowIso,
|
|
1037
|
+
});
|
|
1038
|
+
const text = buildPeriodicText(recap);
|
|
1039
|
+
const event = createAgentEvent({
|
|
1040
|
+
event: "session_recap",
|
|
1041
|
+
agentId: SENTI_AGENT_ID,
|
|
1042
|
+
agentModel: SENTI_MODEL,
|
|
1043
|
+
sessionId: state.sessionId,
|
|
1044
|
+
ts: nowIso,
|
|
1045
|
+
payload: {
|
|
1046
|
+
mode: trigger.mode,
|
|
1047
|
+
recap: text,
|
|
1048
|
+
ephemeral: true,
|
|
1049
|
+
style: RECAP_STYLE,
|
|
1050
|
+
generatedAt: nowIso,
|
|
1051
|
+
sourceEventCount: trigger.policy.sourceEventCount,
|
|
1052
|
+
latestSourceEventAt: trigger.policy.latestUnrecappedSourceEventAt,
|
|
1053
|
+
policy: trigger.policy,
|
|
1054
|
+
summary: recap.summary,
|
|
1055
|
+
},
|
|
1056
|
+
});
|
|
1057
|
+
const persisted = await appendToStream(state.sessionId, event, {
|
|
1058
|
+
targetPath: state.targetPath,
|
|
1059
|
+
});
|
|
1060
|
+
state.lastRecapAt = nowIso;
|
|
1061
|
+
rememberRecapSource(state, trigger.sourceEvent, nowIso);
|
|
1062
|
+
state.lastRecapEvent = persisted;
|
|
1063
|
+
state.lastDecision = {
|
|
1064
|
+
emitted: true,
|
|
1065
|
+
mode: trigger.mode,
|
|
1066
|
+
reason: "",
|
|
1067
|
+
eventId: persisted.eventId || null,
|
|
1068
|
+
sourceEventCount: trigger.policy.sourceEventCount,
|
|
1069
|
+
policy: trigger.policy,
|
|
1070
|
+
};
|
|
863
1071
|
|
|
864
|
-
|
|
865
|
-
|
|
1072
|
+
if (typeof onEmit === "function") {
|
|
1073
|
+
await onEmit(persisted, recap);
|
|
1074
|
+
}
|
|
1075
|
+
if (trigger.stopAfterEmit) {
|
|
1076
|
+
stop("inactive");
|
|
1077
|
+
}
|
|
1078
|
+
return persisted;
|
|
1079
|
+
} finally {
|
|
1080
|
+
state.inFlight = false;
|
|
866
1081
|
}
|
|
867
|
-
return persisted;
|
|
868
1082
|
};
|
|
869
1083
|
|
|
870
1084
|
const handle = {
|
|
@@ -880,8 +1094,12 @@ export function emitPeriodicRecap(
|
|
|
880
1094
|
running: state.running,
|
|
881
1095
|
intervalMs: state.intervalMs,
|
|
882
1096
|
inactivityMs: state.inactivityMs,
|
|
1097
|
+
newEventThreshold: state.newEventThreshold,
|
|
1098
|
+
inFlight: state.inFlight,
|
|
883
1099
|
lastRecapAt: state.lastRecapAt,
|
|
884
1100
|
lastSourceEventAt: state.lastSourceEventAt,
|
|
1101
|
+
lastSourceSequenceId: state.lastSourceSequenceId,
|
|
1102
|
+
lastDecision: state.lastDecision,
|
|
885
1103
|
stoppedReason: state.stoppedReason,
|
|
886
1104
|
}),
|
|
887
1105
|
};
|
|
@@ -906,6 +1124,7 @@ export function getPeriodicRecapEmitter(sessionId, { targetPath = process.cwd()
|
|
|
906
1124
|
|
|
907
1125
|
export {
|
|
908
1126
|
ACTIVE_RECAP_EMITTERS,
|
|
1127
|
+
DEFAULT_RECAP_ACTIVITY_THRESHOLD,
|
|
909
1128
|
DEFAULT_RECAP_INACTIVITY_MS,
|
|
910
1129
|
DEFAULT_RECAP_INTERVAL_MS,
|
|
911
1130
|
DEFAULT_RECAP_MAX_EVENTS,
|
package/src/session/sync.js
CHANGED
|
@@ -1901,10 +1901,7 @@ export async function probeSessionAccess(
|
|
|
1901
1901
|
}
|
|
1902
1902
|
|
|
1903
1903
|
export function resetSessionSyncStateForTests() {
|
|
1904
|
-
|
|
1905
|
-
outboundCircuit.openedAtMs = 0;
|
|
1906
|
-
inboundCircuit.consecutiveFailures = 0;
|
|
1907
|
-
inboundCircuit.openedAtMs = 0;
|
|
1904
|
+
__resetCircuitStateForTests();
|
|
1908
1905
|
sessionIngestWindowBySessionId.clear();
|
|
1909
1906
|
humanRelayWindowBySessionId.clear();
|
|
1910
1907
|
autoGrantAttemptedAgentIds.clear();
|