@ouro.bot/cli 0.1.0-alpha.741 → 0.1.0-alpha.743
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 +42 -0
- package/deploy/unraid/Dockerfile +7 -2
- package/deploy/unraid/README.txt +717 -106
- package/deploy/unraid/migrate-sanctuary-bundle.mjs +21 -0
- package/deploy/unraid/ouro-events/bootstrap-spool.sh +92 -0
- package/deploy/unraid/ouro-events/emit-event.mjs +310 -0
- package/deploy/unraid/ouro-events/emit-usenet-event.sh +54 -0
- package/deploy/unraid/ouro-events/install-usenet-guard.sh +434 -0
- package/deploy/unraid/ouro-events/usenet-health.sh +178 -0
- package/deploy/unraid/sanctuary-acceptance-contract.json +4 -3
- package/deploy/unraid/sanctuary-unit16-host-broker.mjs +5 -1
- package/deploy/unraid/sanctuary.ouro/agent.json +2 -2
- package/deploy/unraid/sanctuary.ouro/bundle-meta.json +2 -2
- package/deploy/unraid/sanctuary.ouro/habits/sanctuary-health.md +1 -1
- package/deploy/unraid/sanctuary.ouro/provider-readiness.json +3 -10
- package/deploy/unraid/sanctuary.ouro/psyche/ASPIRATIONS.md +3 -1
- package/deploy/unraid/sanctuary.ouro/psyche/IDENTITY.md +3 -1
- package/deploy/unraid/sanctuary.ouro/psyche/LORE.md +4 -0
- package/deploy/unraid/sanctuary.ouro/psyche/SOUL.md +6 -2
- package/deploy/unraid/sanctuary.ouro/psyche/TACIT.md +4 -2
- package/deploy/unraid/sanctuary.ouro/state/policy/steward.json +7 -0
- package/deploy/unraid/sanctuary.ouro/tool-profiles.json +19 -17
- package/deploy/unraid/sanctuary.xml +12 -9
- package/dist/arc/cares.js +171 -37
- package/dist/arc/obligations.js +38 -0
- package/dist/heart/awaiting/await-alert.js +4 -2
- package/dist/heart/awaiting/await-expiry.js +39 -4
- package/dist/heart/awaiting/await-parser.js +8 -0
- package/dist/heart/context-loss-gauntlet.js +31 -2
- package/dist/heart/context-loss-sentinel.js +2 -0
- package/dist/heart/core.js +37 -7
- package/dist/heart/cross-chat-delivery.js +1 -0
- package/dist/heart/daemon/container-healthcheck.js +3 -1
- package/dist/heart/daemon/container-runtime.js +13 -0
- package/dist/heart/daemon/container-spec-auditor-main.js +11 -7
- package/dist/heart/daemon/container-spec-auditor.js +38 -11
- package/dist/heart/daemon/daemon-entry.js +19 -5
- package/dist/heart/daemon/daemon.js +154 -22
- package/dist/heart/daemon/sanctuary-acceptance-adapter.js +151 -87
- package/dist/heart/daemon/sanctuary-acceptance-harness.js +26 -29
- package/dist/heart/daemon/sanctuary-acceptance-scenarios.js +42 -51
- package/dist/heart/daemon/sanctuary-bundle-migration.js +398 -0
- package/dist/heart/daemon/sanctuary-scheduler-origin.js +11 -5
- package/dist/heart/daemon/supercronic-supervisor.js +16 -1
- package/dist/heart/external-events/router.js +1025 -43
- package/dist/heart/provider-models.js +10 -3
- package/dist/heart/session-events.js +23 -5
- package/dist/heart/steward-policy.js +302 -0
- package/dist/heart/tool-approval.js +3 -1
- package/dist/heart/turn-context.js +1 -0
- package/dist/mind/context.js +8 -3
- package/dist/mind/pending.js +25 -0
- package/dist/mind/prompt.js +49 -1
- package/dist/repertoire/guardrails.js +2 -1
- package/dist/repertoire/relationship-authorization.js +194 -0
- package/dist/repertoire/tools-awaiting.js +229 -26
- package/dist/repertoire/tools-base.js +15 -0
- package/dist/repertoire/tools-continuity.js +259 -4
- package/dist/repertoire/tools-notes.js +29 -3
- package/dist/repertoire/tools-session.js +219 -4
- package/dist/repertoire/tools-steward-policy.js +88 -0
- package/dist/repertoire/tools-telegram-contacts.js +37 -0
- package/dist/repertoire/tools-unraid.js +113 -6
- package/dist/repertoire/tools.js +104 -9
- package/dist/repertoire/unraid-restart.js +86 -4
- package/dist/senses/private-runtime-worker.js +36 -3
- package/dist/senses/private-runtime.js +310 -63
- package/dist/senses/sanctuary-health-acceptance-probe.js +8 -6
- package/dist/senses/sanctuary-health-runner.js +51 -96
- package/dist/senses/sanctuary-health.js +54 -93
- package/dist/senses/sanctuary-runtime.js +36 -2
- package/dist/senses/sanctuary-sab.js +80 -0
- package/dist/senses/shared-turn.js +64 -9
- package/dist/senses/telegram-admission.js +684 -0
- package/dist/senses/telegram-approval-runtime.js +46 -6
- package/dist/senses/telegram-client.js +236 -72
- package/dist/senses/telegram-effect-adapter.js +787 -0
- package/dist/senses/telegram-entry.js +4 -1
- package/dist/senses/telegram.js +728 -48
- package/npm-shrinkwrap.json +6 -6
- package/package.json +2 -2
|
@@ -615,10 +615,14 @@ class OuroDaemon {
|
|
|
615
615
|
mailboxServer = null;
|
|
616
616
|
socketIdentity = null;
|
|
617
617
|
senseAutostartTimer = null;
|
|
618
|
+
externalEventReconcileTimer = null;
|
|
619
|
+
externalEventReconcileRunning = false;
|
|
618
620
|
mailboxServerFactory;
|
|
619
621
|
privateRuntimePolicyDeps;
|
|
620
622
|
onStopCommandComplete;
|
|
621
623
|
externalEventRoot;
|
|
624
|
+
privilegedEventSpoolRoot;
|
|
625
|
+
privilegedEventScanner;
|
|
622
626
|
rsvpHabitRunner;
|
|
623
627
|
nativeHabitRunner;
|
|
624
628
|
nativeHabitMatch;
|
|
@@ -640,6 +644,8 @@ class OuroDaemon {
|
|
|
640
644
|
this.privateRuntimePolicyDeps = options.privateRuntimePolicyDeps ?? {};
|
|
641
645
|
this.onStopCommandComplete = options.onStopCommandComplete ?? null;
|
|
642
646
|
this.externalEventRoot = options.externalEventRoot ?? null;
|
|
647
|
+
this.privilegedEventSpoolRoot = options.privilegedEventSpoolRoot ?? "/run/ouro-events";
|
|
648
|
+
this.privilegedEventScanner = options.privilegedEventScanner ?? router_1.scanPrivilegedEventSpool;
|
|
643
649
|
this.rsvpHabitRunner = options.rsvpHabitRunner;
|
|
644
650
|
this.nativeHabitRunner = options.nativeHabitRunner;
|
|
645
651
|
this.nativeHabitMatch = options.nativeHabitMatch;
|
|
@@ -694,6 +700,7 @@ class OuroDaemon {
|
|
|
694
700
|
agentName,
|
|
695
701
|
agentRoot: path.join(this.bundlesRoot, `${agentName}.ouro`),
|
|
696
702
|
})));
|
|
703
|
+
const externalEvents = (0, router_1.listExternalEventStatus)(this.externalEventRoot ?? (0, router_1.getExternalEventRoot)());
|
|
697
704
|
const mailboxUrl = this.mailboxServer?.origin ?? "http://127.0.0.1:0";
|
|
698
705
|
return {
|
|
699
706
|
overview: {
|
|
@@ -714,6 +721,7 @@ class OuroDaemon {
|
|
|
714
721
|
sync,
|
|
715
722
|
agents,
|
|
716
723
|
...(providers.length > 0 ? { providers } : {}),
|
|
724
|
+
...(externalEvents.length > 0 ? { externalEvents } : {}),
|
|
717
725
|
};
|
|
718
726
|
}
|
|
719
727
|
overlaySchedulerHealth(healthChecks) {
|
|
@@ -801,6 +809,11 @@ class OuroDaemon {
|
|
|
801
809
|
// (daemon manages multiple agents; agent identity must be set before loading MCP config)
|
|
802
810
|
await this.orphanStartupDrain(this.socketPath);
|
|
803
811
|
await this.openCommandSocket();
|
|
812
|
+
await this.reconcileExternalEvents();
|
|
813
|
+
this.externalEventReconcileTimer = setInterval(() => {
|
|
814
|
+
void this.reconcileExternalEvents();
|
|
815
|
+
}, 1_000);
|
|
816
|
+
this.externalEventReconcileTimer.unref?.();
|
|
804
817
|
this.triggerAutoStartAgents();
|
|
805
818
|
this.triggerAutoStartSensesWhenAgentsSettled();
|
|
806
819
|
// Write all managed PIDs to disk so the next daemon can clean up
|
|
@@ -1105,6 +1118,10 @@ class OuroDaemon {
|
|
|
1105
1118
|
clearTimeout(this.senseAutostartTimer);
|
|
1106
1119
|
this.senseAutostartTimer = null;
|
|
1107
1120
|
}
|
|
1121
|
+
if (this.externalEventReconcileTimer) {
|
|
1122
|
+
clearInterval(this.externalEventReconcileTimer);
|
|
1123
|
+
this.externalEventReconcileTimer = null;
|
|
1124
|
+
}
|
|
1108
1125
|
const workerStopTasks = [Promise.resolve().then(() => this.processManager.stopAll())];
|
|
1109
1126
|
if (this.senseManager) {
|
|
1110
1127
|
workerStopTasks.push(Promise.resolve().then(() => this.senseManager.stopAll()));
|
|
@@ -1279,14 +1296,14 @@ class OuroDaemon {
|
|
|
1279
1296
|
],
|
|
1280
1297
|
};
|
|
1281
1298
|
}
|
|
1282
|
-
buildExternalEventPrivateWakeCommand(command, receiptId) {
|
|
1299
|
+
buildExternalEventPrivateWakeCommand(command, receiptId, generation, attemptCount) {
|
|
1283
1300
|
return {
|
|
1284
1301
|
kind: "private.wake",
|
|
1285
1302
|
agent: command.agent,
|
|
1286
1303
|
reason: `external event ${command.source}/${command.eventType}`,
|
|
1287
1304
|
triggerSource: "external-event",
|
|
1288
1305
|
budgetClass: "interactive",
|
|
1289
|
-
idempotencyKey: `external-event:${command.agent}:${command.source}:${command.eventId}`,
|
|
1306
|
+
idempotencyKey: `external-event:${command.agent}:${command.source}:${command.eventId}:generation:${generation}:attempt:${attemptCount}`,
|
|
1290
1307
|
originRefs: [
|
|
1291
1308
|
{ kind: "external-event", id: command.eventId, source: command.source, eventType: command.eventType },
|
|
1292
1309
|
{ kind: "queue-receipt", id: receiptId },
|
|
@@ -1456,7 +1473,7 @@ class OuroDaemon {
|
|
|
1456
1473
|
data: result,
|
|
1457
1474
|
};
|
|
1458
1475
|
}
|
|
1459
|
-
buildPrivateRuntimeWorkerWakeMessage(command, decision) {
|
|
1476
|
+
buildPrivateRuntimeWorkerWakeMessage(command, decision, externalEvent) {
|
|
1460
1477
|
const awaitName = (0, await_private_wake_1.awaitNameFromPrivateWakeCommand)(command);
|
|
1461
1478
|
if (awaitName) {
|
|
1462
1479
|
return {
|
|
@@ -1483,13 +1500,13 @@ class OuroDaemon {
|
|
|
1483
1500
|
privateTurnDecision: decision,
|
|
1484
1501
|
};
|
|
1485
1502
|
}
|
|
1486
|
-
return { type: "message", privateTurnDecision: decision };
|
|
1503
|
+
return { type: "message", privateTurnDecision: decision, ...(externalEvent ? { externalEvent } : {}) };
|
|
1487
1504
|
}
|
|
1488
1505
|
queueExternalEventForPrivateRuntime(record) {
|
|
1489
1506
|
const pendingDir = path.join(this.bundlesRoot, `${record.agent}.ouro`, "state", "pending", pending_1.PRIVATE_RUNTIME_PENDING.friendId, pending_1.PRIVATE_RUNTIME_PENDING.channel, pending_1.PRIVATE_RUNTIME_PENDING.key);
|
|
1490
1507
|
const originKey = `${record.source}:${record.eventId}`;
|
|
1491
1508
|
const parsedReceivedAt = Date.parse(record.receivedAt);
|
|
1492
|
-
(0, pending_1.
|
|
1509
|
+
(0, pending_1.queuePendingMessageOnce)(pendingDir, {
|
|
1493
1510
|
from: "ouro-external-event",
|
|
1494
1511
|
friendId: "ouro-external-event",
|
|
1495
1512
|
channel: "external-event",
|
|
@@ -1503,6 +1520,7 @@ class OuroDaemon {
|
|
|
1503
1520
|
},
|
|
1504
1521
|
obligationStatus: "pending",
|
|
1505
1522
|
mode: "relay",
|
|
1523
|
+
packetId: `external-event:${record.agent}:${record.source}:${record.eventId}:generation:${record.generation}:attempt:${record.attemptCount}`,
|
|
1506
1524
|
});
|
|
1507
1525
|
(0, runtime_1.emitNervesEvent)({
|
|
1508
1526
|
component: "daemon",
|
|
@@ -1517,7 +1535,124 @@ class OuroDaemon {
|
|
|
1517
1535
|
},
|
|
1518
1536
|
});
|
|
1519
1537
|
}
|
|
1520
|
-
|
|
1538
|
+
externalEventRootPath() {
|
|
1539
|
+
return this.externalEventRoot ?? (0, router_1.getExternalEventRoot)();
|
|
1540
|
+
}
|
|
1541
|
+
externalEventLease(record) {
|
|
1542
|
+
/* v8 ignore next -- dispatcher calls this only with the record returned by claimExternalEvent @preserve */
|
|
1543
|
+
if (!record.claimOwner)
|
|
1544
|
+
throw new Error("External event dispatch requires a claimed receipt");
|
|
1545
|
+
return {
|
|
1546
|
+
schemaVersion: 1,
|
|
1547
|
+
recordPath: record.recordPath,
|
|
1548
|
+
agent: record.agent,
|
|
1549
|
+
source: record.source,
|
|
1550
|
+
eventId: record.eventId,
|
|
1551
|
+
generation: record.generation,
|
|
1552
|
+
observationRevision: record.observationRevision,
|
|
1553
|
+
claimOwner: record.claimOwner,
|
|
1554
|
+
};
|
|
1555
|
+
}
|
|
1556
|
+
async dispatchExternalEvents(records) {
|
|
1557
|
+
const claimed = [];
|
|
1558
|
+
try {
|
|
1559
|
+
for (const record of records) {
|
|
1560
|
+
const owner = `external-event:${record.agent}:${record.source}:${record.eventId}:generation:${record.generation}:attempt:${record.attemptCount + 1}`;
|
|
1561
|
+
claimed.push((0, router_1.claimExternalEvent)(record.recordPath, { owner, expectedVersion: record.version, expectedGeneration: record.generation }));
|
|
1562
|
+
}
|
|
1563
|
+
const primary = claimed[0];
|
|
1564
|
+
const [primaryLease, ...relatedEvents] = claimed.map((record) => this.externalEventLease(record));
|
|
1565
|
+
const lease = { ...primaryLease, ...(relatedEvents.length > 0 ? { relatedEvents } : {}) };
|
|
1566
|
+
const receipt = {
|
|
1567
|
+
id: `external-event:${primary.agent}:${primary.source}:${primary.eventId}:generation:${primary.generation}:attempt:${primary.attemptCount}`,
|
|
1568
|
+
queuedAt: primary.updatedAt,
|
|
1569
|
+
};
|
|
1570
|
+
const wake = await this.handlePrivateRuntimeWake(this.buildExternalEventPrivateWakeCommand({
|
|
1571
|
+
kind: "external.event.submit",
|
|
1572
|
+
agent: primary.agent,
|
|
1573
|
+
source: primary.source,
|
|
1574
|
+
eventType: primary.eventType,
|
|
1575
|
+
eventId: primary.eventId,
|
|
1576
|
+
}, receipt.id, primary.generation, primary.attemptCount), () => { for (const record of claimed)
|
|
1577
|
+
this.queueExternalEventForPrivateRuntime(record); }, lease);
|
|
1578
|
+
const denied = !wake.ok || wake.data?.decision?.executable === false;
|
|
1579
|
+
if (denied)
|
|
1580
|
+
throw new Error(wake.error ?? wake.message ?? /* v8 ignore next -- daemon wake responses always carry an error or message @preserve */ "external-event private turn was denied");
|
|
1581
|
+
return { events: claimed, event: primary, receipt, wake };
|
|
1582
|
+
}
|
|
1583
|
+
catch (error) {
|
|
1584
|
+
for (const record of claimed) {
|
|
1585
|
+
const latest = (0, router_1.readExternalEventRecord)(record.recordPath);
|
|
1586
|
+
if (latest.executionState === "running" && latest.claimOwner === record.claimOwner) {
|
|
1587
|
+
(0, router_1.failExternalEventAttempt)(latest.recordPath, {
|
|
1588
|
+
owner: record.claimOwner, expectedVersion: latest.version, expectedGeneration: latest.generation,
|
|
1589
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1590
|
+
});
|
|
1591
|
+
}
|
|
1592
|
+
}
|
|
1593
|
+
throw error;
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1596
|
+
dispatchExternalEvent(record) {
|
|
1597
|
+
return this.dispatchExternalEvents([record]);
|
|
1598
|
+
}
|
|
1599
|
+
async reconcileExternalEvents() {
|
|
1600
|
+
/* v8 ignore next -- re-entrancy guard is exercised only by overlapping real timer callbacks @preserve */
|
|
1601
|
+
if (this.externalEventReconcileRunning)
|
|
1602
|
+
return;
|
|
1603
|
+
this.externalEventReconcileRunning = true;
|
|
1604
|
+
try {
|
|
1605
|
+
const now = new Date().toISOString();
|
|
1606
|
+
if (fs.existsSync(this.privilegedEventSpoolRoot)) {
|
|
1607
|
+
this.privilegedEventScanner({ spoolRoot: this.privilegedEventSpoolRoot, eventRoot: this.externalEventRootPath() });
|
|
1608
|
+
}
|
|
1609
|
+
const statuses = (0, router_1.listExternalEventStatus)(this.externalEventRootPath());
|
|
1610
|
+
const dueRecords = [];
|
|
1611
|
+
for (const status of statuses) {
|
|
1612
|
+
if (status.corrupt)
|
|
1613
|
+
continue;
|
|
1614
|
+
let record = (0, router_1.readExternalEventRecord)(status.recordPath);
|
|
1615
|
+
if (record.dispatchEnabled === false)
|
|
1616
|
+
continue;
|
|
1617
|
+
if (record.executionState === "running" && record.claimExpiresAt && Date.parse(record.claimExpiresAt) <= Date.parse(now)) {
|
|
1618
|
+
record = (0, router_1.reconcileExternalEvent)(record.recordPath);
|
|
1619
|
+
}
|
|
1620
|
+
const due = record.executionState === "received"
|
|
1621
|
+
|| record.executionState === "queued"
|
|
1622
|
+
|| (record.executionState === "retry_wait" && record.nextAttemptAt !== null && Date.parse(record.nextAttemptAt) <= Date.parse(now));
|
|
1623
|
+
if (due)
|
|
1624
|
+
dueRecords.push(record);
|
|
1625
|
+
}
|
|
1626
|
+
const batches = new Map();
|
|
1627
|
+
for (const record of dueRecords) {
|
|
1628
|
+
const key = `${record.agent}\0${record.source}`;
|
|
1629
|
+
const batch = batches.get(key) ?? [];
|
|
1630
|
+
batch.push(record);
|
|
1631
|
+
batches.set(key, batch);
|
|
1632
|
+
}
|
|
1633
|
+
for (const records of batches.values()) {
|
|
1634
|
+
for (let offset = 0; offset < records.length; offset += 32) {
|
|
1635
|
+
const batch = records.slice(offset, offset + 32);
|
|
1636
|
+
try {
|
|
1637
|
+
await this.dispatchExternalEvents(batch);
|
|
1638
|
+
}
|
|
1639
|
+
catch (error) {
|
|
1640
|
+
(0, runtime_1.emitNervesEvent)({
|
|
1641
|
+
level: "warn",
|
|
1642
|
+
component: "daemon",
|
|
1643
|
+
event: "daemon.external_event_dispatch_error",
|
|
1644
|
+
message: "external event dispatch failed",
|
|
1645
|
+
meta: { recordPath: batch[0].recordPath, batchSize: batch.length, error: error instanceof Error ? error.message : /* v8 ignore next -- dispatch failures are Error objects @preserve */ String(error) },
|
|
1646
|
+
});
|
|
1647
|
+
}
|
|
1648
|
+
}
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
finally {
|
|
1652
|
+
this.externalEventReconcileRunning = false;
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1655
|
+
async handlePrivateRuntimeWake(command, beforeDispatch, externalEvent) {
|
|
1521
1656
|
if (!this.hasManagedPrivateRuntime(command.agent)) {
|
|
1522
1657
|
return {
|
|
1523
1658
|
ok: false,
|
|
@@ -1537,7 +1672,7 @@ class OuroDaemon {
|
|
|
1537
1672
|
}
|
|
1538
1673
|
await beforeDispatch?.(decision);
|
|
1539
1674
|
await this.processManager.startAgent(command.agent);
|
|
1540
|
-
this.processManager.sendToAgent?.(command.agent, this.buildPrivateRuntimeWorkerWakeMessage(command, decision));
|
|
1675
|
+
this.processManager.sendToAgent?.(command.agent, this.buildPrivateRuntimeWorkerWakeMessage(command, decision, externalEvent));
|
|
1541
1676
|
return {
|
|
1542
1677
|
ok: true,
|
|
1543
1678
|
message: `woke private runtime for ${command.agent}`,
|
|
@@ -1766,27 +1901,24 @@ class OuroDaemon {
|
|
|
1766
1901
|
evidence: command.evidence,
|
|
1767
1902
|
payloadPath: command.payloadPath,
|
|
1768
1903
|
priority: command.priority,
|
|
1904
|
+
observationRevision: command.observationRevision,
|
|
1905
|
+
transition: command.transition,
|
|
1769
1906
|
}, {
|
|
1770
1907
|
...(this.externalEventRoot ? { root: this.externalEventRoot } : {}),
|
|
1908
|
+
dispatchEnabled: command.wake !== false,
|
|
1771
1909
|
});
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
taskRef: command.taskRef ?? `${record.source}:${record.eventId}`,
|
|
1779
|
-
});
|
|
1780
|
-
let wake = null;
|
|
1781
|
-
if (command.wake !== false) {
|
|
1782
|
-
wake = await this.handlePrivateRuntimeWake(this.buildExternalEventPrivateWakeCommand(command, receipt.id), () => this.queueExternalEventForPrivateRuntime(record));
|
|
1910
|
+
if (!record.shouldWake || command.wake === false) {
|
|
1911
|
+
return {
|
|
1912
|
+
ok: true,
|
|
1913
|
+
message: `updated external event ${record.source}/${record.eventId} without wake`,
|
|
1914
|
+
data: { event: record, receipt: null, wake: null },
|
|
1915
|
+
};
|
|
1783
1916
|
}
|
|
1917
|
+
const dispatched = await this.dispatchExternalEvent(record);
|
|
1784
1918
|
return {
|
|
1785
1919
|
ok: true,
|
|
1786
|
-
message:
|
|
1787
|
-
|
|
1788
|
-
: `queued external event ${record.source}/${record.eventId} as ${receipt.id}; ${wake?.message ?? "wake skipped"}`,
|
|
1789
|
-
data: { event: record, receipt, wake },
|
|
1920
|
+
message: `queued external event ${record.source}/${record.eventId} as ${dispatched.receipt.id}; ${dispatched.wake.message ?? "wake skipped"}`,
|
|
1921
|
+
data: dispatched,
|
|
1790
1922
|
};
|
|
1791
1923
|
}
|
|
1792
1924
|
case "private.decisions": {
|