sentinelayer-cli 0.34.0 → 0.34.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/package.json +1 -1
- package/src/commands/session.js +18 -0
- package/src/session/remote-hydrate.js +32 -1
package/package.json
CHANGED
package/src/commands/session.js
CHANGED
|
@@ -755,6 +755,14 @@ function formatHumanAskLine(event = {}) {
|
|
|
755
755
|
return `${sequenceLabel} ${humanAskAgentId(event)}${ts ? ` ${ts}` : ""}${suffix}`;
|
|
756
756
|
}
|
|
757
757
|
|
|
758
|
+
function formatRemoteHydrateAppendWarning(result = {}) {
|
|
759
|
+
const count = Number(result?.appendFailureCount || 0);
|
|
760
|
+
if (!Number.isFinite(count) || count <= 0) return "";
|
|
761
|
+
const reason = normalizeString(result.appendFailureReason) || "local_append_failed";
|
|
762
|
+
const noun = count === 1 ? "event" : "events";
|
|
763
|
+
return `Remote hydrate could not persist ${count} ${noun} locally (${reason}); affected cursors were not advanced.`;
|
|
764
|
+
}
|
|
765
|
+
|
|
758
766
|
function eventTimestampMs(event = {}) {
|
|
759
767
|
for (const key of ["ts", "timestamp", "createdAt", "at"]) {
|
|
760
768
|
const epoch = Date.parse(normalizeString(event?.[key]));
|
|
@@ -5481,6 +5489,10 @@ export function registerSessionCommand(program) {
|
|
|
5481
5489
|
),
|
|
5482
5490
|
);
|
|
5483
5491
|
}
|
|
5492
|
+
const appendWarning = formatRemoteHydrateAppendWarning(hydration);
|
|
5493
|
+
if (appendWarning) {
|
|
5494
|
+
console.log(pc.yellow(appendWarning));
|
|
5495
|
+
}
|
|
5484
5496
|
} else {
|
|
5485
5497
|
console.log(
|
|
5486
5498
|
pc.yellow(
|
|
@@ -5847,6 +5859,8 @@ export function registerSessionCommand(program) {
|
|
|
5847
5859
|
eventsCursor: result.eventsCursor,
|
|
5848
5860
|
materializedLocalSession: result.materializedLocalSession,
|
|
5849
5861
|
localAppendComplete: result.localAppendComplete,
|
|
5862
|
+
appendFailureCount: result.appendFailureCount,
|
|
5863
|
+
appendFailureReason: result.appendFailureReason,
|
|
5850
5864
|
access: access || undefined,
|
|
5851
5865
|
};
|
|
5852
5866
|
if (shouldEmitJson(options, command)) {
|
|
@@ -5857,6 +5871,10 @@ export function registerSessionCommand(program) {
|
|
|
5857
5871
|
console.log(
|
|
5858
5872
|
`Hydrated session ${normalizedSessionId}: relayed=${result.relayed} dropped=${result.dropped}.`,
|
|
5859
5873
|
);
|
|
5874
|
+
const appendWarning = formatRemoteHydrateAppendWarning(result);
|
|
5875
|
+
if (appendWarning) {
|
|
5876
|
+
console.log(pc.yellow(appendWarning));
|
|
5877
|
+
}
|
|
5860
5878
|
if (access && !access.accessible) {
|
|
5861
5879
|
if (access.reason === "session_not_found") {
|
|
5862
5880
|
console.log(
|
|
@@ -38,6 +38,7 @@ import { isSessionControlEvent } from "./control-events.js";
|
|
|
38
38
|
const EVENTS_CURSOR_SUFFIX = "events";
|
|
39
39
|
const DEFAULT_EVENT_PAGE_LIMIT = 200;
|
|
40
40
|
const DEFAULT_MAX_EVENT_PAGES = 25;
|
|
41
|
+
const MAX_APPEND_FAILURE_REASON_LENGTH = 160;
|
|
41
42
|
|
|
42
43
|
function indexRelayEventIdentityKeys(indexByKey, eventList = [], event = {}, index = -1) {
|
|
43
44
|
if (!indexByKey || !Array.isArray(eventList) || index < 0) return;
|
|
@@ -163,6 +164,28 @@ function normalizePositiveInteger(value, fallbackValue) {
|
|
|
163
164
|
return Math.floor(normalized);
|
|
164
165
|
}
|
|
165
166
|
|
|
167
|
+
function localAppendFailureReason(error) {
|
|
168
|
+
const message = error?.message || String(error || "");
|
|
169
|
+
let reason = String(message).trim();
|
|
170
|
+
if (!reason) return "local_append_failed";
|
|
171
|
+
reason = reason.replace(
|
|
172
|
+
/(["'])(?:[A-Za-z]:\\|\/(?:Users|home|tmp|var|private|mnt|workspace)\/).*?\1/g,
|
|
173
|
+
"$1[path]$1",
|
|
174
|
+
);
|
|
175
|
+
reason = reason.replace(/[A-Za-z]:\\[^,;\r\n)]+/g, "[path]");
|
|
176
|
+
reason = reason.replace(/(^|[\s"'(])\/(?:Users|home|tmp|var|private|mnt|workspace)\/[^\s,;)"']+/g, "$1[path]");
|
|
177
|
+
reason = reason.replace(/\bBearer\s+[A-Za-z0-9._~+/=-]+/gi, "Bearer [REDACTED]");
|
|
178
|
+
reason = reason.replace(
|
|
179
|
+
/\b([A-Za-z0-9_-]*(?:api[_-]?key|authorization|password|secret|token)[A-Za-z0-9_-]*)\s*[:=]\s*(?:"[^"]+"|'[^']+'|[^\s,;]+)/gi,
|
|
180
|
+
"$1=[REDACTED]",
|
|
181
|
+
);
|
|
182
|
+
reason = reason.replace(/\b[A-Za-z0-9._~+/=-]{32,}\b/g, "[REDACTED]");
|
|
183
|
+
if (reason.length > MAX_APPEND_FAILURE_REASON_LENGTH) {
|
|
184
|
+
reason = `${reason.slice(0, MAX_APPEND_FAILURE_REASON_LENGTH - 3)}...`;
|
|
185
|
+
}
|
|
186
|
+
return reason || "local_append_failed";
|
|
187
|
+
}
|
|
188
|
+
|
|
166
189
|
async function pollSessionEventPages({
|
|
167
190
|
sessionId,
|
|
168
191
|
targetPath,
|
|
@@ -436,6 +459,8 @@ export async function hydrateSessionFromRemote({
|
|
|
436
459
|
mergeExisting: eventsNeedingMerge.has(event),
|
|
437
460
|
}));
|
|
438
461
|
const failedRelayKeys = new Set();
|
|
462
|
+
let appendFailureCount = 0;
|
|
463
|
+
let appendFailureReason = "";
|
|
439
464
|
for (const { event, mergeExisting } of appendEvents) {
|
|
440
465
|
try {
|
|
441
466
|
const persisted = await _append(sessionId, event, {
|
|
@@ -453,7 +478,11 @@ export async function hydrateSessionFromRemote({
|
|
|
453
478
|
persistedEvent,
|
|
454
479
|
existingRelayEvents.length - 1,
|
|
455
480
|
);
|
|
456
|
-
} catch {
|
|
481
|
+
} catch (error) {
|
|
482
|
+
appendFailureCount += 1;
|
|
483
|
+
if (!appendFailureReason) {
|
|
484
|
+
appendFailureReason = localAppendFailureReason(error);
|
|
485
|
+
}
|
|
457
486
|
addSessionEventIdentityKeys(failedRelayKeys, event);
|
|
458
487
|
// Append errors are observable via the stream but should not
|
|
459
488
|
// abort the rest of the batch — partial relay is still progress.
|
|
@@ -492,6 +521,8 @@ export async function hydrateSessionFromRemote({
|
|
|
492
521
|
eventsBackfillReason: eventsResult?.complete === false ? eventsResult?.reason || "" : "",
|
|
493
522
|
materializedLocalSession,
|
|
494
523
|
localAppendComplete: humanCursorSafe && eventsCursorSafe,
|
|
524
|
+
appendFailureCount,
|
|
525
|
+
appendFailureReason,
|
|
495
526
|
remoteStatus: remoteStatus || null,
|
|
496
527
|
};
|
|
497
528
|
}
|