@quantiya/codevibe-core 2.0.78 → 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.
@@ -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), frameAnchor = (value) => value.anchor ?? {
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) => row3.entries.filter((entry5) => entry5.state === "PREPARING" && entry5.frame.startOffset === baseline.byteOffset).map((entry5) => entry5.frame.endOffset));
9074
- return { ...baseline, ...pending2.length && { pendingFrameEndOffset: Math.min(...pending2) } };
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
- result[index] = await lanes[index].admit({ ...snapshot2, streamSha256: laneStreams[index] }, factories[index]);
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
 
@@ -77487,6 +77626,7 @@ function validateOutboxLocation(value, generation, file) {
77487
77626
  }
77488
77627
  function definitiveRejectionCode(error) {
77489
77628
  if (!(error instanceof AppSyncGraphQLError)) return null;
77629
+ if (error.errorType === "SYNC_QUOTA_EXHAUSTED") return "SYNC_QUOTA_EXHAUSTED";
77490
77630
  let values = [error.errorType, error.message.replace(/^GraphQL error: /, "")].filter(
77491
77631
  (value) => typeof value == "string"
77492
77632
  );
@@ -77549,14 +77689,14 @@ var WorkspaceTerminalCoordinator = class {
77549
77689
  throw new Error("WorkspaceTerminalCoordinator: record exceeds size limit");
77550
77690
  return bytes;
77551
77691
  }
77552
- async readJson(filePath) {
77692
+ async readJson(filePath, missing = null) {
77553
77693
  try {
77554
77694
  let stat14 = await import_node_fs34.promises.lstat(filePath);
77555
77695
  if (!stat14.isFile() || stat14.isSymbolicLink() || stat14.size > MAX_RECORD_BYTES2)
77556
77696
  throw new Error("WorkspaceTerminalCoordinator: unsafe or oversized record");
77557
77697
  return JSON.parse(await import_node_fs34.promises.readFile(filePath, "utf8"));
77558
77698
  } catch (error) {
77559
- if (error.code === "ENOENT") return null;
77699
+ if (error.code === "ENOENT") return missing;
77560
77700
  throw error;
77561
77701
  }
77562
77702
  }
@@ -77949,6 +78089,7 @@ var WorkspaceTerminalCoordinator = class {
77949
78089
  ]);
77950
78090
  }
