@ouro.bot/cli 0.1.0-alpha.9 → 0.1.0-alpha.91
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/AdoptionSpecialist.ouro/agent.json +70 -9
- package/AdoptionSpecialist.ouro/psyche/SOUL.md +5 -2
- package/AdoptionSpecialist.ouro/psyche/identities/monty.md +2 -2
- package/README.md +147 -205
- package/assets/ouroboros.png +0 -0
- package/changelog.json +536 -0
- package/dist/heart/active-work.js +251 -0
- package/dist/heart/bridges/manager.js +358 -0
- package/dist/heart/bridges/state-machine.js +135 -0
- package/dist/heart/bridges/store.js +123 -0
- package/dist/heart/commitments.js +109 -0
- package/dist/heart/config.js +68 -23
- package/dist/heart/core.js +452 -93
- package/dist/heart/cross-chat-delivery.js +146 -0
- package/dist/heart/daemon/agent-discovery.js +81 -0
- package/dist/heart/daemon/auth-flow.js +430 -0
- package/dist/heart/daemon/daemon-cli.js +1738 -269
- package/dist/heart/daemon/daemon-entry.js +55 -6
- package/dist/heart/daemon/daemon-runtime-sync.js +212 -0
- package/dist/heart/daemon/daemon.js +216 -10
- package/dist/heart/daemon/hatch-animation.js +10 -3
- package/dist/heart/daemon/hatch-flow.js +7 -82
- package/dist/heart/daemon/hooks/bundle-meta.js +92 -0
- package/dist/heart/daemon/launchd.js +159 -0
- package/dist/heart/daemon/log-tailer.js +4 -3
- package/dist/heart/daemon/message-router.js +17 -8
- package/dist/heart/daemon/ouro-bot-entry.js +0 -0
- package/dist/heart/daemon/ouro-bot-global-installer.js +128 -0
- package/dist/heart/daemon/ouro-entry.js +0 -0
- package/dist/heart/daemon/ouro-path-installer.js +260 -0
- package/dist/heart/daemon/ouro-uti.js +11 -2
- package/dist/heart/daemon/ouro-version-manager.js +171 -0
- package/dist/heart/daemon/process-manager.js +14 -1
- package/dist/heart/daemon/run-hooks.js +37 -0
- package/dist/heart/daemon/runtime-logging.js +58 -15
- package/dist/heart/daemon/runtime-metadata.js +219 -0
- package/dist/heart/daemon/runtime-mode.js +67 -0
- package/dist/heart/daemon/sense-manager.js +307 -0
- package/dist/heart/daemon/skill-management-installer.js +94 -0
- package/dist/heart/daemon/socket-client.js +202 -0
- package/dist/heart/daemon/specialist-orchestrator.js +53 -84
- package/dist/heart/daemon/specialist-prompt.js +63 -11
- package/dist/heart/daemon/specialist-tools.js +211 -60
- package/dist/heart/daemon/staged-restart.js +114 -0
- package/dist/heart/daemon/thoughts.js +507 -0
- package/dist/heart/daemon/update-checker.js +111 -0
- package/dist/heart/daemon/update-hooks.js +138 -0
- package/dist/heart/daemon/wrapper-publish-guard.js +86 -0
- package/dist/heart/delegation.js +62 -0
- package/dist/heart/identity.js +126 -21
- package/dist/heart/kicks.js +1 -19
- package/dist/heart/model-capabilities.js +48 -0
- package/dist/heart/obligations.js +191 -0
- package/dist/heart/progress-story.js +42 -0
- package/dist/heart/providers/anthropic.js +74 -9
- package/dist/heart/providers/azure.js +86 -7
- package/dist/heart/providers/github-copilot.js +149 -0
- package/dist/heart/providers/minimax.js +4 -0
- package/dist/heart/providers/openai-codex.js +12 -3
- package/dist/heart/safe-workspace.js +362 -0
- package/dist/heart/sense-truth.js +61 -0
- package/dist/heart/session-activity.js +169 -0
- package/dist/heart/session-recall.js +116 -0
- package/dist/heart/streaming.js +100 -22
- package/dist/heart/target-resolution.js +123 -0
- package/dist/heart/turn-coordinator.js +28 -0
- package/dist/mind/associative-recall.js +14 -2
- package/dist/mind/bundle-manifest.js +70 -0
- package/dist/mind/context.js +57 -11
- package/dist/mind/first-impressions.js +16 -2
- package/dist/mind/friends/channel.js +35 -0
- package/dist/mind/friends/group-context.js +144 -0
- package/dist/mind/friends/store-file.js +19 -0
- package/dist/mind/friends/trust-explanation.js +74 -0
- package/dist/mind/friends/types.js +8 -0
- package/dist/mind/memory.js +27 -26
- package/dist/mind/obligation-steering.js +31 -0
- package/dist/mind/pending.js +76 -9
- package/dist/mind/phrases.js +1 -0
- package/dist/mind/prompt.js +467 -77
- package/dist/mind/token-estimate.js +8 -12
- package/dist/nerves/cli-logging.js +15 -2
- package/dist/nerves/coverage/run-artifacts.js +1 -1
- package/dist/nerves/index.js +12 -0
- package/dist/repertoire/ado-client.js +4 -2
- package/dist/repertoire/coding/feedback.js +180 -0
- package/dist/repertoire/coding/index.js +4 -1
- package/dist/repertoire/coding/manager.js +69 -4
- package/dist/repertoire/coding/spawner.js +21 -3
- package/dist/repertoire/coding/tools.js +105 -2
- package/dist/repertoire/data/ado-endpoints.json +188 -0
- package/dist/repertoire/guardrails.js +290 -0
- package/dist/repertoire/mcp-client.js +254 -0
- package/dist/repertoire/mcp-manager.js +195 -0
- package/dist/repertoire/skills.js +3 -26
- package/dist/repertoire/tasks/board.js +12 -0
- package/dist/repertoire/tasks/index.js +23 -9
- package/dist/repertoire/tasks/transitions.js +1 -2
- package/dist/repertoire/tools-base.js +714 -249
- package/dist/repertoire/tools-bluebubbles.js +93 -0
- package/dist/repertoire/tools-teams.js +58 -25
- package/dist/repertoire/tools.js +106 -53
- package/dist/senses/bluebubbles-client.js +210 -5
- package/dist/senses/bluebubbles-entry.js +2 -0
- package/dist/senses/bluebubbles-inbound-log.js +109 -0
- package/dist/senses/bluebubbles-media.js +339 -0
- package/dist/senses/bluebubbles-model.js +12 -4
- package/dist/senses/bluebubbles-mutation-log.js +45 -5
- package/dist/senses/bluebubbles-runtime-state.js +109 -0
- package/dist/senses/bluebubbles-session-cleanup.js +72 -0
- package/dist/senses/bluebubbles.js +894 -45
- package/dist/senses/cli-layout.js +187 -0
- package/dist/senses/cli.js +400 -164
- package/dist/senses/continuity.js +94 -0
- package/dist/senses/debug-activity.js +154 -0
- package/dist/senses/inner-dialog-worker.js +47 -18
- package/dist/senses/inner-dialog.js +377 -83
- package/dist/senses/pipeline.js +307 -0
- package/dist/senses/teams.js +573 -129
- package/dist/senses/trust-gate.js +112 -2
- package/package.json +14 -3
- package/subagents/README.md +4 -70
- package/dist/heart/daemon/specialist-session.js +0 -142
- package/dist/heart/daemon/subagent-installer.js +0 -125
- package/dist/inner-worker-entry.js +0 -4
- package/subagents/work-doer.md +0 -233
- package/subagents/work-merger.md +0 -624
- 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
|
-
|
|
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:
|
|
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:
|
|
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:
|
|
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
|
|
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
|
+
}
|