@cello-protocol/daemon 0.0.104 → 0.0.106
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/dist/consortium-bootstrap.d.ts +10 -1
- package/dist/consortium-bootstrap.d.ts.map +1 -1
- package/dist/consortium-bootstrap.js +16 -2
- package/dist/consortium-bootstrap.js.map +1 -1
- package/dist/daemon.js +58 -2
- package/dist/daemon.js.map +1 -1
- package/dist/directory-bootstrap.d.ts +16 -0
- package/dist/directory-bootstrap.d.ts.map +1 -1
- package/dist/directory-bootstrap.js +6 -0
- package/dist/directory-bootstrap.js.map +1 -1
- package/dist/inbound-sessions.d.ts +59 -0
- package/dist/inbound-sessions.d.ts.map +1 -1
- package/dist/inbound-sessions.js +145 -74
- package/dist/inbound-sessions.js.map +1 -1
- package/dist/session-relay-client.d.ts.map +1 -1
- package/dist/session-relay-client.js +108 -1
- package/dist/session-relay-client.js.map +1 -1
- package/package.json +2 -2
|
@@ -20,7 +20,7 @@ import type { Logger } from "./types.js";
|
|
|
20
20
|
import type { ConsortiumManifest } from "@cello-protocol/protocol-types";
|
|
21
21
|
import type { IManifestProvider, IManifestVersionStore, IManifestPollScheduler } from "@cello-protocol/transport";
|
|
22
22
|
import type { DirectoryEndpoint } from "./signaling-connect.js";
|
|
23
|
-
import { type ConsortiumEndpoint } from "./directory-bootstrap.js";
|
|
23
|
+
import { type NodeResolveFailure, type ConsortiumEndpoint } from "./directory-bootstrap.js";
|
|
24
24
|
export interface ManifestGateDeps {
|
|
25
25
|
manifestProvider?: IManifestProvider;
|
|
26
26
|
manifestRootKeys?: readonly string[];
|
|
@@ -85,6 +85,15 @@ export interface ConsortiumRouting {
|
|
|
85
85
|
* path, where there is no primary resolver to wrap.
|
|
86
86
|
*/
|
|
87
87
|
failoverEndpointResolver: (() => Promise<DirectoryEndpoint | null>) | undefined;
|
|
88
|
+
/**
|
|
89
|
+
* Which consortium nodes this daemon currently cannot resolve, and why.
|
|
90
|
+
*
|
|
91
|
+
* Exists so `cello status` can answer "can I actually reach the directory?" rather than only
|
|
92
|
+
* "is my signaling socket up?". Those differ: libp2p signaling dials multiaddrs from the bundled
|
|
93
|
+
* manifest and stays connected, so every agent reports online while anything needing the HTTP
|
|
94
|
+
* endpoint — the roster, and therefore every threshold ceremony — fails.
|
|
95
|
+
*/
|
|
96
|
+
getUnresolvedNodes: () => NodeResolveFailure[];
|
|
88
97
|
/** Null-safe accessor for the ceremony/handler getDirectoryEndpoint sites. */
|
|
89
98
|
getFailoverEndpoint: () => Promise<DirectoryEndpoint | null>;
|
|
90
99
|
/** Stops the daemon-level HTTP manifest poll. Undefined when no poll was started. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consortium-bootstrap.d.ts","sourceRoot":"","sources":["../src/consortium-bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,KAAK,EACV,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,2BAA2B,CAAC;AAGnC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,
|
|
1
|
+
{"version":3,"file":"consortium-bootstrap.d.ts","sourceRoot":"","sources":["../src/consortium-bootstrap.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC;AACzE,OAAO,KAAK,EACV,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACvB,MAAM,2BAA2B,CAAC;AAGnC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChE,OAAO,EAGL,KAAK,kBAAkB,EAEvB,KAAK,kBAAkB,EACxB,MAAM,0BAA0B,CAAC;AAElC,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IACrC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,qBAAqB,CAAC;IAC5C,MAAM,EAAE,MAAM,CAAC;IACf,qFAAqF;IACrF,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,qFAAqF;IACrF,gBAAgB,EAAE,OAAO,CAAC;IAC1B,+EAA+E;IAC/E,uBAAuB,EAAE,MAAM,CAAC;IAChC;;;;OAIG;IACH,mBAAmB,EAAE,kBAAkB,EAAE,CAAC;IAC1C;;;;;;;;OAQG;IACH,gBAAgB,EAAE,kBAAkB,GAAG,IAAI,CAAC;CAC7C;AAED;;;;;GAKG;AACH,wBAAsB,qBAAqB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAsF/F;AAED,MAAM,WAAW,qBAAqB;IACpC,gBAAgB,CAAC,EAAE,iBAAiB,CAAC;IACrC,gBAAgB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,oBAAoB,EAAE,qBAAqB,CAAC;IAC5C,qBAAqB,CAAC,EAAE,sBAAsB,CAAC;IAC/C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,yBAAyB,CAAC,EAAE,MAAM,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IACpE,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC;;;;;OAKG;IACH,uBAAuB,EAAE,MAAM,OAAO,CAAC,kBAAkB,EAAE,GAAG,IAAI,CAAC,CAAC;IACpE;;;;;OAKG;IACH,wBAAwB,EAAE,CAAC,MAAM,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC,GAAG,SAAS,CAAC;IAChF;;;;;;;OAOG;IACH,kBAAkB,EAAE,MAAM,kBAAkB,EAAE,CAAC;IAC/C,8EAA8E;IAC9E,mBAAmB,EAAE,MAAM,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IAC7D,qFAAqF;IACrF,oBAAoB,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,SAAS,CAAC;CAChD;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,qBAAqB,GAAG,iBAAiB,CAkEtF"}
|
|
@@ -90,9 +90,23 @@ export async function verifyStartupManifest(deps) {
|
|
|
90
90
|
}
|
|
91
91
|
export function createConsortiumRouting(deps) {
|
|
92
92
|
const { manifestProvider, manifestRootKeys, manifestThreshold, manifestVersionStore, manifestPollScheduler, directoryHttpUrl, directoryEndpointResolver, logger, fetchFn, } = deps;
|
|
93
|
+
// LAST failure per node, not a running count — the operator needs the current state, and a node
|
|
94
|
+
// that has started resolving again must drop out rather than linger as a stale complaint. Cleared
|
|
95
|
+
// per sweep: every resolve attempt rebuilds this from what actually failed that time.
|
|
96
|
+
let unresolvedNodes = [];
|
|
97
|
+
const getUnresolvedNodes = () => [...unresolvedNodes];
|
|
93
98
|
const resolveConsortiumRoster = async () => {
|
|
94
99
|
const m = manifestProvider?.getCurrentManifest();
|
|
95
|
-
|
|
100
|
+
if (!m)
|
|
101
|
+
return null;
|
|
102
|
+
const failures = [];
|
|
103
|
+
const endpoints = await manifestNodesToEndpoints(m.nodes, {
|
|
104
|
+
logger,
|
|
105
|
+
fetchFn,
|
|
106
|
+
onNodeUnresolved: (f) => failures.push(f),
|
|
107
|
+
});
|
|
108
|
+
unresolvedNodes = failures;
|
|
109
|
+
return endpoints;
|
|
96
110
|
};
|
|
97
111
|
// DECLARED membership, straight off the verified manifest — no probe. Lets the resolver reject a
|
|
98
112
|
// primary that resolves but belongs to a different consortium (the compiled-in default URL after
|
|
@@ -130,6 +144,6 @@ export function createConsortiumRouting(deps) {
|
|
|
130
144
|
mintCorrelationId: () => randomUUID(),
|
|
131
145
|
});
|
|
132
146
|
}
|
|
133
|
-
return { resolveConsortiumRoster, failoverEndpointResolver, getFailoverEndpoint, stopHttpManifestPoll };
|
|
147
|
+
return { resolveConsortiumRoster, failoverEndpointResolver, getFailoverEndpoint, getUnresolvedNodes, stopHttpManifestPoll };
|
|
134
148
|
}
|
|
135
149
|
//# sourceMappingURL=consortium-bootstrap.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consortium-bootstrap.js","sourceRoot":"","sources":["../src/consortium-bootstrap.ts"],"names":[],"mappings":"AAyBA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,OAAO,EACL,mBAAmB,EACnB,wBAAwB,
|
|
1
|
+
{"version":3,"file":"consortium-bootstrap.js","sourceRoot":"","sources":["../src/consortium-bootstrap.ts"],"names":[],"mappings":"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"}
|
package/dist/daemon.js
CHANGED
|
@@ -240,7 +240,7 @@ async function startDaemonHoldingLock(config, singletonLock) {
|
|
|
240
240
|
"Check the logs for the specific failure reason (manifest_signature_invalid, manifest_expired, or manifest_version_rollback).");
|
|
241
241
|
}
|
|
242
242
|
// The manifest poll starts only AFTER the refuse above — a refused startup must not leak a timer.
|
|
243
|
-
const { resolveConsortiumRoster, failoverEndpointResolver, getFailoverEndpoint, stopHttpManifestPoll } = createConsortiumRouting({
|
|
243
|
+
const { resolveConsortiumRoster, failoverEndpointResolver, getFailoverEndpoint, getUnresolvedNodes, stopHttpManifestPoll } = createConsortiumRouting({
|
|
244
244
|
manifestProvider,
|
|
245
245
|
manifestRootKeys,
|
|
246
246
|
manifestThreshold,
|
|
@@ -477,7 +477,28 @@ async function startDaemonHoldingLock(config, singletonLock) {
|
|
|
477
477
|
// is only ever discovered at the NEXT agent start, not on the reconnect that actually
|
|
478
478
|
// brings the agent back — this closes that gap. Fire-and-forget; autoRecoverForAgent
|
|
479
479
|
// already catches its own per-relay errors internally.
|
|
480
|
-
onConnected: () => {
|
|
480
|
+
onConnected: () => {
|
|
481
|
+
void autoRecoverForAgent(agentName);
|
|
482
|
+
// RE-REGISTER THE STANDING RECEIVER. The receiver's LIFETIME is tied to this daemon; its
|
|
483
|
+
// REGISTRATION is tied to this stream, and the stream turns over roughly every 70 seconds.
|
|
484
|
+
// ensureStandingReceiverForAgent ran only at agent start, so 46 of 48 reconnects in one hour
|
|
485
|
+
// left every agent unregistered — the directory then answers `targetStreamFound: false` and
|
|
486
|
+
// a session request fails with `target_offline`, while `cello status`, `agent.online` and the
|
|
487
|
+
// directory's own agent_presence all still report the agent healthy. Silent, and it does not
|
|
488
|
+
// self-heal: only a daemon restart recovered it (2026-07-31 incident).
|
|
489
|
+
//
|
|
490
|
+
// Guarded on onlineAgents because this fires on the FIRST connect too, and an agent that was
|
|
491
|
+
// never started must not acquire a receiver here. Re-entry at start is harmless —
|
|
492
|
+
// #ensureStandingReceiver returns immediately when one exists or is being created.
|
|
493
|
+
if (onlineAgents.has(agentName)) {
|
|
494
|
+
void sessionNodeManager.ensureStandingReceiverForAgent(agentName).catch((err) => {
|
|
495
|
+
logger.warn("session.standing_receiver.reregister.failed", {
|
|
496
|
+
agentName,
|
|
497
|
+
error: err instanceof Error ? err.message : String(err),
|
|
498
|
+
});
|
|
499
|
+
});
|
|
500
|
+
}
|
|
501
|
+
},
|
|
481
502
|
});
|
|
482
503
|
const entry = { signaling: mgr, getNode: () => nodeRef };
|
|
483
504
|
perAgentSignaling.set(agentName, entry);
|
|
@@ -2415,10 +2436,45 @@ async function startDaemonHoldingLock(config, singletonLock) {
|
|
|
2415
2436
|
return { ok: true, signal_hash: signalHash, removed_locally: removed, directory_results: results };
|
|
2416
2437
|
});
|
|
2417
2438
|
// ─── MCP-001: cello_status (per-connection perspective) ───
|
|
2439
|
+
/**
|
|
2440
|
+
* The directory-reachability block for `cello_status`, or undefined when every node resolves.
|
|
2441
|
+
*
|
|
2442
|
+
* Reports the LAST resolve sweep. An empty list is not proof of health — it also means no sweep
|
|
2443
|
+
* has run yet — so the shape says which nodes failed and why rather than asserting "all good".
|
|
2444
|
+
*/
|
|
2445
|
+
function unresolvedNodesForStatus() {
|
|
2446
|
+
const failures = getUnresolvedNodes();
|
|
2447
|
+
if (failures.length === 0)
|
|
2448
|
+
return undefined;
|
|
2449
|
+
return {
|
|
2450
|
+
directory_endpoints_unresolved: {
|
|
2451
|
+
nodes: failures.map((f) => ({ node: f.nodeId, endpoint: f.endpoint, reason: f.reason, detail: f.detail })),
|
|
2452
|
+
guidance: "This daemon cannot resolve these directory endpoints, so the consortium roster is short and " +
|
|
2453
|
+
"threshold ceremonies will fail — sessions surface that as counterparty_offline, " +
|
|
2454
|
+
"directory_below_threshold, or ceremony_exhausted, none of which name the real cause. " +
|
|
2455
|
+
"Agents can still show 'online': signaling dials multiaddrs and does not need DNS. " +
|
|
2456
|
+
"If reason is dns_error after a directory restart or wake, the resolver is holding a cached " +
|
|
2457
|
+
"negative answer — flush it (macOS: sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder). " +
|
|
2458
|
+
"Verify with node -e 'require(\"dns\").lookup(host,console.log)', NOT dig: dig bypasses the " +
|
|
2459
|
+
"cache this daemon is stuck behind, so it reports success while the daemon still fails.",
|
|
2460
|
+
},
|
|
2461
|
+
};
|
|
2462
|
+
}
|
|
2418
2463
|
handlers.set("cello_status", async (_params, connectionId) => {
|
|
2419
2464
|
return {
|
|
2420
2465
|
daemon: "running",
|
|
2421
2466
|
directory_signaling: directorySignalingStatus(),
|
|
2467
|
+
// CAN I ACTUALLY REACH THE DIRECTORY — not just "is my socket up?".
|
|
2468
|
+
//
|
|
2469
|
+
// These are different facts and they diverged for an hour on 2026-07-31. libp2p signaling
|
|
2470
|
+
// dials multiaddrs from the bundled manifest, so it stayed connected and every agent reported
|
|
2471
|
+
// online, while a cached NXDOMAIN meant nothing that needed the HTTP endpoint resolved. The
|
|
2472
|
+
// roster came back empty, so every threshold ceremony failed — surfacing to the operator as
|
|
2473
|
+
// counterparty_offline, then directory_below_threshold, then ceremony_exhausted. Three errors,
|
|
2474
|
+
// none of them naming DNS, while the reason sat in the log 26 times per node.
|
|
2475
|
+
//
|
|
2476
|
+
// Omitted entirely when nothing is failing, so a healthy status stays quiet.
|
|
2477
|
+
...(unresolvedNodesForStatus() ?? {}),
|
|
2422
2478
|
agents: getAgentsForConnection(connectionId),
|
|
2423
2479
|
// M-1 PULL: live MCP clients must see interrupted sessions too, exactly as
|
|
2424
2480
|
// the daemon-wide getStatus() surfaces them.
|