@quantiya/codevibe-core 2.0.79 → 2.0.80
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/dist/appsync/appsync-client.d.ts +4 -0
- package/dist/appsync/index.d.ts +2 -0
- package/dist/appsync/sync-mobile-echo.d.ts +9 -0
- package/dist/appsync/sync-source-cursor.d.ts +14 -0
- package/dist/appsync/sync-source-file.d.ts +15 -0
- package/dist/appsync/sync-source-pair.d.ts +2 -1
- package/dist/appsync/sync-source-recovery.d.ts +35 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +517 -517
- package/dist/orchestration-shell/cli.js +150 -11
- package/dist/tool-activity/replay-cursor.d.ts +11 -1
- package/package.json +1 -1
|
@@ -8927,7 +8927,15 @@ var import_zod = require("zod"), MAX_SYNC_SOURCE_ANCHOR_BYTES = 64 * 1024, count
|
|
|
8927
8927
|
anchor,
|
|
8928
8928
|
reason: import_zod.z.enum(["BACKLOG_LIMIT", "OVERSIZED_RECORD", "PARTIAL_RECORD", "MALFORMED_RECORD", "EMPTY_RECORD"]),
|
|
8929
8929
|
discardUntilNewline: import_zod.z.boolean()
|
|
8930
|
-
}).strict().refine((value) => value.endOffset > value.startOffset && value.anchor.endOffset === value.endOffset && value.anchor.startOffset >= value.startOffset && (!value.discardUntilNewline || ["BACKLOG_LIMIT", "OVERSIZED_RECORD", "PARTIAL_RECORD"].includes(value.reason))), position = import_zod.z.object({ byteOffset: count2, anchor: anchor.nullable(), discardUntilNewline: import_zod.z.boolean() }).strict().refine((value) => value.byteOffset === 0 ? value.anchor === null && !value.discardUntilNewline : value.anchor?.endOffset === value.byteOffset)
|
|
8930
|
+
}).strict().refine((value) => value.endOffset > value.startOffset && value.anchor.endOffset === value.endOffset && value.anchor.startOffset >= value.startOffset && (!value.discardUntilNewline || ["BACKLOG_LIMIT", "OVERSIZED_RECORD", "PARTIAL_RECORD"].includes(value.reason))), position = import_zod.z.object({ byteOffset: count2, anchor: anchor.nullable(), discardUntilNewline: import_zod.z.boolean() }).strict().refine((value) => value.byteOffset === 0 ? value.anchor === null && !value.discardUntilNewline : value.anchor?.endOffset === value.byteOffset);
|
|
8931
|
+
function validSourceRebase(previous, target2, skipped) {
|
|
8932
|
+
return position.safeParse({
|
|
8933
|
+
byteOffset: previous.byteOffset,
|
|
8934
|
+
anchor: previous.anchor,
|
|
8935
|
+
discardUntilNewline: previous.discardUntilNewline
|
|
8936
|
+
}).success && previous.byteOffset > 0 && anchor.safeParse(target2).success && typeof skipped == "boolean";
|
|
8937
|
+
}
|
|
8938
|
+
var frameAnchor = (value) => value.anchor ?? {
|
|
8931
8939
|
startOffset: value.startOffset,
|
|
8932
8940
|
endOffset: value.endOffset,
|
|
8933
8941
|
sha256: value.sourceSha256
|
|
@@ -9039,6 +9047,26 @@ function createSourceJournal(options) {
|
|
|
9039
9047
|
row3.byteOffset = next.endOffset, row3.anchor = next.anchor, row3.discardUntilNewline = next.discardUntilNewline, row3.skippedBytes += next.endOffset - next.startOffset, row3.lastGap = next, row3.lastFrame = null, row3.projection = null, await write(row3, assertOwnership);
|
|
9040
9048
|
});
|
|
9041
9049
|
},
|
|
9050
|
+
rebase: async (previous, target2, skippedHistory, recordedAt, recoveryProjection = null) => {
|
|
9051
|
+
if (!validSourceRebase(previous, target2, skippedHistory) || !Number.isSafeInteger(recordedAt) || recordedAt < 1 || !projection.safeParse(recoveryProjection).success) return options.invalid();
|
|
9052
|
+
await options.locked(async (assertOwnership) => {
|
|
9053
|
+
await recoverLocked(assertOwnership);
|
|
9054
|
+
let row3 = await required(), occurrence = `rebase:${previous.byteOffset}:${previous.anchor.sha256}:${Number(skippedHistory)}:${recordedAt}`;
|
|
9055
|
+
if (row3.lastFrame?.occurrence === occurrence && row3.byteOffset === target2.endOffset && JSON.stringify(row3.anchor) === JSON.stringify(target2))
|
|
9056
|
+
return row3.projection !== recoveryProjection ? options.invalid() : void 0;
|
|
9057
|
+
if (row3.entries.length) throw Error("SYNC_SOURCE_RECOVERY_PENDING");
|
|
9058
|
+
if (row3.byteOffset !== previous.byteOffset || row3.discardUntilNewline !== previous.discardUntilNewline || JSON.stringify(row3.anchor) !== JSON.stringify(previous.anchor)) return options.invalid();
|
|
9059
|
+
if (row3.skippedBytes > target2.endOffset) throw Error("SYNC_SOURCE_RECOVERY_UNAVAILABLE");
|
|
9060
|
+
row3.byteOffset = target2.endOffset, row3.anchor = { ...target2 }, row3.discardUntilNewline = !1, row3.lastGap = null, row3.projection = recoveryProjection, row3.lastFrame = {
|
|
9061
|
+
...stream,
|
|
9062
|
+
occurrence,
|
|
9063
|
+
sourceSha256: target2.sha256,
|
|
9064
|
+
startOffset: target2.startOffset,
|
|
9065
|
+
endOffset: target2.endOffset,
|
|
9066
|
+
anchor: { ...target2 }
|
|
9067
|
+
}, await write(row3, assertOwnership);
|
|
9068
|
+
});
|
|
9069
|
+
},
|
|
9042
9070
|
recover: () => options.locked(recoverLocked),
|
|
9043
9071
|
drain: (maximum = 64, signal) => options.drainLocked(async () => {
|
|
9044
9072
|
if (!Number.isSafeInteger(maximum) || maximum < 1 || maximum > 256) return options.invalid();
|
|
@@ -9063,6 +9091,23 @@ function createSourceJournal(options) {
|
|
|
9063
9091
|
function createSourcePair(options) {
|
|
9064
9092
|
let { source: source2, lanes, laneStreams } = options, recover = async () => {
|
|
9065
9093
|
for (let lane of lanes) await lane.recover();
|
|
9094
|
+
}, rebaseMarker = (row3) => /^rebase:([1-9][0-9]*):([a-f0-9]{64}):([01]):([1-9][0-9]*)$/.exec(row3.lastFrame?.occurrence ?? ""), finishRebase = async () => {
|
|
9095
|
+
let rows = await Promise.all(lanes.map((lane) => lane.load())), candidates = [];
|
|
9096
|
+
for (let index2 of [0, 1]) {
|
|
9097
|
+
let row4 = rows[index2];
|
|
9098
|
+
if (!row4) continue;
|
|
9099
|
+
let marker2 = rebaseMarker(row4);
|
|
9100
|
+
if (!marker2) continue;
|
|
9101
|
+
let peer2 = rows[1 - index2];
|
|
9102
|
+
if (!peer2) return options.invalid();
|
|
9103
|
+
row4.byteOffset === peer2.byteOffset && JSON.stringify(row4.anchor) === JSON.stringify(peer2.anchor) && row4.projection === peer2.projection && row4.lastFrame?.occurrence === peer2.lastFrame?.occurrence || peer2.byteOffset === Number(marker2[1]) && peer2.anchor?.sha256 === marker2[2] && candidates.push({ index: index2, marker: marker2 });
|
|
9104
|
+
}
|
|
9105
|
+
if (!candidates.length) return;
|
|
9106
|
+
if (candidates.sort((a, b) => Number(b.marker[4]) - Number(a.marker[4])), candidates.length > 1 && candidates[0].marker[4] === candidates[1].marker[4])
|
|
9107
|
+
throw Error("SYNC_SOURCE_RECOVERY_UNAVAILABLE");
|
|
9108
|
+
let { index, marker } = candidates[0], row3 = rows[index], peer = rows[1 - index];
|
|
9109
|
+
if (row3.entries.length || peer.entries.length) throw Error("SYNC_SOURCE_RECOVERY_PENDING");
|
|
9110
|
+
await lanes[1 - index].rebase(position2(peer), row3.anchor, marker[3] === "1", Number(marker[4]), row3.projection);
|
|
9066
9111
|
}, position2 = (row3) => ({
|
|
9067
9112
|
byteOffset: row3.byteOffset,
|
|
9068
9113
|
anchor: row3.anchor ? { ...row3.anchor } : null,
|
|
@@ -9070,14 +9115,33 @@ function createSourcePair(options) {
|
|
|
9070
9115
|
}), earliest = (rows) => {
|
|
9071
9116
|
let ordered = [...rows].sort((a, b) => a.byteOffset - b.byteOffset);
|
|
9072
9117
|
if (ordered.length === 2 && ordered[0].byteOffset === ordered[1].byteOffset && JSON.stringify(position2(ordered[0])) !== JSON.stringify(position2(ordered[1]))) return options.invalid();
|
|
9073
|
-
let baseline = position2(ordered[0]), pending2 = rows.flatMap((row3) =>
|
|
9074
|
-
|
|
9118
|
+
let baseline = position2(ordered[0]), pending2 = rows.flatMap((row3) => {
|
|
9119
|
+
let frames = row3.entries.filter((entry5) => entry5.state === "PREPARING" && entry5.frame.startOffset === baseline.byteOffset).map((entry5) => entry5.frame);
|
|
9120
|
+
return row3.byteOffset > baseline.byteOffset && row3.lastFrame && !rebaseMarker(row3) && row3.lastFrame.startOffset === baseline.byteOffset && row3.lastFrame.endOffset === row3.byteOffset && frames.push(row3.lastFrame), frames.map((frame3) => ({
|
|
9121
|
+
startOffset: frame3.startOffset,
|
|
9122
|
+
endOffset: frame3.endOffset,
|
|
9123
|
+
sourceSha256: frame3.sourceSha256
|
|
9124
|
+
}));
|
|
9125
|
+
});
|
|
9126
|
+
if (pending2.some((value) => JSON.stringify(value) !== JSON.stringify(pending2[0]))) return options.invalid();
|
|
9127
|
+
let marker = rebaseMarker(ordered[0]);
|
|
9128
|
+
return {
|
|
9129
|
+
...baseline,
|
|
9130
|
+
...pending2.length && { pendingFrameEndOffset: pending2[0].endOffset, pendingFrame: pending2[0] },
|
|
9131
|
+
...marker && { recovered: {
|
|
9132
|
+
previousOffset: Number(marker[1]),
|
|
9133
|
+
boundaryOffset: baseline.byteOffset,
|
|
9134
|
+
skippedHistory: marker[3] === "1",
|
|
9135
|
+
recordedAt: Number(marker[4]),
|
|
9136
|
+
projection: ordered[0].projection
|
|
9137
|
+
} }
|
|
9138
|
+
};
|
|
9075
9139
|
};
|
|
9076
9140
|
return Object.freeze({
|
|
9077
9141
|
open: (initial, validateInitial) => {
|
|
9078
9142
|
let snapshot2 = typeof initial == "number" ? initial : position2(initial);
|
|
9079
9143
|
return options.locked(async () => {
|
|
9080
|
-
await recover();
|
|
9144
|
+
await recover(), await finishRebase();
|
|
9081
9145
|
let present = (await Promise.all(lanes.map((lane) => lane.load()))).filter((row3) => row3 !== null);
|
|
9082
9146
|
if (present.length === 1 && (present[0].lastFrame !== null || present[0].entries.length !== 0 || present[0].skippedBytes !== 0 || present[0].projection !== null))
|
|
9083
9147
|
return options.invalid();
|
|
@@ -9092,8 +9156,14 @@ function createSourcePair(options) {
|
|
|
9092
9156
|
let snapshot2 = { ...frame3, ...frame3.anchor && { anchor: { ...frame3.anchor } } }, factories = [...prepare];
|
|
9093
9157
|
return options.locked(async () => {
|
|
9094
9158
|
let result = [null, null];
|
|
9095
|
-
for (let index of [0, 1])
|
|
9096
|
-
|
|
9159
|
+
for (let index of [0, 1]) {
|
|
9160
|
+
let row3 = await lanes[index].load();
|
|
9161
|
+
result[index] = await lanes[index].admit(
|
|
9162
|
+
{ ...snapshot2, streamSha256: laneStreams[index] },
|
|
9163
|
+
factories[index],
|
|
9164
|
+
row3 && rebaseMarker(row3) ? null : void 0
|
|
9165
|
+
);
|
|
9166
|
+
}
|
|
9097
9167
|
return result;
|
|
9098
9168
|
});
|
|
9099
9169
|
},
|
|
@@ -9104,6 +9174,20 @@ function createSourcePair(options) {
|
|
|
9104
9174
|
for (let lane of lanes) await lane.skip(snapshot2);
|
|
9105
9175
|
});
|
|
9106
9176
|
},
|
|
9177
|
+
rebase: async (previous, target2, skippedHistory, recoveryProjection = null) => {
|
|
9178
|
+
if (!validSourceRebase(previous, target2, skippedHistory)) return options.invalid();
|
|
9179
|
+
let before = position2(previous), next = { ...target2 };
|
|
9180
|
+
return options.locked(async () => {
|
|
9181
|
+
await recover(), await finishRebase();
|
|
9182
|
+
let rows = await Promise.all(lanes.map((lane) => lane.load()));
|
|
9183
|
+
if (rows.some((row3) => !row3)) return options.invalid();
|
|
9184
|
+
if (rows.some((row3) => row3.entries.length || JSON.stringify(position2(row3)) !== JSON.stringify(before)))
|
|
9185
|
+
throw Error("SYNC_SOURCE_RECOVERY_PENDING");
|
|
9186
|
+
let recordedAt = Math.max(Date.now(), ...rows.map((row3) => Number(rebaseMarker(row3)?.[4] ?? 0) + 1));
|
|
9187
|
+
for (let lane of lanes) await lane.rebase(before, next, skippedHistory, recordedAt, recoveryProjection);
|
|
9188
|
+
return earliest(await Promise.all(lanes.map(async (lane) => await lane.load())));
|
|
9189
|
+
});
|
|
9190
|
+
},
|
|
9107
9191
|
recover: () => options.locked(recover),
|
|
9108
9192
|
drain: async (maximumPerLane = 64, signal) => {
|
|
9109
9193
|
let count4 = 0, failure2, failed = !1;
|
|
@@ -10166,7 +10250,19 @@ var import_zod6 = require("zod"), import_node_crypto11 = require("node:crypto"),
|
|
|
10166
10250
|
sessionGenerationId: uuid7,
|
|
10167
10251
|
provider: import_zod6.z.enum(["codex", "claude", "agy"]),
|
|
10168
10252
|
entries: import_zod6.z.array(entry3).max(64)
|
|
10169
|
-
}).strict(), normalize = (text2, mode) => mode === "trim" ? text2.trim() : text2.replace(/\s+/g, " ").trim(), tokenFor = (target2) => (0, import_node_crypto11.createHash)("sha256").update(JSON.stringify(target2)).digest("hex")
|
|
10253
|
+
}).strict(), normalize = (text2, mode) => mode === "trim" ? text2.trim() : text2.replace(/\s+/g, " ").trim(), tokenFor = (target2) => (0, import_node_crypto11.createHash)("sha256").update(JSON.stringify(target2)).digest("hex"), omissionPlan = import_zod6.z.object({
|
|
10254
|
+
kind: import_zod6.z.literal("omitted-echoes-v1"),
|
|
10255
|
+
ownerSha256: hash2,
|
|
10256
|
+
matches: import_zod6.z.array(import_zod6.z.tuple([hash2, hash2, hash2])).max(64)
|
|
10257
|
+
}).strict(), ownerHash = (row3) => (0, import_node_crypto11.createHash)("sha256").update(JSON.stringify([
|
|
10258
|
+
row3.operationId,
|
|
10259
|
+
row3.sessionId,
|
|
10260
|
+
row3.sessionGenerationId,
|
|
10261
|
+
row3.provider
|
|
10262
|
+
])).digest("hex"), reservationHash = (e) => (0, import_node_crypto11.createHash)("sha256").update(JSON.stringify({ ...e, claim: null, claimedEchoSha256: null })).digest("hex"), matchesText = (e, content, nativeMs) => {
|
|
10263
|
+
let normalized = normalize(content, e.normalization);
|
|
10264
|
+
return nativeMs >= Math.floor(e.armedAt / e.clockPrecisionMs) * e.clockPrecisionMs && nativeMs <= e.expiresAt && (e.normalized === normalized || e.allowSuffix && normalized.length >= 16 && normalized.length / e.normalized.length >= 0.35 && e.normalized.endsWith(normalized));
|
|
10265
|
+
};
|
|
10170
10266
|
function decodeMobileEcho(value) {
|
|
10171
10267
|
let parsed = row2.parse(value);
|
|
10172
10268
|
if (new Set(parsed.entries.map((e) => e.token)).size !== parsed.entries.length || parsed.entries.some((e) => e.token !== tokenFor(e.target))) throw Error("SYNC_MOBILE_ECHO_INVALID");
|
|
@@ -10196,6 +10292,31 @@ function createMobileEchoJournal(options) {
|
|
|
10196
10292
|
row3.entries.push(snapshot2), await save();
|
|
10197
10293
|
});
|
|
10198
10294
|
},
|
|
10295
|
+
planOmitted: (records) => options.mutate(async (row3) => {
|
|
10296
|
+
let eligible = row3.entries.filter((e) => !e.claim), used = /* @__PURE__ */ new Set(), proofs = /* @__PURE__ */ new Set(), matches2 = [];
|
|
10297
|
+
if (eligible.length) for (let record2 of records) {
|
|
10298
|
+
hash2.parse(record2.sourceSha256);
|
|
10299
|
+
let nativeMs = Date.parse(record2.timestamp);
|
|
10300
|
+
if (!Number.isFinite(nativeMs) || proofs.has(record2.sourceSha256)) continue;
|
|
10301
|
+
let match = eligible.find((e) => !used.has(e.token) && matchesText(e, record2.content, nativeMs));
|
|
10302
|
+
if (match && (used.add(match.token), proofs.add(record2.sourceSha256), matches2.push([match.token, reservationHash(match), record2.sourceSha256])), used.size === eligible.length) break;
|
|
10303
|
+
}
|
|
10304
|
+
let plan = JSON.stringify({ kind: "omitted-echoes-v1", ownerSha256: ownerHash(row3), matches: matches2 });
|
|
10305
|
+
if (Buffer.byteLength(plan) > 16384) throw Error("SYNC_MOBILE_ECHO_INVALID");
|
|
10306
|
+
return plan;
|
|
10307
|
+
}),
|
|
10308
|
+
settleOmitted: (value) => {
|
|
10309
|
+
if (Buffer.byteLength(value) > 16384) throw Error("SYNC_MOBILE_ECHO_INVALID");
|
|
10310
|
+
let plan = omissionPlan.parse(JSON.parse(value)), tokens = new Set(plan.matches.map((m) => m[0])), proofs = new Set(plan.matches.map((m) => m[2]));
|
|
10311
|
+
if (tokens.size !== plan.matches.length || proofs.size !== plan.matches.length) throw Error("SYNC_MOBILE_ECHO_INVALID");
|
|
10312
|
+
return options.mutate(async (row3, save) => {
|
|
10313
|
+
if (ownerHash(row3) !== plan.ownerSha256) throw Error("SYNC_MOBILE_ECHO_INVALID");
|
|
10314
|
+
let exact2 = new Map(plan.matches.map(([token4, fingerprint2]) => [token4, fingerprint2])), before = row3.entries.length;
|
|
10315
|
+
row3.entries = row3.entries.filter((e) => e.claim || exact2.get(e.token) !== reservationHash(e));
|
|
10316
|
+
let count4 = before - row3.entries.length;
|
|
10317
|
+
return count4 && await save(), count4;
|
|
10318
|
+
});
|
|
10319
|
+
},
|
|
10199
10320
|
claim: (value, content, timestamp5) => {
|
|
10200
10321
|
let next = frame2.parse(value), echoHash = (e) => (0, import_node_crypto11.createHash)("sha256").update(normalize(content, e.normalization)).digest("hex"), nativeMs = Date.parse(timestamp5);
|
|
10201
10322
|
if (!Number.isFinite(nativeMs)) throw Error("SYNC_MOBILE_ECHO_TIMESTAMP_INVALID");
|
|
@@ -10203,10 +10324,7 @@ function createMobileEchoJournal(options) {
|
|
|
10203
10324
|
let claimed = row3.entries.find((e) => e.claim?.streamSha256 === next.streamSha256 && e.claim?.occurrence === next.occurrence);
|
|
10204
10325
|
if (claimed)
|
|
10205
10326
|
return JSON.stringify(claimed.claim) !== JSON.stringify(next) || claimed.claimedEchoSha256 !== echoHash(claimed) ? options.collision() : !0;
|
|
10206
|
-
let pending2 = row3.entries.find((e) =>
|
|
10207
|
-
let normalized = normalize(content, e.normalization);
|
|
10208
|
-
return !e.claim && nativeMs >= Math.floor(e.armedAt / e.clockPrecisionMs) * e.clockPrecisionMs && nativeMs <= e.expiresAt && (e.normalized === normalized || e.allowSuffix && normalized.length >= 16 && normalized.length / e.normalized.length >= 0.35 && e.normalized.endsWith(normalized));
|
|
10209
|
-
});
|
|
10327
|
+
let pending2 = row3.entries.find((e) => !e.claim && matchesText(e, content, nativeMs));
|
|
10210
10328
|
return pending2 ? (pending2.claim = next, pending2.claimedEchoSha256 = echoHash(pending2), await save(), !0) : !1;
|
|
10211
10329
|
});
|
|
10212
10330
|
},
|
|
@@ -13975,6 +14093,7 @@ var AppSyncClient = class _AppSyncClient {
|
|
|
13975
14093
|
this.syncRegistrations = /* @__PURE__ */ new Map();
|
|
13976
14094
|
// MARK: - Heartbeat
|
|
13977
14095
|
this.heartbeatTimers = /* @__PURE__ */ new Map();
|
|
14096
|
+
this.heartbeatReadiness = /* @__PURE__ */ new Map();
|
|
13978
14097
|
/** Identity tokens invalidate in-flight pulses when a session is stopped. */
|
|
13979
14098
|
this.heartbeatTokens = /* @__PURE__ */ new Map();
|
|
13980
14099
|
/** Shared initial confirmation makes duplicate start calls idempotent. */
|
|
@@ -18300,6 +18419,13 @@ var AppSyncClient = class _AppSyncClient {
|
|
|
18300
18419
|
cleanupApplyUserDecisionWatcherState(state) {
|
|
18301
18420
|
state.destroyed = !0, this.cancelReconnectReconciliationWait(state), state.reconnectTimer && (clearTimeout(state.reconnectTimer), state.reconnectTimer = void 0), state.keepAliveTimer && (clearTimeout(state.keepAliveTimer), state.keepAliveTimer = void 0), state.ws && (disposeWatcherSocket(state.ws, state.subscriptionId), state.ws = null);
|
|
18302
18421
|
}
|
|
18422
|
+
/** Local producer health, not a quota/transport flag. Reconnect must not
|
|
18423
|
+
* advertise readiness while the owning transcript reader is degraded. */
|
|
18424
|
+
setHeartbeatReadiness(sessionId, ready) {
|
|
18425
|
+
return this.heartbeatReadiness.set(sessionId, ready), () => {
|
|
18426
|
+
this.heartbeatReadiness.get(sessionId) === ready && this.heartbeatReadiness.delete(sessionId);
|
|
18427
|
+
};
|
|
18428
|
+
}
|
|
18303
18429
|
/**
|
|
18304
18430
|
* Start periodic heartbeat for a session.
|
|
18305
18431
|
* Updates lastHeartbeatAt on the session every intervalMs (default 2 minutes).
|
|
@@ -18382,6 +18508,11 @@ var AppSyncClient = class _AppSyncClient {
|
|
|
18382
18508
|
*/
|
|
18383
18509
|
async sendHeartbeat(sessionId, token4) {
|
|
18384
18510
|
if (this.heartbeatTokens.get(sessionId) !== token4) return "stopped";
|
|
18511
|
+
try {
|
|
18512
|
+
if (this.heartbeatReadiness.get(sessionId)?.() === !1) return "stopped";
|
|
18513
|
+
} catch {
|
|
18514
|
+
return "stopped";
|
|
18515
|
+
}
|
|
18385
18516
|
try {
|
|
18386
18517
|
let heartbeatAt = (/* @__PURE__ */ new Date()).toISOString(), refreshed = await this.updateSession({
|
|
18387
18518
|
sessionId,
|
|
@@ -18750,6 +18881,14 @@ async function updateMobileInputStatus(update, event, status) {
|
|
|
18750
18881
|
return receipt2;
|
|
18751
18882
|
}
|
|
18752
18883
|
|
|
18884
|
+
// src/appsync/sync-source-recovery.ts
|
|
18885
|
+
var DEFAULT_SYNC_SOURCE_RECOVERY_POLICY = Object.freeze({
|
|
18886
|
+
staleAfterMs: 5 * 6e4,
|
|
18887
|
+
maximumRecentMessages: 20,
|
|
18888
|
+
anchorSearchBytes: 8 * 1024 * 1024,
|
|
18889
|
+
maximumScanBytes: 64 * 1024 * 1024
|
|
18890
|
+
});
|
|
18891
|
+
|
|
18753
18892
|
// src/appsync/sync-source-file.ts
|
|
18754
18893
|
var CHUNK = 64 * 1024;
|
|
18755
18894
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { DesktopSyncSourceAnchor } from '../appsync/sync-source-cursor';
|
|
1
2
|
import { z } from 'zod';
|
|
2
3
|
import type { Logger } from '../logger';
|
|
3
4
|
/** Keep every ordinary replay read comfortably below Node/Buffer's platform limits. */
|
|
@@ -67,6 +68,10 @@ export interface ToolReplayInitialBoundary {
|
|
|
67
68
|
};
|
|
68
69
|
size: number;
|
|
69
70
|
}
|
|
71
|
+
/** The ordinary source has validated this descriptor/anchor before tool replay. */
|
|
72
|
+
export interface ToolReplayVerifiedBoundary extends ToolReplayInitialBoundary {
|
|
73
|
+
anchor: DesktopSyncSourceAnchor | null;
|
|
74
|
+
}
|
|
70
75
|
/** Capture a native boundary synchronously before lifecycle/cloud awaits.
|
|
71
76
|
* Existing partial records remain unread. Memory and reverse lookup are bounded. */
|
|
72
77
|
export declare function captureToolReplayBoundary(filePath: string, initialOffset?: number): ToolReplayInitialBoundary;
|
|
@@ -146,6 +151,11 @@ export declare class ToolReplayCursor {
|
|
|
146
151
|
load(initialBoundary?: ToolReplayInitialBoundary, requireExisting?: boolean): Promise<void>;
|
|
147
152
|
/** The current durable checkpoint (0 when fresh). */
|
|
148
153
|
byteOffset(): number;
|
|
154
|
+
needsVerifiedRebase(boundary: ToolReplayVerifiedBoundary): boolean;
|
|
155
|
+
private verifyBoundary;
|
|
156
|
+
/** Only a recognized nonzero source recovery may replace file coordinates.
|
|
157
|
+
* Caller seals in-memory tools first; ledger and admitted outbox stay intact. */
|
|
158
|
+
adoptVerifiedBoundary(boundary: ToolReplayVerifiedBoundary): Promise<void>;
|
|
149
159
|
/**
|
|
150
160
|
* Read + byte-frame ONE BOUNDED transcript batch from the durable checkpoint
|
|
151
161
|
* (or 0 after a rotation). PURE — persists nothing. File positions are ordinary
|
|
@@ -159,7 +169,7 @@ export declare class ToolReplayCursor {
|
|
|
159
169
|
* unbounded while one malformed/huge JSONL RECORD has a controlled bound.
|
|
160
170
|
* The trailing partial is returned as `carryover` and re-read next cycle.
|
|
161
171
|
*/
|
|
162
|
-
readFrames(): Promise<ReadFramesResult>;
|
|
172
|
+
readFrames(verifiedBoundary?: ToolReplayVerifiedBoundary): Promise<ReadFramesResult>;
|
|
163
173
|
/**
|
|
164
174
|
* Advance the durable checkpoint over a contiguous durably-outboxed prefix
|
|
165
175
|
* (§4.5) and persist atomically. FORWARD-ONLY **within the same file**: a
|
package/package.json
CHANGED