77951
78091
  async flushTerminalIntent(intent) {
78092
+ if (await this.settleQuarantined(intent.nonce, intent.sessionGenerationId)) return;
77952
78093
  intent.subjectKind === "task" ? (validateTerminal(intent), await this.prepareExactInput(intent, "outbox")) : (validateGroupTerminal(intent), await this.prepareExactInput(intent, "draft"), await this.promoteDraftToOutbox(intent));
77953
78094
  let row3 = await this.readJson(
77954
78095
  this.outboxPath(intent.nonce, intent.sessionGenerationId)
@@ -77956,25 +78097,64 @@ var WorkspaceTerminalCoordinator = class {
77956
78097
  if (!row3) throw new Error("WorkspaceTerminalCoordinator: exact outbox row is unavailable");
77957
78098
  await this.sendOutbox(validateOutboxForIntent(row3, intent));
77958
78099
  }
77959
- async acknowledge(nonce, generation = this.generation()) {
78100
+ async syncSettlementDirectory(directory) {
78101
+ let handle;
78102
+ try {
78103
+ handle = await import_node_fs34.promises.open(directory, import_node_fs34.constants.O_RDONLY | import_node_fs34.constants.O_DIRECTORY | import_node_fs34.constants.O_NOFOLLOW);
78104
+ } catch (error) {
78105
+ if (error.code === "ENOENT") return;
78106
+ throw error;
78107
+ }
78108
+ try {
78109
+ await handle.sync();
78110
+ } finally {
78111
+ await handle.close();
78112
+ }
78113
+ }
78114
+ async persistSettlementMarker(file, record2) {
78115
+ await atomicWriteFileSync2(file, this.serialize(record2), { requireDirectorySync: !0 });
78116
+ for (let directory of [this.quarantineRoot(), path74.join(this.rootDir, "quarantine"), this.rootDir]) {
78117
+ let handle = await import_node_fs34.promises.open(directory, import_node_fs34.constants.O_RDONLY | import_node_fs34.constants.O_DIRECTORY | import_node_fs34.constants.O_NOFOLLOW);
78118
+ try {
78119
+ await handle.sync();
78120
+ } finally {
78121
+ await handle.close();
78122
+ }
78123
+ }
78124
+ }
78125
+ async acknowledge(nonce, generation = this.generation(), settlement = !1) {
78126
+ let sync = (directory) => settlement ? this.syncSettlementDirectory(directory) : fsyncDir(directory);
77960
78127
  await import_node_fs34.promises.unlink(this.outboxPath(nonce, generation)).catch((error) => {
77961
78128
  if (error.code !== "ENOENT") throw error;
77962
- }), await fsyncDir(this.outboxDir(generation)), await import_node_fs34.promises.unlink(this.draftPath(nonce, generation)).catch((error) => {
78129
+ }), await sync(this.outboxDir(generation)), await import_node_fs34.promises.unlink(this.draftPath(nonce, generation)).catch((error) => {
77963
78130
  if (error.code !== "ENOENT") throw error;
77964
- }), await fsyncDir(this.draftDir(generation)), await import_node_fs34.promises.unlink(this.intentPath(nonce, generation)).catch((error) => {
78131
+ }), await sync(this.draftDir(generation)), await import_node_fs34.promises.unlink(this.intentPath(nonce, generation)).catch((error) => {
77965
78132
  if (error.code !== "ENOENT") throw error;
77966
- }), await fsyncDir(this.intentDir(generation));
78133
+ }), await sync(this.intentDir(generation));
77967
78134
  }
77968
78135
  async quarantine(nonce, rejectionCode, generation = this.generation()) {
77969
78136
  let raw = await this.readJson(this.outboxPath(nonce, generation));
77970
78137
  if (!raw) return;
77971
- let row3 = validateOutbox(raw), directory = this.quarantineDir(generation), files = await this.listRecordsAcrossGenerations(this.quarantineRoot());
78138
+ let row3 = validateOutbox(raw);
78139
+ if (await this.settleQuarantined(nonce, generation, row3.inputHash)) return;
78140
+ let directory = this.quarantineDir(generation), files = await this.listRecordsAcrossGenerations(this.quarantineRoot());
77972
78141
  if (files.length >= MAX_QUARANTINE_RECORDS) {
77973
- let oldest = (await Promise.all(files.map(async (record2) => ({
78142
+ let pending2 = /* @__PURE__ */ new Set();
78143
+ for (let root of [this.intentRoot(), this.outboxRoot(), this.draftRoot()])
78144
+ for (let record2 of await this.listRecordsAcrossGenerations(root))
78145
+ pending2.add(`${record2.generation}/${sha2563(path74.basename(record2.file, ".json"))}`);
78146
+ let disposable = files.filter((record2) => !pending2.has(`${record2.generation}/${path74.basename(record2.file, ".json")}`)), oldest = (await Promise.all(disposable.map(async (record2) => ({
77974
78147
  ...record2,
77975
78148
  mtimeMs: (await import_node_fs34.promises.stat(record2.file)).mtimeMs
77976
78149
  })))).sort((left, right) => left.mtimeMs - right.mtimeMs || left.file.localeCompare(right.file))[0];
77977
- await import_node_fs34.promises.unlink(oldest.file), await fsyncDir(path74.dirname(oldest.file));
78150
+ if (!oldest) throw new Error("WorkspaceTerminalCoordinator: pending settlement capacity is full");
78151
+ for (let directory2 of [this.intentDir(oldest.generation), this.outboxDir(oldest.generation), this.draftDir(oldest.generation)]) {
78152
+ await this.syncSettlementDirectory(directory2);
78153
+ for (let file of await this.listRecords(directory2))
78154
+ if (sha2563(path74.basename(file, ".json")) === path74.basename(oldest.file, ".json"))
78155
+ throw new Error("WorkspaceTerminalCoordinator: settlement cleanup is still pending");
78156
+ }
78157
+ await import_node_fs34.promises.unlink(oldest.file), await this.syncSettlementDirectory(path74.dirname(oldest.file));
77978
78158
  }
77979
78159
  let diagnostic = {
77980
78160
  version: QUARANTINE_VERSION,
@@ -77983,10 +78163,37 @@ var WorkspaceTerminalCoordinator = class {
77983
78163
  rejectionCode,
77984
78164
  quarantinedAt: this.now().toISOString()
77985
78165
  };
77986
- await atomicWriteFileSync2(
78166
+ await this.persistSettlementMarker(
77987
78167
  path74.join(directory, `${sha2563(nonce)}.json`),
77988
- this.serialize(diagnostic)
77989
- ), await this.acknowledge(nonce, generation), this.reportSyncIssue(`Workspace result could not be synchronized (${rejectionCode}).`);
78168
+ diagnostic
78169
+ ), await this.acknowledge(nonce, generation, !0), this.reportSyncIssue(`Workspace result could not be synchronized (${rejectionCode}).`);
78170
+ }
78171
+ async settleQuarantined(nonce, generation, inputHash) {
78172
+ let markerPath = path74.join(this.quarantineDir(generation), `${sha2563(nonce)}.json`), missing = /* @__PURE__ */ Symbol("absent settlement record"), raw = await this.readJson(markerPath, missing);
78173
+ if (raw === missing) return !1;
78174
+ if (raw === null || typeof raw != "object" || Array.isArray(raw))
78175
+ throw new Error("WorkspaceTerminalCoordinator: invalid settlement barrier");
78176
+ let record2 = raw;
78177
+ if (record2.version !== QUARANTINE_VERSION || record2.nonceHash !== sha2563(nonce) || typeof record2.inputHash != "string" || !SHA256_RE2.test(record2.inputHash) || inputHash !== void 0 && record2.inputHash !== inputHash || typeof record2.rejectionCode != "string" || ![
78178
+ "SYNC_QUOTA_EXHAUSTED",
78179
+ "OUTCOME_ADMISSION_EXPIRED",
78180
+ "OUTCOME_ADMISSION_CONFLICT",
78181
+ "GENERATION_MISMATCH",
78182
+ "ACCOUNT_DELETING"
78183
+ ].includes(record2.rejectionCode) || typeof record2.quarantinedAt != "string")
78184
+ throw new Error("WorkspaceTerminalCoordinator: invalid settlement barrier");
78185
+ let intentValue = await this.readJson(this.intentPath(nonce, generation), missing), intent = intentValue === missing ? void 0 : validateAnyIntent(intentValue);
78186
+ if (intent && (intent.nonce !== nonce || intent.sessionId !== this.session.sessionId || intent.sessionGenerationId !== generation))
78187
+ throw new Error("WorkspaceTerminalCoordinator: settlement intent identity changed");
78188
+ for (let file of [this.outboxPath(nonce, generation), this.draftPath(nonce, generation)]) {
78189
+ let saved = await this.readJson(file, missing);
78190
+ if (saved === missing) continue;
78191
+ let row3 = validateOutboxLocation(saved, generation, file);
78192
+ if (row3.sessionId !== this.session.sessionId || row3.inputHash !== record2.inputHash)
78193
+ throw new Error("WorkspaceTerminalCoordinator: settlement identity changed");
78194
+ intent && validateOutboxForIntent(row3, intent);
78195
+ }
78196
+ return await this.persistSettlementMarker(markerPath, record2), await this.acknowledge(nonce, generation, !0), this.reportSyncIssue(`Workspace result could not be synchronized (${record2.rejectionCode}).`), !0;
77990
78197
  }
77991
78198
  reportSyncIssue(message2) {
77992
78199
  this.reportedSyncIssues.has(message2) || (this.reportedSyncIssues.add(message2), this.onSyncIssue?.(message2));
@@ -77994,6 +78201,7 @@ var WorkspaceTerminalCoordinator = class {
77994
78201
  async sendOutbox(row3) {
77995
78202
  for (let attempt = 1; attempt <= 2; attempt += 1)
77996
78203
  try {
78204
+ if (await this.settleQuarantined(row3.nonce, row3.sessionGenerationId, row3.inputHash)) return;
77997
78205
  let target2 = this.outboxPath(row3.nonce, row3.sessionGenerationId), current = validateOutboxLocation(await this.readJson(target2), row3.sessionGenerationId, target2), { syncProtocol: priorProtocol, ...original } = row3, { syncProtocol: currentProtocol, ...persisted } = current;
77998
78206
  if (canonicalJson3(original) !== canonicalJson3(persisted) || priorProtocol === "SYNC_V2" && currentProtocol !== "SYNC_V2")
77999
78207
  throw new Error("WorkspaceTerminalCoordinator: outbox identity or protocol changed");
@@ -107,8 +107,11 @@ export declare class WorkspaceTerminalCoordinator implements WorkspaceOutcomeSin
107
107
  private prepareExactInput;
108
108
  private promoteDraftToOutbox;
109
109
  private flushTerminalIntent;
110
+ private syncSettlementDirectory;
111
+ private persistSettlementMarker;
110
112
  private acknowledge;
111
113
  private quarantine;
114
+ private settleQuarantined;
112
115
  private reportSyncIssue;
113
116
  private sendOutbox;
114
117
  /** Reconcile terminal receipts first, then replay exact encrypted bytes. */
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quantiya/codevibe-core",
3
- "version": "2.0.78",
3
+ "version": "2.0.80",
4
4
  "description": "Core library for CodeVibe plugins - shared keychain, crypto, AppSync, and auth functionality",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",