@ouro.bot/cli 0.1.0-alpha.9 → 0.1.0-alpha.90

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.
Files changed (128) hide show
  1. package/AdoptionSpecialist.ouro/agent.json +70 -9
  2. package/AdoptionSpecialist.ouro/psyche/SOUL.md +5 -2
  3. package/AdoptionSpecialist.ouro/psyche/identities/monty.md +2 -2
  4. package/README.md +147 -205
  5. package/assets/ouroboros.png +0 -0
  6. package/changelog.json +529 -0
  7. package/dist/heart/active-work.js +251 -0
  8. package/dist/heart/bridges/manager.js +358 -0
  9. package/dist/heart/bridges/state-machine.js +135 -0
  10. package/dist/heart/bridges/store.js +123 -0
  11. package/dist/heart/commitments.js +109 -0
  12. package/dist/heart/config.js +68 -23
  13. package/dist/heart/core.js +452 -93
  14. package/dist/heart/cross-chat-delivery.js +146 -0
  15. package/dist/heart/daemon/agent-discovery.js +81 -0
  16. package/dist/heart/daemon/auth-flow.js +430 -0
  17. package/dist/heart/daemon/daemon-cli.js +1737 -269
  18. package/dist/heart/daemon/daemon-entry.js +55 -6
  19. package/dist/heart/daemon/daemon-runtime-sync.js +212 -0
  20. package/dist/heart/daemon/daemon.js +216 -10
  21. package/dist/heart/daemon/hatch-animation.js +10 -3
  22. package/dist/heart/daemon/hatch-flow.js +7 -82
  23. package/dist/heart/daemon/hooks/bundle-meta.js +92 -0
  24. package/dist/heart/daemon/launchd.js +159 -0
  25. package/dist/heart/daemon/log-tailer.js +4 -3
  26. package/dist/heart/daemon/message-router.js +17 -8
  27. package/dist/heart/daemon/ouro-bot-entry.js +0 -0
  28. package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
  29. package/dist/heart/daemon/ouro-entry.js +0 -0
  30. package/dist/heart/daemon/ouro-path-installer.js +260 -0
  31. package/dist/heart/daemon/ouro-uti.js +11 -2
  32. package/dist/heart/daemon/ouro-version-manager.js +171 -0
  33. package/dist/heart/daemon/process-manager.js +14 -1
  34. package/dist/heart/daemon/run-hooks.js +37 -0
  35. package/dist/heart/daemon/runtime-logging.js +58 -15
  36. package/dist/heart/daemon/runtime-metadata.js +219 -0
  37. package/dist/heart/daemon/runtime-mode.js +67 -0
  38. package/dist/heart/daemon/sense-manager.js +307 -0
  39. package/dist/heart/daemon/skill-management-installer.js +94 -0
  40. package/dist/heart/daemon/socket-client.js +202 -0
  41. package/dist/heart/daemon/specialist-orchestrator.js +53 -84
  42. package/dist/heart/daemon/specialist-prompt.js +63 -11
  43. package/dist/heart/daemon/specialist-tools.js +211 -60
  44. package/dist/heart/daemon/staged-restart.js +114 -0
  45. package/dist/heart/daemon/thoughts.js +507 -0
  46. package/dist/heart/daemon/update-checker.js +111 -0
  47. package/dist/heart/daemon/update-hooks.js +138 -0
  48. package/dist/heart/daemon/wrapper-publish-guard.js +86 -0
  49. package/dist/heart/delegation.js +62 -0
  50. package/dist/heart/identity.js +126 -21
  51. package/dist/heart/kicks.js +1 -19
  52. package/dist/heart/model-capabilities.js +48 -0
  53. package/dist/heart/obligations.js +191 -0
  54. package/dist/heart/progress-story.js +42 -0
  55. package/dist/heart/providers/anthropic.js +74 -9
  56. package/dist/heart/providers/azure.js +86 -7
  57. package/dist/heart/providers/github-copilot.js +149 -0
  58. package/dist/heart/providers/minimax.js +4 -0
  59. package/dist/heart/providers/openai-codex.js +12 -3
  60. package/dist/heart/safe-workspace.js +362 -0
  61. package/dist/heart/sense-truth.js +61 -0
  62. package/dist/heart/session-activity.js +169 -0
  63. package/dist/heart/session-recall.js +116 -0
  64. package/dist/heart/streaming.js +100 -22
  65. package/dist/heart/target-resolution.js +123 -0
  66. package/dist/heart/turn-coordinator.js +28 -0
  67. package/dist/mind/associative-recall.js +14 -2
  68. package/dist/mind/bundle-manifest.js +70 -0
  69. package/dist/mind/context.js +57 -11
  70. package/dist/mind/first-impressions.js +16 -2
  71. package/dist/mind/friends/channel.js +35 -0
  72. package/dist/mind/friends/group-context.js +144 -0
  73. package/dist/mind/friends/store-file.js +19 -0
  74. package/dist/mind/friends/trust-explanation.js +74 -0
  75. package/dist/mind/friends/types.js +8 -0
  76. package/dist/mind/memory.js +27 -26
  77. package/dist/mind/obligation-steering.js +31 -0
  78. package/dist/mind/pending.js +76 -9
  79. package/dist/mind/phrases.js +1 -0
  80. package/dist/mind/prompt.js +467 -77
  81. package/dist/mind/token-estimate.js +8 -12
  82. package/dist/nerves/cli-logging.js +15 -2
  83. package/dist/nerves/coverage/run-artifacts.js +1 -1
  84. package/dist/nerves/index.js +12 -0
  85. package/dist/repertoire/ado-client.js +4 -2
  86. package/dist/repertoire/coding/feedback.js +180 -0
  87. package/dist/repertoire/coding/index.js +4 -1
  88. package/dist/repertoire/coding/manager.js +69 -4
  89. package/dist/repertoire/coding/spawner.js +21 -3
  90. package/dist/repertoire/coding/tools.js +105 -2
  91. package/dist/repertoire/data/ado-endpoints.json +188 -0
  92. package/dist/repertoire/guardrails.js +290 -0
  93. package/dist/repertoire/mcp-client.js +254 -0
  94. package/dist/repertoire/mcp-manager.js +195 -0
  95. package/dist/repertoire/skills.js +3 -26
  96. package/dist/repertoire/tasks/board.js +12 -0
  97. package/dist/repertoire/tasks/index.js +23 -9
  98. package/dist/repertoire/tasks/transitions.js +1 -2
  99. package/dist/repertoire/tools-base.js +714 -249
  100. package/dist/repertoire/tools-bluebubbles.js +93 -0
  101. package/dist/repertoire/tools-teams.js +58 -25
  102. package/dist/repertoire/tools.js +106 -53
  103. package/dist/senses/bluebubbles-client.js +210 -5
  104. package/dist/senses/bluebubbles-entry.js +2 -0
  105. package/dist/senses/bluebubbles-inbound-log.js +109 -0
  106. package/dist/senses/bluebubbles-media.js +339 -0
  107. package/dist/senses/bluebubbles-model.js +12 -4
  108. package/dist/senses/bluebubbles-mutation-log.js +45 -5
  109. package/dist/senses/bluebubbles-runtime-state.js +109 -0
  110. package/dist/senses/bluebubbles-session-cleanup.js +72 -0
  111. package/dist/senses/bluebubbles.js +894 -45
  112. package/dist/senses/cli-layout.js +187 -0
  113. package/dist/senses/cli.js +400 -164
  114. package/dist/senses/continuity.js +94 -0
  115. package/dist/senses/debug-activity.js +154 -0
  116. package/dist/senses/inner-dialog-worker.js +47 -18
  117. package/dist/senses/inner-dialog.js +377 -83
  118. package/dist/senses/pipeline.js +307 -0
  119. package/dist/senses/teams.js +573 -129
  120. package/dist/senses/trust-gate.js +112 -2
  121. package/package.json +14 -3
  122. package/subagents/README.md +4 -70
  123. package/dist/heart/daemon/specialist-session.js +0 -142
  124. package/dist/heart/daemon/subagent-installer.js +0 -125
  125. package/dist/inner-worker-entry.js +0 -4
  126. package/subagents/work-doer.md +0 -233
  127. package/subagents/work-merger.md +0 -624
  128. package/subagents/work-planner.md +0 -373
