@ouro.bot/cli 0.1.0-alpha.726 → 0.1.0-alpha.728
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/README.md +14 -1
- package/assets/bluebubbles-host +264 -0
- package/changelog.json +18 -0
- package/dist/heart/config.js +1 -2
- package/dist/heart/core.js +181 -209
- package/dist/heart/daemon/bluebubbles-cli-integration.js +71 -0
- package/dist/heart/daemon/bluebubbles-host-protocol.js +433 -0
- package/dist/heart/daemon/bluebubbles-host.js +273 -0
- package/dist/heart/daemon/cli-defaults.js +8 -1
- package/dist/heart/daemon/cli-exec.js +239 -34
- package/dist/heart/daemon/cli-help.js +17 -6
- package/dist/heart/daemon/cli-parse.js +69 -1
- package/dist/heart/daemon/cli-render.js +7 -0
- package/dist/heart/daemon/daemon.js +79 -14
- package/dist/heart/daemon/doctor.js +21 -1
- package/dist/heart/daemon/mcp-canary.js +160 -29
- package/dist/heart/daemon/process-manager.js +100 -18
- package/dist/heart/daemon/socket-client.js +28 -19
- package/dist/heart/providers/anthropic.js +17 -12
- package/dist/heart/streaming.js +6 -6
- package/dist/heart/versioning/ouro-path-installer.js +30 -24
- package/dist/heart/versioning/ouro-recovery-launcher.js +76 -0
- package/dist/heart/versioning/version-intent.js +114 -0
- package/dist/mind/prompt-budget.js +104 -5
- package/dist/repertoire/tools.js +0 -10
- package/dist/senses/bluebubbles/client.js +43 -57
- package/dist/senses/bluebubbles/context-packet.js +104 -19
- package/dist/senses/bluebubbles/entry.js +14 -1
- package/dist/senses/bluebubbles/index.js +1398 -719
- package/dist/senses/bluebubbles/latest-turn.js +311 -0
- package/dist/senses/bluebubbles/outbound-state.js +4 -0
- package/dist/senses/bluebubbles/reaction-policy.js +4 -12
- package/dist/senses/bluebubbles/semantic-receipts.js +178 -10
- package/dist/senses/bluebubbles/webhook-registration.js +228 -0
- package/package.json +4 -2
|
@@ -118,6 +118,7 @@ function usage() {
|
|
|
118
118
|
" ouro link <agent> --friend <id> --provider <provider> --external-id <external-id>",
|
|
119
119
|
" ouro bluebubbles replay [--agent <name>] --message-guid <guid> [--event-type new-message|updated-message] [--json]",
|
|
120
120
|
" ouro bluebubbles context-smoke [--agent <name>] --message-guid <guid> [--persist] [--json]",
|
|
121
|
+
" ouro bluebubbles host <install|status|repair|remove|collect> [--username <name> --uid <uid> --home <path>] [--request-id <id>] [--json]",
|
|
121
122
|
" ouro rsvp <doctor|incident|cutover|legacy-render|replay|config|habit|import-legacy|refresh|compare|smoke> ...",
|
|
122
123
|
" ouro friend list [--agent <name>]",
|
|
123
124
|
" ouro friend show <id> [--agent <name>]",
|
|
@@ -1543,6 +1544,7 @@ function parseMcpCommand(args) {
|
|
|
1543
1544
|
if (sub === "doctor") {
|
|
1544
1545
|
let socketOverride;
|
|
1545
1546
|
let json = false;
|
|
1547
|
+
let hostStallObserved = false;
|
|
1546
1548
|
for (let i = 0; i < rest.length; i++) {
|
|
1547
1549
|
if (rest[i] === "--socket") {
|
|
1548
1550
|
if (!rest[i + 1])
|
|
@@ -1554,6 +1556,10 @@ function parseMcpCommand(args) {
|
|
|
1554
1556
|
json = true;
|
|
1555
1557
|
continue;
|
|
1556
1558
|
}
|
|
1559
|
+
if (rest[i] === "--host-stall-observed") {
|
|
1560
|
+
hostStallObserved = true;
|
|
1561
|
+
continue;
|
|
1562
|
+
}
|
|
1557
1563
|
throw new Error(`Unknown mcp doctor flag: ${rest[i]}`);
|
|
1558
1564
|
}
|
|
1559
1565
|
if (!agent)
|
|
@@ -1563,6 +1569,7 @@ function parseMcpCommand(args) {
|
|
|
1563
1569
|
agent,
|
|
1564
1570
|
...(socketOverride ? { socketOverride } : {}),
|
|
1565
1571
|
...(json ? { json: true } : {}),
|
|
1572
|
+
...(hostStallObserved ? { hostStallObserved: true } : {}),
|
|
1566
1573
|
};
|
|
1567
1574
|
}
|
|
1568
1575
|
throw new Error(`Usage\n${usage()}`);
|
|
@@ -1751,6 +1758,62 @@ function parseMigrateToDeskCommand(args) {
|
|
|
1751
1758
|
}
|
|
1752
1759
|
function parseBlueBubblesCommand(args) {
|
|
1753
1760
|
const subcommand = args[0];
|
|
1761
|
+
if (subcommand === "host") {
|
|
1762
|
+
const action = args[1];
|
|
1763
|
+
const usageText = "Usage: ouro bluebubbles host <install|status|repair|remove|collect> [--username <name> --uid <uid> --home <path>] [--request-id <id>] [--json]";
|
|
1764
|
+
if (action === "collect") {
|
|
1765
|
+
let requestId;
|
|
1766
|
+
let json = false;
|
|
1767
|
+
for (let index = 2; index < args.length; index += 1) {
|
|
1768
|
+
if (args[index] === "--request-id" && args[index + 1]) {
|
|
1769
|
+
requestId = args[++index];
|
|
1770
|
+
}
|
|
1771
|
+
else if (args[index] === "--json") {
|
|
1772
|
+
json = true;
|
|
1773
|
+
}
|
|
1774
|
+
else {
|
|
1775
|
+
throw new Error(usageText);
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
if (!requestId)
|
|
1779
|
+
throw new Error(`${usageText}\ncollect requires --request-id <id>`);
|
|
1780
|
+
return { kind: "bluebubbles.host.collect", requestId, ...(json ? { json: true } : {}) };
|
|
1781
|
+
}
|
|
1782
|
+
if (action !== "install" && action !== "status" && action !== "repair" && action !== "remove") {
|
|
1783
|
+
throw new Error(usageText);
|
|
1784
|
+
}
|
|
1785
|
+
let username;
|
|
1786
|
+
let uid;
|
|
1787
|
+
let homeDir;
|
|
1788
|
+
let json = false;
|
|
1789
|
+
for (let index = 2; index < args.length; index += 1) {
|
|
1790
|
+
const token = args[index];
|
|
1791
|
+
if (token === "--username" && args[index + 1])
|
|
1792
|
+
username = args[++index];
|
|
1793
|
+
else if (token === "--uid" && args[index + 1]) {
|
|
1794
|
+
const value = Number(args[++index]);
|
|
1795
|
+
if (!Number.isInteger(value))
|
|
1796
|
+
throw new Error(`${usageText}\n--uid must be an integer`);
|
|
1797
|
+
uid = value;
|
|
1798
|
+
}
|
|
1799
|
+
else if (token === "--home" && args[index + 1])
|
|
1800
|
+
homeDir = args[++index];
|
|
1801
|
+
else if (token === "--json")
|
|
1802
|
+
json = true;
|
|
1803
|
+
else
|
|
1804
|
+
throw new Error(usageText);
|
|
1805
|
+
}
|
|
1806
|
+
const targetFields = [username, uid, homeDir].filter((value) => value !== undefined).length;
|
|
1807
|
+
if (targetFields !== 0 && targetFields !== 3) {
|
|
1808
|
+
throw new Error(`${usageText}\ncross-user setup requires --username, --uid, and --home together`);
|
|
1809
|
+
}
|
|
1810
|
+
return {
|
|
1811
|
+
kind: "bluebubbles.host",
|
|
1812
|
+
action,
|
|
1813
|
+
...(targetFields === 3 ? { target: { username: username, uid: uid, homeDir: homeDir } } : {}),
|
|
1814
|
+
...(json ? { json: true } : {}),
|
|
1815
|
+
};
|
|
1816
|
+
}
|
|
1754
1817
|
if (subcommand !== "replay" && subcommand !== "context-smoke") {
|
|
1755
1818
|
throw new Error(`Usage\n${usage()}`);
|
|
1756
1819
|
}
|
|
@@ -2442,7 +2505,12 @@ function parseOuroCommand(args) {
|
|
|
2442
2505
|
}
|
|
2443
2506
|
if (head === "up") {
|
|
2444
2507
|
const noRepair = args.includes("--no-repair");
|
|
2445
|
-
|
|
2508
|
+
const latest = args.includes("--latest");
|
|
2509
|
+
return {
|
|
2510
|
+
kind: "daemon.up",
|
|
2511
|
+
...(noRepair ? { noRepair: true } : {}),
|
|
2512
|
+
...(latest ? { latest: true } : {}),
|
|
2513
|
+
};
|
|
2446
2514
|
}
|
|
2447
2515
|
if (head === "dev") {
|
|
2448
2516
|
const devArgs = args.slice(1);
|
|
@@ -48,6 +48,7 @@ exports.buildStoppedStatusPayload = buildStoppedStatusPayload;
|
|
|
48
48
|
exports.renderRollupStatusLine = renderRollupStatusLine;
|
|
49
49
|
exports.daemonUnavailableStatusOutput = daemonUnavailableStatusOutput;
|
|
50
50
|
exports.isDaemonUnavailableError = isDaemonUnavailableError;
|
|
51
|
+
exports.isDaemonTimeoutError = isDaemonTimeoutError;
|
|
51
52
|
exports.formatMcpResponse = formatMcpResponse;
|
|
52
53
|
const path = __importStar(require("path"));
|
|
53
54
|
const runtime_metadata_1 = require("./runtime-metadata");
|
|
@@ -746,6 +747,12 @@ function isDaemonUnavailableError(error) {
|
|
|
746
747
|
: "";
|
|
747
748
|
return code === "ENOENT" || code === "ECONNREFUSED";
|
|
748
749
|
}
|
|
750
|
+
function isDaemonTimeoutError(error) {
|
|
751
|
+
const code = typeof error === "object" && error !== null && "code" in error
|
|
752
|
+
? String(error.code ?? "")
|
|
753
|
+
: "";
|
|
754
|
+
return code === "ETIMEDOUT";
|
|
755
|
+
}
|
|
749
756
|
function formatMcpResponse(command, response) {
|
|
750
757
|
if (command.kind === "mcp.list") {
|
|
751
758
|
const allTools = response.data;
|
|
@@ -39,6 +39,8 @@ exports.parseOrphanPidsFromPs = parseOrphanPidsFromPs;
|
|
|
39
39
|
exports.filterPidfilePidsToActualOrphans = filterPidfilePidsToActualOrphans;
|
|
40
40
|
exports.mergeUniqueOrphanPids = mergeUniqueOrphanPids;
|
|
41
41
|
exports.waitForOrphanProcessesToSettle = waitForOrphanProcessesToSettle;
|
|
42
|
+
exports.assertOrphanCleanupComplete = assertOrphanCleanupComplete;
|
|
43
|
+
exports.drainOrphanProcessesBeforeStartup = drainOrphanProcessesBeforeStartup;
|
|
42
44
|
exports.killOrphanProcesses = killOrphanProcesses;
|
|
43
45
|
exports.writePidfile = writePidfile;
|
|
44
46
|
exports.handleAgentSenseTurn = handleAgentSenseTurn;
|
|
@@ -124,7 +126,8 @@ function parseOrphanPidsFromPs(psOutput, selfPid) {
|
|
|
124
126
|
&& !line.includes("bluebubbles/entry.js")
|
|
125
127
|
&& !line.includes("mail-entry.js")
|
|
126
128
|
&& !line.includes("teams-entry.js")
|
|
127
|
-
&& !line.includes("a2a-entry.js")
|
|
129
|
+
&& !line.includes("a2a-entry.js")
|
|
130
|
+
&& !line.includes("voice-entry.js"))
|
|
128
131
|
continue;
|
|
129
132
|
// Parse `<pid> <ppid> <command...>`. ps pads these with leading spaces.
|
|
130
133
|
// Regex guarantees both groups are \d+ so parseInt can't produce NaN.
|
|
@@ -228,6 +231,41 @@ async function waitForOrphanProcessesToSettle(pids, deps = {}) {
|
|
|
228
231
|
}
|
|
229
232
|
return survivors;
|
|
230
233
|
}
|
|
234
|
+
function assertOrphanCleanupComplete(survivingPids) {
|
|
235
|
+
if (survivingPids.length === 0)
|
|
236
|
+
return;
|
|
237
|
+
const errorReason = `refusing startup while ${survivingPids.length} orphaned Ouro processes remain: ${survivingPids.join(", ")}`;
|
|
238
|
+
(0, runtime_1.emitNervesEvent)({
|
|
239
|
+
level: "error",
|
|
240
|
+
component: "daemon",
|
|
241
|
+
event: "daemon.orphan_cleanup_incomplete",
|
|
242
|
+
message: errorReason,
|
|
243
|
+
meta: { survivingPids },
|
|
244
|
+
});
|
|
245
|
+
throw new Error(errorReason);
|
|
246
|
+
}
|
|
247
|
+
const ORPHAN_CLEANUP_MAX_SIGNAL_PASSES = 8;
|
|
248
|
+
async function drainOrphanProcessesBeforeStartup(socketPath = socket_client_1.DEFAULT_DAEMON_SOCKET_PATH, deps = {}) {
|
|
249
|
+
const signalOrphans = deps.signalOrphans ?? killOrphanProcesses;
|
|
250
|
+
const settleOrphans = deps.settleOrphans ?? waitForOrphanProcessesToSettle;
|
|
251
|
+
const maxSignalPasses = deps.maxSignalPasses ?? ORPHAN_CLEANUP_MAX_SIGNAL_PASSES;
|
|
252
|
+
for (let pass = 0; pass < maxSignalPasses; pass += 1) {
|
|
253
|
+
const signaledPids = signalOrphans(socketPath);
|
|
254
|
+
if (signaledPids.length === 0)
|
|
255
|
+
return;
|
|
256
|
+
const survivingPids = await settleOrphans(signaledPids);
|
|
257
|
+
assertOrphanCleanupComplete(survivingPids);
|
|
258
|
+
}
|
|
259
|
+
const errorReason = `orphan cleanup did not reach a fixed point after ${maxSignalPasses} signaling round(s)`;
|
|
260
|
+
(0, runtime_1.emitNervesEvent)({
|
|
261
|
+
level: "error",
|
|
262
|
+
component: "daemon",
|
|
263
|
+
event: "daemon.orphan_cleanup_not_converged",
|
|
264
|
+
message: errorReason,
|
|
265
|
+
meta: { maxSignalPasses },
|
|
266
|
+
});
|
|
267
|
+
throw new Error(errorReason);
|
|
268
|
+
}
|
|
231
269
|
/* v8 ignore start -- shells out to ps; covered by filterPidfilePidsToActualOrphans unit tests via injected runner @preserve */
|
|
232
270
|
function runPsCheck(pids) {
|
|
233
271
|
try {
|
|
@@ -305,7 +343,10 @@ function killOrphanProcesses(socketPath = socket_client_1.DEFAULT_DAEMON_SOCKET_
|
|
|
305
343
|
const result = (0, child_process_1.execSync)("ps -eo pid,ppid,command", { encoding: "utf-8", timeout: 5000 });
|
|
306
344
|
scanOrphans = parseOrphanPidsFromPs(result, process.pid);
|
|
307
345
|
}
|
|
308
|
-
catch {
|
|
346
|
+
catch (error) {
|
|
347
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
348
|
+
throw new Error(`could not discover orphaned Ouro processes: ${detail}`);
|
|
349
|
+
}
|
|
309
350
|
const pidsToKill = mergeUniqueOrphanPids(pidfileOrphans, scanOrphans);
|
|
310
351
|
if (pidsToKill.length > 0) {
|
|
311
352
|
for (const pid of pidsToKill) {
|
|
@@ -325,13 +366,13 @@ function killOrphanProcesses(socketPath = socket_client_1.DEFAULT_DAEMON_SOCKET_
|
|
|
325
366
|
}
|
|
326
367
|
catch (error) {
|
|
327
368
|
(0, runtime_1.emitNervesEvent)({
|
|
328
|
-
level: "
|
|
369
|
+
level: "error",
|
|
329
370
|
component: "daemon",
|
|
330
371
|
event: "daemon.orphan_cleanup_error",
|
|
331
372
|
message: "failed to clean up orphaned ouro processes",
|
|
332
373
|
meta: { error: error instanceof Error ? error.message : String(error) },
|
|
333
374
|
});
|
|
334
|
-
|
|
375
|
+
throw error instanceof Error ? error : new Error(String(error));
|
|
335
376
|
}
|
|
336
377
|
}
|
|
337
378
|
/**
|
|
@@ -575,6 +616,7 @@ class OuroDaemon {
|
|
|
575
616
|
onStopCommandComplete;
|
|
576
617
|
externalEventRoot;
|
|
577
618
|
rsvpHabitRunner;
|
|
619
|
+
orphanStartupDrain;
|
|
578
620
|
constructor(options) {
|
|
579
621
|
this.socketPath = options.socketPath;
|
|
580
622
|
this.processManager = options.processManager;
|
|
@@ -589,6 +631,7 @@ class OuroDaemon {
|
|
|
589
631
|
this.onStopCommandComplete = options.onStopCommandComplete ?? null;
|
|
590
632
|
this.externalEventRoot = options.externalEventRoot ?? null;
|
|
591
633
|
this.rsvpHabitRunner = options.rsvpHabitRunner;
|
|
634
|
+
this.orphanStartupDrain = options.orphanStartupDrain ?? drainOrphanProcessesBeforeStartup;
|
|
592
635
|
}
|
|
593
636
|
/* v8 ignore start -- default mailbox server wiring: production-only path, tests inject mailboxServerFactory stub instead. startMailboxHttpServer itself has full coverage in mailbox-http.test.ts @preserve */
|
|
594
637
|
createDefaultMailboxServer() {
|
|
@@ -740,10 +783,7 @@ class OuroDaemon {
|
|
|
740
783
|
}
|
|
741
784
|
// MCP connections are lazily initialized per-agent during senseTurn
|
|
742
785
|
// (daemon manages multiple agents; agent identity must be set before loading MCP config)
|
|
743
|
-
|
|
744
|
-
const killedOrphanPids = killOrphanProcesses(this.socketPath);
|
|
745
|
-
await waitForOrphanProcessesToSettle(killedOrphanPids);
|
|
746
|
-
/* v8 ignore stop */
|
|
786
|
+
await this.orphanStartupDrain(this.socketPath);
|
|
747
787
|
await this.openCommandSocket();
|
|
748
788
|
this.triggerAutoStartAgents();
|
|
749
789
|
this.triggerAutoStartSensesWhenAgentsSettled();
|
|
@@ -1049,8 +1089,12 @@ class OuroDaemon {
|
|
|
1049
1089
|
clearTimeout(this.senseAutostartTimer);
|
|
1050
1090
|
this.senseAutostartTimer = null;
|
|
1051
1091
|
}
|
|
1052
|
-
|
|
1053
|
-
|
|
1092
|
+
const workerStopTasks = [Promise.resolve().then(() => this.processManager.stopAll())];
|
|
1093
|
+
if (this.senseManager) {
|
|
1094
|
+
workerStopTasks.push(Promise.resolve().then(() => this.senseManager.stopAll()));
|
|
1095
|
+
}
|
|
1096
|
+
const workerStopResults = await Promise.allSettled(workerStopTasks);
|
|
1097
|
+
const workerStopFailures = workerStopResults.flatMap((result) => result.status === "rejected" ? [result.reason] : []);
|
|
1054
1098
|
if (this.server) {
|
|
1055
1099
|
// DO NOT `await` server.close() here. server.close() resolves only
|
|
1056
1100
|
// after every open connection has closed. When stop() is invoked
|
|
@@ -1113,6 +1157,19 @@ class OuroDaemon {
|
|
|
1113
1157
|
});
|
|
1114
1158
|
}
|
|
1115
1159
|
this.socketIdentity = null;
|
|
1160
|
+
if (workerStopFailures.length > 0) {
|
|
1161
|
+
const errorReason = `daemon shutdown could not drain ${workerStopFailures.length} managed worker group(s)`;
|
|
1162
|
+
(0, runtime_1.emitNervesEvent)({
|
|
1163
|
+
level: "error",
|
|
1164
|
+
component: "daemon",
|
|
1165
|
+
event: "daemon.worker_shutdown_error",
|
|
1166
|
+
message: errorReason,
|
|
1167
|
+
meta: {
|
|
1168
|
+
failures: workerStopFailures.map((error) => error instanceof Error ? error.message : /* v8 ignore next -- defensive: non-Error rejection @preserve */ String(error)),
|
|
1169
|
+
},
|
|
1170
|
+
});
|
|
1171
|
+
throw new AggregateError(workerStopFailures, errorReason);
|
|
1172
|
+
}
|
|
1116
1173
|
}
|
|
1117
1174
|
async handleRawPayload(raw) {
|
|
1118
1175
|
try {
|
|
@@ -1477,8 +1534,12 @@ class OuroDaemon {
|
|
|
1477
1534
|
await this.start();
|
|
1478
1535
|
return { ok: true, message: "daemon started" };
|
|
1479
1536
|
case "daemon.stop":
|
|
1480
|
-
|
|
1481
|
-
|
|
1537
|
+
try {
|
|
1538
|
+
await this.stop();
|
|
1539
|
+
}
|
|
1540
|
+
finally {
|
|
1541
|
+
this.onStopCommandComplete?.();
|
|
1542
|
+
}
|
|
1482
1543
|
return { ok: true, message: "daemon stopped" };
|
|
1483
1544
|
case "daemon.restart": {
|
|
1484
1545
|
// Restart is "stop + let launchctl respawn." Under launchctl's KeepAlive
|
|
@@ -1494,8 +1555,12 @@ class OuroDaemon {
|
|
|
1494
1555
|
requestedBy: command.requestedBy ?? null,
|
|
1495
1556
|
},
|
|
1496
1557
|
});
|
|
1497
|
-
|
|
1498
|
-
|
|
1558
|
+
try {
|
|
1559
|
+
await this.stop();
|
|
1560
|
+
}
|
|
1561
|
+
finally {
|
|
1562
|
+
this.onStopCommandComplete?.();
|
|
1563
|
+
}
|
|
1499
1564
|
return {
|
|
1500
1565
|
ok: true,
|
|
1501
1566
|
message: "daemon restarting — launchctl will respawn",
|
|
@@ -24,6 +24,7 @@ exports.checkLifecycle = checkLifecycle;
|
|
|
24
24
|
exports.runDoctorChecks = runDoctorChecks;
|
|
25
25
|
const runtime_1 = require("../../nerves/runtime");
|
|
26
26
|
const bluebubbles_health_diagnostics_1 = require("./bluebubbles-health-diagnostics");
|
|
27
|
+
const webhook_registration_1 = require("../../senses/bluebubbles/webhook-registration");
|
|
27
28
|
const freshness_1 = require("./freshness");
|
|
28
29
|
const ouro_path_installer_1 = require("../versioning/ouro-path-installer");
|
|
29
30
|
const runtime_credentials_1 = require("../runtime-credentials");
|
|
@@ -35,6 +36,8 @@ const config_1 = require("../../rsvp/config");
|
|
|
35
36
|
const cutover_1 = require("../../rsvp/cutover");
|
|
36
37
|
const diagnostics_1 = require("../../rsvp/diagnostics");
|
|
37
38
|
const DEFAULT_BLUEBUBBLES_REQUEST_TIMEOUT_MS = 30_000;
|
|
39
|
+
const DEFAULT_BLUEBUBBLES_PORT = 18_790;
|
|
40
|
+
const DEFAULT_BLUEBUBBLES_WEBHOOK_PATH = "/bluebubbles-webhook";
|
|
38
41
|
// ── Category checkers ──
|
|
39
42
|
function checkCliPath(deps) {
|
|
40
43
|
const resolution = (0, ouro_path_installer_1.diagnoseOuroPath)({
|
|
@@ -412,10 +415,11 @@ async function checkSenses(deps) {
|
|
|
412
415
|
});
|
|
413
416
|
let upstreamContext = "upstream probe not run in this pass";
|
|
414
417
|
if (deps.fetchImpl) {
|
|
418
|
+
const requestTimeoutMs = numberField(bluebubblesChannel, "requestTimeoutMs", DEFAULT_BLUEBUBBLES_REQUEST_TIMEOUT_MS);
|
|
415
419
|
const probe = await (0, bluebubbles_health_diagnostics_1.probeBlueBubblesHealth)({
|
|
416
420
|
serverUrl,
|
|
417
421
|
password,
|
|
418
|
-
requestTimeoutMs
|
|
422
|
+
requestTimeoutMs,
|
|
419
423
|
fetchImpl: deps.fetchImpl,
|
|
420
424
|
});
|
|
421
425
|
checks.push({
|
|
@@ -426,6 +430,22 @@ async function checkSenses(deps) {
|
|
|
426
430
|
upstreamContext = probe.ok
|
|
427
431
|
? "upstream probe reachable — which does not prove inbound delivery"
|
|
428
432
|
: "upstream probe failing";
|
|
433
|
+
const webhook = await (0, webhook_registration_1.inspectBlueBubblesWebhookRegistration)({
|
|
434
|
+
serverUrl,
|
|
435
|
+
password,
|
|
436
|
+
callbackPort: numberField(bluebubblesChannel, "port", DEFAULT_BLUEBUBBLES_PORT),
|
|
437
|
+
callbackPath: textField(bluebubblesChannel, "webhookPath") || DEFAULT_BLUEBUBBLES_WEBHOOK_PATH,
|
|
438
|
+
agentName,
|
|
439
|
+
machineId,
|
|
440
|
+
requestTimeoutMs,
|
|
441
|
+
listenerReady: true,
|
|
442
|
+
}, { fetchImpl: deps.fetchImpl });
|
|
443
|
+
checks.push({
|
|
444
|
+
id: "senses.bluebubbles.webhook",
|
|
445
|
+
label: `${agentDir} bluebubbles webhook`,
|
|
446
|
+
status: webhook.ok ? "pass" : "fail",
|
|
447
|
+
detail: webhook.detail,
|
|
448
|
+
});
|
|
429
449
|
}
|
|
430
450
|
const bluebubblesStateRoot = `${deps.bundlesRoot}/${agentDir}/state/senses/bluebubbles`;
|
|
431
451
|
checks.push(senseInboundDeliveryCheck({
|