@ouro.bot/cli 0.1.0-alpha.540 → 0.1.0-alpha.541

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/changelog.json CHANGED
@@ -1,6 +1,13 @@
1
1
  {
2
2
  "_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
3
3
  "versions": [
4
+ {
5
+ "version": "0.1.0-alpha.541",
6
+ "changes": [
7
+ "BlueBubbles recovery now treats message GUID completion as authoritative across repaired session keys, so stale `chat_identifier:unknown` mutation/capture sidecars stop keeping iMessage health in a false pending-recovery state after the real chat turn has completed.",
8
+ "Adds regression coverage for recovered captured-inbound and mutation backlog records whose original degraded session key differs from the canonical processed chat key."
9
+ ]
10
+ },
4
11
  {
5
12
  "version": "0.1.0-alpha.540",
6
13
  "changes": [
@@ -828,7 +828,8 @@ async function handleBlueBubblesNormalizedEvent(event, resolvedDeps, source, opt
828
828
  }
829
829
  let ownsInFlightMessage = false;
830
830
  if (event.kind === "message") {
831
- if ((0, processed_log_1.hasProcessedBlueBubblesMessage)(agentName, event.chat.sessionKey, event.messageGuid)) {
831
+ if ((0, processed_log_1.hasProcessedBlueBubblesMessage)(agentName, event.chat.sessionKey, event.messageGuid)
832
+ || (0, processed_log_1.hasProcessedBlueBubblesMessageGuid)(agentName, event.messageGuid)) {
832
833
  (0, runtime_1.emitNervesEvent)({
833
834
  component: "senses",
834
835
  event: "senses.bluebubbles_recovery_skip",
@@ -1211,6 +1212,7 @@ async function handleBlueBubblesEvent(payload, deps = {}) {
1211
1212
  // normalizeBlueBubblesEvent rejects guidless payloads, so duplicate handling
1212
1213
  // only needs to discriminate between known processed, in-flight, or new.
1213
1214
  const duplicateReason = (0, processed_log_1.hasProcessedBlueBubblesMessage)(agentName, normalized.chat.sessionKey, normalized.messageGuid)
1215
+ || (0, processed_log_1.hasProcessedBlueBubblesMessageGuid)(agentName, normalized.messageGuid)
1214
1216
  ? "processed"
1215
1217
  : isBlueBubblesMessageInFlight(normalized.chat.sessionKey, normalized.messageGuid)
1216
1218
  ? "in_flight"
@@ -1237,7 +1239,7 @@ async function handleBlueBubblesEvent(payload, deps = {}) {
1237
1239
  }
1238
1240
  function countPendingRecoveryCandidates(agentName) {
1239
1241
  return (0, mutation_log_1.listBlueBubblesRecoveryCandidates)(agentName)
1240
- .filter((entry) => !(0, processed_log_1.hasProcessedBlueBubblesMessage)(agentName, entry.sessionKey, entry.messageGuid))
1242
+ .filter((entry) => !(0, processed_log_1.hasProcessedBlueBubblesMessageGuid)(agentName, entry.messageGuid))
1241
1243
  .length;
1242
1244
  }
1243
1245
  function countPendingCapturedInboundMessages(agentName) {
@@ -1252,7 +1254,7 @@ function listPendingCapturedInboundMessages(agentName) {
1252
1254
  seenMessageGuids.add(entry.messageGuid);
1253
1255
  return true;
1254
1256
  })
1255
- .filter((entry) => !(0, processed_log_1.hasProcessedBlueBubblesMessage)(agentName, entry.sessionKey, entry.messageGuid));
1257
+ .filter((entry) => !(0, processed_log_1.hasProcessedBlueBubblesMessageGuid)(agentName, entry.messageGuid));
1256
1258
  }
1257
1259
  function parseTimestampMs(value) {
1258
1260
  if (!value)
@@ -1281,7 +1283,7 @@ function blueBubblesPendingRecoverySnapshot(agentName, nowMs = Date.now()) {
1281
1283
  const pendingRecordedAt = [
1282
1284
  ...listPendingCapturedInboundMessages(agentName).map((entry) => entry.recordedAt),
1283
1285
  ...(0, mutation_log_1.listBlueBubblesRecoveryCandidates)(agentName)
1284
- .filter((entry) => !(0, processed_log_1.hasProcessedBlueBubblesMessage)(agentName, entry.sessionKey, entry.messageGuid))
1286
+ .filter((entry) => !(0, processed_log_1.hasProcessedBlueBubblesMessageGuid)(agentName, entry.messageGuid))
1285
1287
  .map((entry) => entry.recordedAt),
1286
1288
  ]
1287
1289
  .map((value) => ({ value, ms: Date.parse(value) }))
@@ -1468,7 +1470,7 @@ async function catchUpMissedBlueBubblesMessages(deps = {}, previousState, option
1468
1470
  result.inspected++;
1469
1471
  if (event.fromMe
1470
1472
  || event.timestamp < catchUpSince
1471
- || (0, processed_log_1.hasProcessedBlueBubblesMessage)(agentName, event.chat.sessionKey, event.messageGuid)
1473
+ || (0, processed_log_1.hasProcessedBlueBubblesMessageGuid)(agentName, event.messageGuid)
1472
1474
  || isBlueBubblesMessageInFlight(event.chat.sessionKey, event.messageGuid)) {
1473
1475
  result.skipped++;
1474
1476
  continue;
@@ -1578,6 +1580,7 @@ async function recoverCapturedBlueBubblesInboundMessages(deps = {}) {
1578
1580
  .sort((left, right) => (parseTimestampMs(left.recordedAt) ?? 0) - (parseTimestampMs(right.recordedAt) ?? 0));
1579
1581
  for (const entry of candidates) {
1580
1582
  if ((0, processed_log_1.hasProcessedBlueBubblesMessage)(agentName, entry.sessionKey, entry.messageGuid)
1583
+ || (0, processed_log_1.hasProcessedBlueBubblesMessageGuid)(agentName, entry.messageGuid)
1581
1584
  || isBlueBubblesMessageInFlight(entry.sessionKey, entry.messageGuid)) {
1582
1585
  result.skipped++;
1583
1586
  continue;
@@ -1627,6 +1630,7 @@ async function recoverMissedBlueBubblesMessages(deps = {}) {
1627
1630
  const result = { recovered: 0, skipped: 0, pending: 0, failed: 0 };
1628
1631
  for (const candidate of (0, mutation_log_1.listBlueBubblesRecoveryCandidates)(agentName)) {
1629
1632
  if ((0, processed_log_1.hasProcessedBlueBubblesMessage)(agentName, candidate.sessionKey, candidate.messageGuid)
1633
+ || (0, processed_log_1.hasProcessedBlueBubblesMessageGuid)(agentName, candidate.messageGuid)
1630
1634
  || isBlueBubblesMessageInFlight(candidate.sessionKey, candidate.messageGuid)) {
1631
1635
  result.skipped++;
1632
1636
  continue;
@@ -35,6 +35,7 @@ var __importStar = (this && this.__importStar) || (function () {
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.getBlueBubblesProcessedLogPath = getBlueBubblesProcessedLogPath;
37
37
  exports.hasProcessedBlueBubblesMessage = hasProcessedBlueBubblesMessage;
38
+ exports.hasProcessedBlueBubblesMessageGuid = hasProcessedBlueBubblesMessageGuid;
38
39
  exports.recordProcessedBlueBubblesMessage = recordProcessedBlueBubblesMessage;
39
40
  const fs = __importStar(require("node:fs"));
40
41
  const path = __importStar(require("node:path"));
@@ -58,12 +59,29 @@ function readEntries(filePath) {
58
59
  return [];
59
60
  }
60
61
  }
62
+ function readAllEntries(agentName) {
63
+ const processedDir = path.join((0, identity_1.getAgentRoot)(agentName), "state", "senses", "bluebubbles", "processed");
64
+ try {
65
+ return fs.readdirSync(processedDir)
66
+ .filter((name) => name.endsWith(".ndjson"))
67
+ .sort()
68
+ .flatMap((name) => readEntries(path.join(processedDir, name)));
69
+ }
70
+ catch {
71
+ return [];
72
+ }
73
+ }
61
74
  function hasProcessedBlueBubblesMessage(agentName, sessionKey, messageGuid) {
62
75
  if (!messageGuid.trim())
63
76
  return false;
64
77
  const filePath = getBlueBubblesProcessedLogPath(agentName, sessionKey);
65
78
  return readEntries(filePath).some((entry) => entry.messageGuid === messageGuid);
66
79
  }
80
+ function hasProcessedBlueBubblesMessageGuid(agentName, messageGuid) {
81
+ if (!messageGuid.trim())
82
+ return false;
83
+ return readAllEntries(agentName).some((entry) => entry.messageGuid === messageGuid);
84
+ }
67
85
  function recordProcessedBlueBubblesMessage(agentName, event, source, outcome) {
68
86
  const filePath = getBlueBubblesProcessedLogPath(agentName, event.chat.sessionKey);
69
87
  try {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ouro.bot/cli",
3
- "version": "0.1.0-alpha.540",
3
+ "version": "0.1.0-alpha.541",
4
4
  "main": "dist/heart/daemon/ouro-entry.js",
5
5
  "bin": {
6
6
  "cli": "dist/heart/daemon/ouro-bot-entry.js",