@@ -3,8 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createBlueBubblesClient = createBlueBubblesClient;
4
4
  const node_crypto_1 = require("node:crypto");
5
5
  const config_1 = require("../heart/config");
6
+ const identity_1 = require("../heart/identity");
6
7
  const runtime_1 = require("../nerves/runtime");
7
8
  const bluebubbles_model_1 = require("./bluebubbles-model");
9
+ const bluebubbles_media_1 = require("./bluebubbles-media");
8
10
  function buildBlueBubblesApiUrl(baseUrl, endpoint, password) {
9
11
  const root = baseUrl.endsWith("/") ? baseUrl : `${baseUrl}/`;
10
12
  const url = new URL(endpoint.replace(/^\//, ""), root);
@@ -16,6 +18,10 @@ function asRecord(value) {
16
18
  ? value
17
19
  : null;
18
20
  }
21
+ function readString(record, key) {
22
+ const value = record[key];
23
+ return typeof value === "string" ? value : undefined;
24
+ }
19
25
  function extractMessageGuid(payload) {
20
26
  if (!payload || typeof payload !== "object")
21
27
  return undefined;
@@ -55,6 +61,75 @@ function buildRepairUrl(baseUrl, messageGuid, password) {
55
61
  parsed.searchParams.set("with", "attachments,payloadData,chats,messageSummaryInfo");
56
62
  return parsed.toString();
57
63
  }
64
+ function extractChatIdentifierFromGuid(chatGuid) {
65
+ const parts = chatGuid.split(";");
66
+ return parts.length >= 3 ? parts[2]?.trim() || undefined : undefined;
67
+ }
68
+ function extractChatGuid(value) {
69
+ const record = asRecord(value);
70
+ const candidates = [
71
+ record?.chatGuid,
72
+ record?.guid,
73
+ record?.chat_guid,
74
+ record?.identifier,
75
+ record?.chatIdentifier,
76
+ record?.chat_identifier,
77
+ ];
78
+ for (const candidate of candidates) {
79
+ if (typeof candidate === "string" && candidate.trim()) {
80
+ return candidate.trim();
81
+ }
82
+ }
83
+ return undefined;
84
+ }
85
+ function extractQueriedChatIdentifier(chat, chatGuid) {
86
+ const explicitIdentifier = readString(chat, "chatIdentifier")
87
+ ?? readString(chat, "identifier")
88
+ ?? readString(chat, "chat_identifier");
89
+ if (explicitIdentifier) {
90
+ return explicitIdentifier;
91
+ }
92
+ return extractChatIdentifierFromGuid(chatGuid);
93
+ }
94
+ function extractChatQueryRows(payload) {
95
+ const record = asRecord(payload);
96
+ const data = Array.isArray(record?.data) ? record.data : payload;
97
+ if (!Array.isArray(data)) {
98
+ return [];
99
+ }
100
+ return data.map((entry) => asRecord(entry)).filter((entry) => entry !== null);
101
+ }
102
+ async function resolveChatGuidForIdentifier(config, channelConfig, chatIdentifier) {
103
+ const trimmedIdentifier = chatIdentifier.trim();
104
+ if (!trimmedIdentifier)
105
+ return undefined;
106
+ const url = buildBlueBubblesApiUrl(config.serverUrl, "/api/v1/chat/query", config.password);
107
+ const response = await fetch(url, {
108
+ method: "POST",
109
+ headers: { "Content-Type": "application/json" },
110
+ body: JSON.stringify({
111
+ limit: 500,
112
+ offset: 0,
113
+ with: ["participants"],
114
+ }),
115
+ signal: AbortSignal.timeout(channelConfig.requestTimeoutMs),
116
+ });
117
+ if (!response.ok) {
118
+ return undefined;
119
+ }
120
+ const payload = await parseJsonBody(response);
121
+ const rows = extractChatQueryRows(payload);
122
+ for (const row of rows) {
123
+ const guid = extractChatGuid(row);
124
+ if (!guid)
125
+ continue;
126
+ const identifier = extractQueriedChatIdentifier(row, guid);
127
+ if (identifier === trimmedIdentifier || guid === trimmedIdentifier) {
128
+ return guid;
129
+ }
130
+ }
131
+ return undefined;
132
+ }
58
133
  function collectPreviewStrings(value, out, depth = 0) {
59
134
  if (depth > 4 || out.length >= 4)
60
135
  return;
@@ -95,6 +170,12 @@ function applyRepairNotice(event, notice) {
95
170
  repairNotice: notice,
96
171
  };
97
172
  }
173
+ function hasRecoverableMessageContent(event) {
174
+ return event.kind === "message"
175
+ && (event.textForAgent.trim().length > 0
176
+ || event.attachments.length > 0
177
+ || event.hasPayloadData);
178
+ }
98
179
  function hydrateTextForAgent(event, rawData) {
99
180
  if (event.kind !== "message") {
100
181
  return { ...event, requiresRepair: false };
@@ -120,6 +201,14 @@ function extractRepairData(payload) {
120
201
  const record = asRecord(payload);
121
202
  return asRecord(record?.data) ?? record;
122
203
  }
204
+ function providerSupportsAudioInput(provider) {
205
+ void provider;
206
+ return false;
207
+ }
208
+ async function resolveChatGuid(chat, config, channelConfig) {
209
+ return chat.chatGuid
210
+ ?? await resolveChatGuidForIdentifier(config, channelConfig, chat.chatIdentifier ?? "");
211
+ }
123
212
  function createBlueBubblesClient(config = (0, config_1.getBlueBubblesConfig)(), channelConfig = (0, config_1.getBlueBubblesChannelConfig)()) {
124
213
  return {
125
214
  async sendText(params) {
@@ -127,12 +216,13 @@ function createBlueBubblesClient(config = (0, config_1.getBlueBubblesConfig)(),
127
216
  if (!trimmedText) {
128
217
  throw new Error("BlueBubbles send requires non-empty text.");
129
218
  }
130
- if (!params.chat.chatGuid) {
219
+ const resolvedChatGuid = await resolveChatGuid(params.chat, config, channelConfig);
220
+ if (!resolvedChatGuid) {
131
221
  throw new Error("BlueBubbles send currently requires chat.chatGuid from the inbound event.");
132
222
  }
133
223
  const url = buildBlueBubblesApiUrl(config.serverUrl, "/api/v1/message/text", config.password);
134
224
  const body = {
135
- chatGuid: params.chat.chatGuid,
225
+ chatGuid: resolvedChatGuid,
136
226
  tempGuid: (0, node_crypto_1.randomUUID)(),
137
227
  message: trimmedText,
138
228
  };
@@ -146,7 +236,7 @@ function createBlueBubblesClient(config = (0, config_1.getBlueBubblesConfig)(),
146
236
  event: "senses.bluebubbles_send_start",
147
237
  message: "sending bluebubbles message",
148
238
  meta: {
149
- chatGuid: params.chat.chatGuid,
239
+ chatGuid: resolvedChatGuid,
150
240
  hasReplyTarget: Boolean(params.replyToMessageGuid?.trim()),
151
241
  },
152
242
  });
@@ -177,12 +267,102 @@ function createBlueBubblesClient(config = (0, config_1.getBlueBubblesConfig)(),
177
267
  event: "senses.bluebubbles_send_end",
178
268
  message: "bluebubbles message sent",
179
269
  meta: {
180
- chatGuid: params.chat.chatGuid,
270
+ chatGuid: resolvedChatGuid,
181
271
  messageGuid: messageGuid ?? null,
182
272
  },
183
273
  });
184
274
  return { messageGuid };
185
275
  },
276
+ async editMessage(params) {
277
+ const messageGuid = params.messageGuid.trim();
278
+ const text = params.text.trim();
279
+ if (!messageGuid) {
280
+ throw new Error("BlueBubbles edit requires messageGuid.");
281
+ }
282
+ if (!text) {
283
+ throw new Error("BlueBubbles edit requires non-empty text.");
284
+ }
285
+ const editTimeoutMs = Math.max(channelConfig.requestTimeoutMs, 120000);
286
+ const url = buildBlueBubblesApiUrl(config.serverUrl, `/api/v1/message/${encodeURIComponent(messageGuid)}/edit`, config.password);
287
+ const response = await fetch(url, {
288
+ method: "POST",
289
+ headers: { "Content-Type": "application/json" },
290
+ body: JSON.stringify({
291
+ editedMessage: text,
292
+ backwardsCompatibilityMessage: params.backwardsCompatibilityMessage ?? `Edited to: ${text}`,
293
+ partIndex: typeof params.partIndex === "number" ? params.partIndex : 0,
294
+ }),
295
+ signal: AbortSignal.timeout(editTimeoutMs),
296
+ });
297
+ if (!response.ok) {
298
+ const errorText = await response.text().catch(() => "");
299
+ throw new Error(`BlueBubbles edit failed (${response.status}): ${errorText || "unknown"}`);
300
+ }
301
+ },
302
+ async setTyping(chat, typing) {
303
+ const resolvedChatGuid = await resolveChatGuid(chat, config, channelConfig);
304
+ if (!resolvedChatGuid) {
305
+ return;
306
+ }
307
+ const url = buildBlueBubblesApiUrl(config.serverUrl, `/api/v1/chat/${encodeURIComponent(resolvedChatGuid)}/typing`, config.password);
308
+ const response = await fetch(url, {
309
+ method: typing ? "POST" : "DELETE",
310
+ signal: AbortSignal.timeout(channelConfig.requestTimeoutMs),
311
+ });
312
+ if (!response.ok) {
313
+ const errorText = await response.text().catch(() => "");
314
+ throw new Error(`BlueBubbles typing failed (${response.status}): ${errorText || "unknown"}`);
315
+ }
316
+ },
317
+ async markChatRead(chat) {
318
+ const resolvedChatGuid = await resolveChatGuid(chat, config, channelConfig);
319
+ if (!resolvedChatGuid) {
320
+ return;
321
+ }
322
+ const url = buildBlueBubblesApiUrl(config.serverUrl, `/api/v1/chat/${encodeURIComponent(resolvedChatGuid)}/read`, config.password);
323
+ const response = await fetch(url, {
324
+ method: "POST",
325
+ signal: AbortSignal.timeout(channelConfig.requestTimeoutMs),
326
+ });
327
+ if (!response.ok) {
328
+ const errorText = await response.text().catch(() => "");
329
+ throw new Error(`BlueBubbles read failed (${response.status}): ${errorText || "unknown"}`);
330
+ }
331
+ },
332
+ async checkHealth() {
333
+ const url = buildBlueBubblesApiUrl(config.serverUrl, "/api/v1/message/count", config.password);
334
+ (0, runtime_1.emitNervesEvent)({
335
+ component: "senses",
336
+ event: "senses.bluebubbles_healthcheck_start",
337
+ message: "probing bluebubbles upstream health",
338
+ meta: { serverUrl: config.serverUrl },
339
+ });
340
+ const response = await fetch(url, {
341
+ method: "GET",
342
+ signal: AbortSignal.timeout(channelConfig.requestTimeoutMs),
343
+ });
344
+ if (!response.ok) {
345
+ const errorText = await response.text().catch(() => "");
346
+ (0, runtime_1.emitNervesEvent)({
347
+ level: "warn",
348
+ component: "senses",
349
+ event: "senses.bluebubbles_healthcheck_error",
350
+ message: "bluebubbles upstream health probe failed",
351
+ meta: {
352
+ serverUrl: config.serverUrl,
353
+ status: response.status,
354
+ reason: errorText || "unknown",
355
+ },
356
+ });
357
+ throw new Error(`BlueBubbles upstream health check failed (${response.status}): ${errorText || "unknown"}`);
358
+ }
359
+ (0, runtime_1.emitNervesEvent)({
360
+ component: "senses",
361
+ event: "senses.bluebubbles_healthcheck_end",
362
+ message: "bluebubbles upstream health probe succeeded",
363
+ meta: { serverUrl: config.serverUrl },
364
+ });
365
+ },
186
366
  async repairEvent(event) {
187
367
  if (!event.requiresRepair) {
188
368
  (0, runtime_1.emitNervesEvent)({
@@ -247,7 +427,31 @@ function createBlueBubblesClient(config = (0, config_1.getBlueBubblesConfig)(),
247
427
  type: event.eventType,
248
428
  data,
249
429
  });
250
- const hydrated = hydrateTextForAgent(normalized, data);
430
+ const recoveredMessage = event.kind === "mutation"
431
+ && !event.shouldNotifyAgent
432
+ ? (0, bluebubbles_model_1.normalizeBlueBubblesEvent)({
433
+ type: "new-message",
434
+ data,
435
+ })
436
+ : null;
437
+ let hydrated = recoveredMessage && hasRecoverableMessageContent(recoveredMessage)
438
+ ? hydrateTextForAgent(recoveredMessage, data)
439
+ : hydrateTextForAgent(normalized, data);
440
+ if (hydrated.kind === "message" &&
441
+ hydrated.balloonBundleId !== "com.apple.messages.URLBalloonProvider" &&
442
+ hydrated.attachments.length > 0) {
443
+ const media = await (0, bluebubbles_media_1.hydrateBlueBubblesAttachments)(hydrated.attachments, config, channelConfig, {
444
+ preferAudioInput: providerSupportsAudioInput((0, identity_1.loadAgentConfig)().provider),
445
+ });
446
+ const transcriptSuffix = media.transcriptAdditions.map((entry) => `[${entry}]`).join("\n");
447
+ const noticeSuffix = media.notices.map((entry) => `[${entry}]`).join("\n");
448
+ const combinedSuffix = [transcriptSuffix, noticeSuffix].filter(Boolean).join("\n");
449
+ hydrated = {
450
+ ...hydrated,
451
+ inputPartsForAgent: media.inputParts.length > 0 ? media.inputParts : undefined,
452
+ textForAgent: [hydrated.textForAgent, combinedSuffix].filter(Boolean).join("\n"),
453
+ };
454
+ }
251
455
  (0, runtime_1.emitNervesEvent)({
252
456
  component: "senses",
253
457
  event: "senses.bluebubbles_repair_end",
@@ -256,6 +460,7 @@ function createBlueBubblesClient(config = (0, config_1.getBlueBubblesConfig)(),
256
460
  kind: hydrated.kind,
257
461
  messageGuid: hydrated.messageGuid,
258
462
  repairedFrom: event.kind,
463
+ promotedFromMutation: event.kind === "mutation" && hydrated.kind === "message",
259
464
  },
260
465
  });
261
466
  return hydrated;
@@ -8,4 +8,6 @@ if (!process.argv.includes("--agent")) {
8
8
  process.exit(1);
9
9
  }
10
10
  const bluebubbles_1 = require("./bluebubbles");
11
+ const runtime_logging_1 = require("../heart/daemon/runtime-logging");
12
+ (0, runtime_logging_1.configureDaemonRuntimeLogger)("bluebubbles");
11
13
  (0, bluebubbles_1.startBlueBubblesApp)();
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.getBlueBubblesInboundLogPath = getBlueBubblesInboundLogPath;
37
+ exports.hasRecordedBlueBubblesInbound = hasRecordedBlueBubblesInbound;
38
+ exports.recordBlueBubblesInbound = recordBlueBubblesInbound;
39
+ const fs = __importStar(require("node:fs"));
40
+ const path = __importStar(require("node:path"));
41
+ const config_1 = require("../heart/config");
42
+ const identity_1 = require("../heart/identity");
43
+ const runtime_1 = require("../nerves/runtime");
44
+ function getBlueBubblesInboundLogPath(agentName, sessionKey) {
45
+ return path.join((0, identity_1.getAgentRoot)(agentName), "state", "senses", "bluebubbles", "inbound", `${(0, config_1.sanitizeKey)(sessionKey)}.ndjson`);
46
+ }
47
+ function readEntries(filePath) {
48
+ try {
49
+ const raw = fs.readFileSync(filePath, "utf-8");
50
+ return raw
51
+ .split("\n")
52
+ .map((line) => line.trim())
53
+ .filter(Boolean)
54
+ .map((line) => JSON.parse(line))
55
+ .filter((entry) => typeof entry.messageGuid === "string" && typeof entry.sessionKey === "string");
56
+ }
57
+ catch {
58
+ return [];
59
+ }
60
+ }
61
+ function hasRecordedBlueBubblesInbound(agentName, sessionKey, messageGuid) {
62
+ if (!messageGuid.trim())
63
+ return false;
64
+ const filePath = getBlueBubblesInboundLogPath(agentName, sessionKey);
65
+ return readEntries(filePath).some((entry) => entry.messageGuid === messageGuid);
66
+ }
67
+ function recordBlueBubblesInbound(agentName, event, source) {
68
+ const filePath = getBlueBubblesInboundLogPath(agentName, event.chat.sessionKey);
69
+ try {
70
+ fs.mkdirSync(path.dirname(filePath), { recursive: true });
71
+ fs.appendFileSync(filePath, JSON.stringify({
72
+ recordedAt: new Date(event.timestamp).toISOString(),
73
+ messageGuid: event.messageGuid,
74
+ chatGuid: event.chat.chatGuid ?? null,
75
+ chatIdentifier: event.chat.chatIdentifier ?? null,
76
+ sessionKey: event.chat.sessionKey,
77
+ textForAgent: event.textForAgent,
78
+ source,
79
+ }) + "\n", "utf-8");
80
+ }
81
+ catch (error) {
82
+ (0, runtime_1.emitNervesEvent)({
83
+ level: "warn",
84
+ component: "senses",
85
+ event: "senses.bluebubbles_inbound_log_error",
86
+ message: "failed to record bluebubbles inbound sidecar log",
87
+ meta: {
88
+ agentName,
89
+ messageGuid: event.messageGuid,
90
+ sessionKey: event.chat.sessionKey,
91
+ reason: error instanceof Error ? error.message : String(error),
92
+ },
93
+ });
94
+ return filePath;
95
+ }
96
+ (0, runtime_1.emitNervesEvent)({
97
+ component: "senses",
98
+ event: "senses.bluebubbles_inbound_logged",
99
+ message: "recorded bluebubbles inbound message to sidecar log",
100
+ meta: {
101
+ agentName,
102
+ messageGuid: event.messageGuid,
103
+ sessionKey: event.chat.sessionKey,
104
+ source,
105
+ path: filePath,
106
+ },
107
+ });
108
+ return filePath;
109
+ }