@cello-protocol/daemon 0.0.3 → 0.0.5

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 (153) hide show
  1. package/dist/agent-loader.d.ts +41 -0
  2. package/dist/agent-loader.d.ts.map +1 -0
  3. package/dist/agent-loader.js +94 -0
  4. package/dist/agent-loader.js.map +1 -0
  5. package/dist/bin/cello-daemon.d.ts +13 -0
  6. package/dist/bin/cello-daemon.d.ts.map +1 -0
  7. package/dist/bin/cello-daemon.js +170 -0
  8. package/dist/bin/cello-daemon.js.map +1 -0
  9. package/dist/cello-node-transport-dialer.d.ts +59 -0
  10. package/dist/cello-node-transport-dialer.d.ts.map +1 -0
  11. package/dist/cello-node-transport-dialer.js +108 -0
  12. package/dist/cello-node-transport-dialer.js.map +1 -0
  13. package/dist/challenge-verifier.d.ts +12 -0
  14. package/dist/challenge-verifier.d.ts.map +1 -0
  15. package/dist/challenge-verifier.js +11 -0
  16. package/dist/challenge-verifier.js.map +1 -0
  17. package/dist/connect-or-start.d.ts +25 -0
  18. package/dist/connect-or-start.d.ts.map +1 -0
  19. package/dist/connect-or-start.js +117 -0
  20. package/dist/connect-or-start.js.map +1 -0
  21. package/dist/content-park-client.d.ts +49 -0
  22. package/dist/content-park-client.d.ts.map +1 -0
  23. package/dist/content-park-client.js +196 -0
  24. package/dist/content-park-client.js.map +1 -0
  25. package/dist/daemon.d.ts +65 -0
  26. package/dist/daemon.d.ts.map +1 -0
  27. package/dist/daemon.js +3202 -0
  28. package/dist/daemon.js.map +1 -0
  29. package/dist/directory-bootstrap.d.ts +55 -0
  30. package/dist/directory-bootstrap.d.ts.map +1 -0
  31. package/dist/directory-bootstrap.js +102 -0
  32. package/dist/directory-bootstrap.js.map +1 -0
  33. package/dist/file-manifest-provider.d.ts +18 -0
  34. package/dist/file-manifest-provider.d.ts.map +1 -0
  35. package/dist/file-manifest-provider.js +72 -0
  36. package/dist/file-manifest-provider.js.map +1 -0
  37. package/dist/index.d.ts +18 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +18 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/ipc-client.d.ts +31 -0
  42. package/dist/ipc-client.d.ts.map +1 -0
  43. package/dist/ipc-client.js +112 -0
  44. package/dist/ipc-client.js.map +1 -0
  45. package/dist/ipc-server.d.ts +49 -0
  46. package/dist/ipc-server.d.ts.map +1 -0
  47. package/dist/ipc-server.js +268 -0
  48. package/dist/ipc-server.js.map +1 -0
  49. package/dist/lock-file.d.ts +27 -0
  50. package/dist/lock-file.d.ts.map +1 -0
  51. package/dist/lock-file.js +84 -0
  52. package/dist/lock-file.js.map +1 -0
  53. package/dist/manifest-loader.d.ts +33 -0
  54. package/dist/manifest-loader.d.ts.map +1 -0
  55. package/dist/manifest-loader.js +70 -0
  56. package/dist/manifest-loader.js.map +1 -0
  57. package/dist/manifest-poll-scheduler.d.ts +31 -0
  58. package/dist/manifest-poll-scheduler.d.ts.map +1 -0
  59. package/dist/manifest-poll-scheduler.js +59 -0
  60. package/dist/manifest-poll-scheduler.js.map +1 -0
  61. package/dist/manifest-version-store-file.d.ts +18 -0
  62. package/dist/manifest-version-store-file.d.ts.map +1 -0
  63. package/dist/manifest-version-store-file.js +40 -0
  64. package/dist/manifest-version-store-file.js.map +1 -0
  65. package/dist/manifest-version-store.d.ts +14 -0
  66. package/dist/manifest-version-store.d.ts.map +1 -0
  67. package/dist/manifest-version-store.js +13 -0
  68. package/dist/manifest-version-store.js.map +1 -0
  69. package/dist/network-directory-node.d.ts +94 -0
  70. package/dist/network-directory-node.d.ts.map +1 -0
  71. package/dist/network-directory-node.js +626 -0
  72. package/dist/network-directory-node.js.map +1 -0
  73. package/dist/nonce-dedup.d.ts +68 -0
  74. package/dist/nonce-dedup.d.ts.map +1 -0
  75. package/dist/nonce-dedup.js +204 -0
  76. package/dist/nonce-dedup.js.map +1 -0
  77. package/dist/notification-dispatcher.d.ts +65 -0
  78. package/dist/notification-dispatcher.d.ts.map +1 -0
  79. package/dist/notification-dispatcher.js +138 -0
  80. package/dist/notification-dispatcher.js.map +1 -0
  81. package/dist/registration-context.d.ts +69 -0
  82. package/dist/registration-context.d.ts.map +1 -0
  83. package/dist/registration-context.js +118 -0
  84. package/dist/registration-context.js.map +1 -0
  85. package/dist/registration-manager.d.ts +72 -0
  86. package/dist/registration-manager.d.ts.map +1 -0
  87. package/dist/registration-manager.js +267 -0
  88. package/dist/registration-manager.js.map +1 -0
  89. package/dist/registration-persistence.d.ts +131 -0
  90. package/dist/registration-persistence.d.ts.map +1 -0
  91. package/dist/registration-persistence.js +233 -0
  92. package/dist/registration-persistence.js.map +1 -0
  93. package/dist/retry-queue.d.ts +144 -0
  94. package/dist/retry-queue.d.ts.map +1 -0
  95. package/dist/retry-queue.js +444 -0
  96. package/dist/retry-queue.js.map +1 -0
  97. package/dist/seal-frontier-verify.d.ts +58 -0
  98. package/dist/seal-frontier-verify.d.ts.map +1 -0
  99. package/dist/seal-frontier-verify.js +87 -0
  100. package/dist/seal-frontier-verify.js.map +1 -0
  101. package/dist/seal-legibility-tbs.d.ts +25 -0
  102. package/dist/seal-legibility-tbs.d.ts.map +1 -0
  103. package/dist/seal-legibility-tbs.js +78 -0
  104. package/dist/seal-legibility-tbs.js.map +1 -0
  105. package/dist/seal-upgrade.d.ts +90 -0
  106. package/dist/seal-upgrade.d.ts.map +1 -0
  107. package/dist/seal-upgrade.js +178 -0
  108. package/dist/seal-upgrade.js.map +1 -0
  109. package/dist/session-assignment-parser.d.ts +22 -0
  110. package/dist/session-assignment-parser.d.ts.map +1 -0
  111. package/dist/session-assignment-parser.js +139 -0
  112. package/dist/session-assignment-parser.js.map +1 -0
  113. package/dist/session-ceremony.d.ts +156 -0
  114. package/dist/session-ceremony.d.ts.map +1 -0
  115. package/dist/session-ceremony.js +447 -0
  116. package/dist/session-ceremony.js.map +1 -0
  117. package/dist/session-connection-gater.d.ts +91 -0
  118. package/dist/session-connection-gater.d.ts.map +1 -0
  119. package/dist/session-connection-gater.js +146 -0
  120. package/dist/session-connection-gater.js.map +1 -0
  121. package/dist/session-node-manager.d.ts +585 -0
  122. package/dist/session-node-manager.d.ts.map +1 -0
  123. package/dist/session-node-manager.js +2609 -0
  124. package/dist/session-node-manager.js.map +1 -0
  125. package/dist/session-relay-client.d.ts +101 -0
  126. package/dist/session-relay-client.d.ts.map +1 -0
  127. package/dist/session-relay-client.js +520 -0
  128. package/dist/session-relay-client.js.map +1 -0
  129. package/dist/session-tree.d.ts +80 -0
  130. package/dist/session-tree.d.ts.map +1 -0
  131. package/dist/session-tree.js +123 -0
  132. package/dist/session-tree.js.map +1 -0
  133. package/dist/signaling-connect.d.ts +83 -0
  134. package/dist/signaling-connect.d.ts.map +1 -0
  135. package/dist/signaling-connect.js +266 -0
  136. package/dist/signaling-connect.js.map +1 -0
  137. package/dist/transcript-cipher.d.ts +31 -0
  138. package/dist/transcript-cipher.d.ts.map +1 -0
  139. package/dist/transcript-cipher.js +74 -0
  140. package/dist/transcript-cipher.js.map +1 -0
  141. package/dist/transport-composition.d.ts +31 -0
  142. package/dist/transport-composition.d.ts.map +1 -0
  143. package/dist/transport-composition.js +55 -0
  144. package/dist/transport-composition.js.map +1 -0
  145. package/dist/transport-selector.d.ts +189 -0
  146. package/dist/transport-selector.d.ts.map +1 -0
  147. package/dist/transport-selector.js +195 -0
  148. package/dist/transport-selector.js.map +1 -0
  149. package/dist/types.d.ts +265 -0
  150. package/dist/types.d.ts.map +1 -0
  151. package/dist/types.js +33 -0
  152. package/dist/types.js.map +1 -0
  153. package/package.json +4 -4
@@ -0,0 +1,68 @@
1
+ /**
2
+ * CELLO Daemon — NonceDedupStore
3
+ *
4
+ * Per-session LRU set of already-seen incoming nonces. When an incoming message
5
+ * arrives, the daemon checks its nonce here BEFORE delivering to cello_receive.
6
+ * Duplicates are silently discarded.
7
+ *
8
+ * Persistence: SQLCipher table `session_seen_nonces`.
9
+ * Cap: 10,000 nonces per session (LRU eviction).
10
+ *
11
+ * Pseudocode (SPARC Phase P):
12
+ *
13
+ * 1. constructor(db, logger):
14
+ * - Store db handle and logger reference
15
+ * - Initialize empty per-session Map<sessionId, Map<nonceHex, seenAt>>
16
+ * - Create session_seen_nonces table IF NOT EXISTS
17
+ * - Create index on (session_id, seen_at ASC) for LRU eviction
18
+ *
19
+ * 2. loadFromDb():
20
+ * - SELECT all rows from session_seen_nonces ORDER BY session_id, seen_at ASC
21
+ * - Group into per-session Maps of nonceHex → seenAt
22
+ * - This populates the in-memory LRU for duplicate checks
23
+ *
24
+ * 3. has(sessionId, nonce: Uint8Array):
25
+ * - Convert nonce to hex: Buffer.from(nonce).toString('hex')
26
+ * - Return whether the session's set contains this nonceHex
27
+ *
28
+ * 4. add(sessionId, nonce: Uint8Array, senderPubkey: Uint8Array):
29
+ * - Convert to hex strings
30
+ * - If already present: log message.nonce.duplicate DEBUG, return true (is duplicate)
31
+ * - If session set size >= 10,000: LRU evict oldest (lowest seen_at)
32
+ * - DELETE from session_seen_nonces WHERE session_id AND nonce_hex = oldest
33
+ * - Remove from in-memory map
34
+ * - INSERT into session_seen_nonces
35
+ * - Add to in-memory map
36
+ * - Return false (not a duplicate)
37
+ *
38
+ * 5. checkAndAdd(sessionId, nonce: Uint8Array, senderPubkey: Uint8Array):
39
+ * - If has(sessionId, nonce): log duplicate, return true (duplicate)
40
+ * - Otherwise: add, return false (new)
41
+ * - Combined check-and-add for atomic dedup logic
42
+ */
43
+ import type { DatabaseSync } from "node:sqlite";
44
+ import type { Logger } from "./types.js";
45
+ /** LRU cap per outline.md Resource Caps. */
46
+ export declare const NONCE_DEDUP_CAP = 10000;
47
+ export declare class NonceDedupStore {
48
+ #private;
49
+ constructor(db: DatabaseSync, logger: Logger);
50
+ /**
51
+ * Load all nonce entries from SQLCipher into memory.
52
+ * Must complete BEFORE the IPC socket opens (AC-007).
53
+ */
54
+ loadFromDb(): void;
55
+ /**
56
+ * Check if a nonce has been seen for a session.
57
+ */
58
+ has(sessionId: string, nonce: Uint8Array): boolean;
59
+ /**
60
+ * Check if nonce is a duplicate; if not, add it to the store.
61
+ * Returns true if the nonce is a DUPLICATE (should be discarded).
62
+ * Returns false if the nonce is NEW (should be delivered).
63
+ *
64
+ * This is the combined check-and-add for the daemon's inbound message path.
65
+ */
66
+ checkAndAdd(sessionId: string, nonce: Uint8Array, senderPubkey: Uint8Array): boolean;
67
+ }
68
+ //# sourceMappingURL=nonce-dedup.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nonce-dedup.d.ts","sourceRoot":"","sources":["../src/nonce-dedup.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAChD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAEzC,4CAA4C;AAC5C,eAAO,MAAM,eAAe,QAAS,CAAC;AAQtC,qBAAa,eAAe;;gBAUd,EAAE,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM;IAoB5C;;;OAGG;IACH,UAAU,IAAI,IAAI;IA0BlB;;OAEG;IACH,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO;IAOlD;;;;;;OAMG;IACH,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,GAAG,OAAO;CAoGrF"}
@@ -0,0 +1,204 @@
1
+ /**
2
+ * CELLO Daemon — NonceDedupStore
3
+ *
4
+ * Per-session LRU set of already-seen incoming nonces. When an incoming message
5
+ * arrives, the daemon checks its nonce here BEFORE delivering to cello_receive.
6
+ * Duplicates are silently discarded.
7
+ *
8
+ * Persistence: SQLCipher table `session_seen_nonces`.
9
+ * Cap: 10,000 nonces per session (LRU eviction).
10
+ *
11
+ * Pseudocode (SPARC Phase P):
12
+ *
13
+ * 1. constructor(db, logger):
14
+ * - Store db handle and logger reference
15
+ * - Initialize empty per-session Map<sessionId, Map<nonceHex, seenAt>>
16
+ * - Create session_seen_nonces table IF NOT EXISTS
17
+ * - Create index on (session_id, seen_at ASC) for LRU eviction
18
+ *
19
+ * 2. loadFromDb():
20
+ * - SELECT all rows from session_seen_nonces ORDER BY session_id, seen_at ASC
21
+ * - Group into per-session Maps of nonceHex → seenAt
22
+ * - This populates the in-memory LRU for duplicate checks
23
+ *
24
+ * 3. has(sessionId, nonce: Uint8Array):
25
+ * - Convert nonce to hex: Buffer.from(nonce).toString('hex')
26
+ * - Return whether the session's set contains this nonceHex
27
+ *
28
+ * 4. add(sessionId, nonce: Uint8Array, senderPubkey: Uint8Array):
29
+ * - Convert to hex strings
30
+ * - If already present: log message.nonce.duplicate DEBUG, return true (is duplicate)
31
+ * - If session set size >= 10,000: LRU evict oldest (lowest seen_at)
32
+ * - DELETE from session_seen_nonces WHERE session_id AND nonce_hex = oldest
33
+ * - Remove from in-memory map
34
+ * - INSERT into session_seen_nonces
35
+ * - Add to in-memory map
36
+ * - Return false (not a duplicate)
37
+ *
38
+ * 5. checkAndAdd(sessionId, nonce: Uint8Array, senderPubkey: Uint8Array):
39
+ * - If has(sessionId, nonce): log duplicate, return true (duplicate)
40
+ * - Otherwise: add, return false (new)
41
+ * - Combined check-and-add for atomic dedup logic
42
+ */
43
+ /** LRU cap per outline.md Resource Caps. */
44
+ export const NONCE_DEDUP_CAP = 10_000;
45
+ export class NonceDedupStore {
46
+ #db;
47
+ #logger;
48
+ /**
49
+ * Per-session ordered map: nonceHex → NonceEntry.
50
+ * Insertion order approximates LRU (oldest first in iteration).
51
+ * For exact LRU we track seenAt and find the minimum.
52
+ */
53
+ #sessions = new Map();
54
+ constructor(db, logger) {
55
+ this.#db = db;
56
+ this.#logger = logger;
57
+ // Create table + index if not exists (inline migration — not Flyway)
58
+ this.#db.exec(`
59
+ CREATE TABLE IF NOT EXISTS session_seen_nonces (
60
+ session_id TEXT NOT NULL,
61
+ nonce_hex TEXT NOT NULL,
62
+ sender_pubkey TEXT NOT NULL,
63
+ seen_at INTEGER NOT NULL,
64
+ PRIMARY KEY (session_id, nonce_hex)
65
+ )
66
+ `);
67
+ this.#db.exec(`
68
+ CREATE INDEX IF NOT EXISTS seen_nonces_by_session_seen_at
69
+ ON session_seen_nonces(session_id, seen_at ASC)
70
+ `);
71
+ }
72
+ /**
73
+ * Load all nonce entries from SQLCipher into memory.
74
+ * Must complete BEFORE the IPC socket opens (AC-007).
75
+ */
76
+ loadFromDb() {
77
+ const rows = this.#db
78
+ .prepare("SELECT session_id, nonce_hex, sender_pubkey, seen_at FROM session_seen_nonces ORDER BY session_id, seen_at ASC")
79
+ .all();
80
+ this.#sessions.clear();
81
+ for (const row of rows) {
82
+ let sessionMap = this.#sessions.get(row.session_id);
83
+ if (!sessionMap) {
84
+ sessionMap = new Map();
85
+ this.#sessions.set(row.session_id, sessionMap);
86
+ }
87
+ sessionMap.set(row.nonce_hex, {
88
+ nonceHex: row.nonce_hex,
89
+ senderPubkey: row.sender_pubkey,
90
+ seenAt: row.seen_at,
91
+ });
92
+ }
93
+ }
94
+ /**
95
+ * Check if a nonce has been seen for a session.
96
+ */
97
+ has(sessionId, nonce) {
98
+ const nonceHex = Buffer.from(nonce).toString("hex");
99
+ const sessionMap = this.#sessions.get(sessionId);
100
+ if (!sessionMap)
101
+ return false;
102
+ return sessionMap.has(nonceHex);
103
+ }
104
+ /**
105
+ * Check if nonce is a duplicate; if not, add it to the store.
106
+ * Returns true if the nonce is a DUPLICATE (should be discarded).
107
+ * Returns false if the nonce is NEW (should be delivered).
108
+ *
109
+ * This is the combined check-and-add for the daemon's inbound message path.
110
+ */
111
+ checkAndAdd(sessionId, nonce, senderPubkey) {
112
+ const nonceHex = Buffer.from(nonce).toString("hex");
113
+ const senderPubkeyHex = Buffer.from(senderPubkey).toString("hex");
114
+ let sessionMap = this.#sessions.get(sessionId);
115
+ if (!sessionMap) {
116
+ sessionMap = new Map();
117
+ this.#sessions.set(sessionId, sessionMap);
118
+ }
119
+ // Check for duplicate
120
+ if (sessionMap.has(nonceHex)) {
121
+ this.#logger.debug("message.nonce.duplicate", {
122
+ sessionId,
123
+ nonce: nonceHex,
124
+ senderPubkey: senderPubkeyHex,
125
+ });
126
+ return true; // duplicate — discard
127
+ }
128
+ // LRU eviction if at cap
129
+ if (sessionMap.size >= NONCE_DEDUP_CAP) {
130
+ this.#evictOldest(sessionId, sessionMap);
131
+ }
132
+ // Add new nonce
133
+ const seenAt = Date.now();
134
+ const entry = { nonceHex, senderPubkey: senderPubkeyHex, seenAt };
135
+ sessionMap.set(nonceHex, entry);
136
+ // Persist to SQLCipher
137
+ try {
138
+ this.#db
139
+ .prepare(`INSERT INTO session_seen_nonces (session_id, nonce_hex, sender_pubkey, seen_at)
140
+ VALUES (?, ?, ?, ?)`)
141
+ .run(sessionId, nonceHex, senderPubkeyHex, seenAt);
142
+ }
143
+ catch (err) {
144
+ this.#logger.error("message.nonce.persist.failed", {
145
+ sessionId,
146
+ nonce: nonceHex,
147
+ error: err instanceof Error ? err.message : String(err),
148
+ });
149
+ }
150
+ return false; // new — deliver
151
+ }
152
+ /**
153
+ * Evict the oldest entry (lowest seen_at) for a session.
154
+ * Uses the SQLite index on (session_id, seen_at ASC) for O(log n) lookup
155
+ * instead of O(n) in-memory scan.
156
+ */
157
+ #evictOldest(sessionId, sessionMap) {
158
+ // Use indexed query to find the oldest — O(log n) via the seen_at index
159
+ let oldestHex = null;
160
+ try {
161
+ const row = this.#db
162
+ .prepare("SELECT nonce_hex FROM session_seen_nonces WHERE session_id = ? ORDER BY seen_at ASC LIMIT 1")
163
+ .get(sessionId);
164
+ if (row) {
165
+ oldestHex = row.nonce_hex;
166
+ }
167
+ }
168
+ catch (err) {
169
+ this.#logger.error("message.nonce.persist.failed", {
170
+ sessionId,
171
+ nonce: "eviction_query",
172
+ error: err instanceof Error ? err.message : String(err),
173
+ });
174
+ }
175
+ // Fallback: if DB query failed, scan in-memory
176
+ if (!oldestHex) {
177
+ let oldest = null;
178
+ for (const entry of sessionMap.values()) {
179
+ if (!oldest || entry.seenAt < oldest.seenAt) {
180
+ oldest = entry;
181
+ }
182
+ }
183
+ if (!oldest)
184
+ return;
185
+ oldestHex = oldest.nonceHex;
186
+ }
187
+ // Delete from DB
188
+ try {
189
+ this.#db
190
+ .prepare("DELETE FROM session_seen_nonces WHERE session_id = ? AND nonce_hex = ?")
191
+ .run(sessionId, oldestHex);
192
+ }
193
+ catch (err) {
194
+ this.#logger.error("message.nonce.persist.failed", {
195
+ sessionId,
196
+ nonce: oldestHex,
197
+ error: err instanceof Error ? err.message : String(err),
198
+ });
199
+ }
200
+ // Remove from memory
201
+ sessionMap.delete(oldestHex);
202
+ }
203
+ }
204
+ //# sourceMappingURL=nonce-dedup.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"nonce-dedup.js","sourceRoot":"","sources":["../src/nonce-dedup.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,65 @@
1
+ /**
2
+ * CELLO Daemon — NotificationDispatcher
3
+ *
4
+ * Owns the routing table for MCP notifications. Applies per-notification-type
5
+ * routing rules:
6
+ * - agent_state_changed → ALL active IPC connections
7
+ * - agent_current_changed → triggering connection ONLY
8
+ * - session_state_changed → connections where affected agent is current
9
+ *
10
+ * Pseudocode (SPARC Phase P):
11
+ *
12
+ * registerConnection(connectionId, socket):
13
+ * 1. Add entry to routing table: { connectionId → { socket, currentAgent: null } }
14
+ *
15
+ * unregisterConnection(connectionId):
16
+ * 1. Remove entry from routing table
17
+ *
18
+ * setCurrentAgent(connectionId, agentName):
19
+ * 1. Update currentAgent for the connection entry
20
+ *
21
+ * dispatchAgentStateChanged(agentName, state, reason):
22
+ * 1. Build notification: { notification: "agent_state_changed", data: { agent, type, agentName, state, reason } }
23
+ * 2. For each connection in routing table: write notification to socket
24
+ * 3. On write error: log notification.dispatch.failed at DEBUG, discard for that connection
25
+ *
26
+ * dispatchAgentCurrentChanged(connectionId, fromAgent, toAgent):
27
+ * 1. Build notification: { notification: "agent_current_changed", data: { agent: toAgent, type, fromAgent, toAgent } }
28
+ * 2. Write to the ONE connection identified by connectionId
29
+ * 3. On write error: log notification.dispatch.failed at DEBUG
30
+ *
31
+ * dispatchSessionStateChanged(agentName, sessionId, state, counterpartyPubkey):
32
+ * 1. Build notification: { notification: "session_state_changed", data: { agent, type, agentName, sessionId, state, counterpartyPubkey } }
33
+ * 2. For each connection where currentAgent === agentName: write notification
34
+ * 3. On write error: log notification.dispatch.failed at DEBUG, discard for that connection
35
+ */
36
+ import type { Logger, IpcNotification } from "./types.js";
37
+ export type NotificationSender = (connectionId: string, notification: IpcNotification) => boolean;
38
+ export interface NotificationDispatcherConfig {
39
+ logger: Logger;
40
+ sendNotification: NotificationSender;
41
+ getConnectionIds: () => string[];
42
+ }
43
+ export declare class NotificationDispatcher {
44
+ #private;
45
+ constructor(config: NotificationDispatcherConfig);
46
+ registerConnection(connectionId: string): void;
47
+ unregisterConnection(connectionId: string): void;
48
+ setCurrentAgent(connectionId: string, agentName: string | null): void;
49
+ /**
50
+ * Broadcast agent_state_changed to ALL active IPC connections.
51
+ * Routing rule: all connections receive this, including those with no current agent.
52
+ */
53
+ dispatchAgentStateChanged(agentName: string, state: "online" | "offline", reason: string): void;
54
+ /**
55
+ * Send agent_current_changed to the triggering connection ONLY.
56
+ * Routing rule: only the connection that called cello_use_agent receives this.
57
+ */
58
+ dispatchAgentCurrentChanged(connectionId: string, fromAgent: string | null, toAgent: string | null): void;
59
+ /**
60
+ * Send session_state_changed to connections where the affected agent is current.
61
+ * Routing rule: only connections with currentAgent === agentName receive this.
62
+ */
63
+ dispatchSessionStateChanged(agentName: string, sessionId: string, state: string, counterpartyPubkey: string | null): void;
64
+ }
65
+ //# sourceMappingURL=notification-dispatcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification-dispatcher.d.ts","sourceRoot":"","sources":["../src/notification-dispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE1D,MAAM,MAAM,kBAAkB,GAAG,CAAC,YAAY,EAAE,MAAM,EAAE,YAAY,EAAE,eAAe,KAAK,OAAO,CAAC;AAElG,MAAM,WAAW,4BAA4B;IAC3C,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE,kBAAkB,CAAC;IACrC,gBAAgB,EAAE,MAAM,MAAM,EAAE,CAAC;CAClC;AAED,qBAAa,sBAAsB;;gBAOrB,MAAM,EAAE,4BAA4B;IAMhD,kBAAkB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAI9C,oBAAoB,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IAIhD,eAAe,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAMrE;;;OAGG;IACH,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI;IAkB/F;;;OAGG;IACH,2BAA2B,CAAC,YAAY,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAczG;;;OAGG;IACH,2BAA2B,CACzB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,kBAAkB,EAAE,MAAM,GAAG,IAAI,GAChC,IAAI;CAuCR"}
@@ -0,0 +1,138 @@
1
+ /**
2
+ * CELLO Daemon — NotificationDispatcher
3
+ *
4
+ * Owns the routing table for MCP notifications. Applies per-notification-type
5
+ * routing rules:
6
+ * - agent_state_changed → ALL active IPC connections
7
+ * - agent_current_changed → triggering connection ONLY
8
+ * - session_state_changed → connections where affected agent is current
9
+ *
10
+ * Pseudocode (SPARC Phase P):
11
+ *
12
+ * registerConnection(connectionId, socket):
13
+ * 1. Add entry to routing table: { connectionId → { socket, currentAgent: null } }
14
+ *
15
+ * unregisterConnection(connectionId):
16
+ * 1. Remove entry from routing table
17
+ *
18
+ * setCurrentAgent(connectionId, agentName):
19
+ * 1. Update currentAgent for the connection entry
20
+ *
21
+ * dispatchAgentStateChanged(agentName, state, reason):
22
+ * 1. Build notification: { notification: "agent_state_changed", data: { agent, type, agentName, state, reason } }
23
+ * 2. For each connection in routing table: write notification to socket
24
+ * 3. On write error: log notification.dispatch.failed at DEBUG, discard for that connection
25
+ *
26
+ * dispatchAgentCurrentChanged(connectionId, fromAgent, toAgent):
27
+ * 1. Build notification: { notification: "agent_current_changed", data: { agent: toAgent, type, fromAgent, toAgent } }
28
+ * 2. Write to the ONE connection identified by connectionId
29
+ * 3. On write error: log notification.dispatch.failed at DEBUG
30
+ *
31
+ * dispatchSessionStateChanged(agentName, sessionId, state, counterpartyPubkey):
32
+ * 1. Build notification: { notification: "session_state_changed", data: { agent, type, agentName, sessionId, state, counterpartyPubkey } }
33
+ * 2. For each connection where currentAgent === agentName: write notification
34
+ * 3. On write error: log notification.dispatch.failed at DEBUG, discard for that connection
35
+ */
36
+ export class NotificationDispatcher {
37
+ #logger;
38
+ #sendNotification;
39
+ #getConnectionIds;
40
+ // Maps connectionId → currentAgent name (null if not set)
41
+ #currentAgentMap = new Map();
42
+ constructor(config) {
43
+ this.#logger = config.logger;
44
+ this.#sendNotification = config.sendNotification;
45
+ this.#getConnectionIds = config.getConnectionIds;
46
+ }
47
+ registerConnection(connectionId) {
48
+ this.#currentAgentMap.set(connectionId, null);
49
+ }
50
+ unregisterConnection(connectionId) {
51
+ this.#currentAgentMap.delete(connectionId);
52
+ }
53
+ setCurrentAgent(connectionId, agentName) {
54
+ if (this.#currentAgentMap.has(connectionId)) {
55
+ this.#currentAgentMap.set(connectionId, agentName);
56
+ }
57
+ }
58
+ /**
59
+ * Broadcast agent_state_changed to ALL active IPC connections.
60
+ * Routing rule: all connections receive this, including those with no current agent.
61
+ */
62
+ dispatchAgentStateChanged(agentName, state, reason) {
63
+ const notification = {
64
+ notification: "agent_state_changed",
65
+ data: {
66
+ agent: agentName,
67
+ type: "agent_state_changed",
68
+ agentName,
69
+ state,
70
+ reason,
71
+ },
72
+ };
73
+ for (const connectionId of this.#getConnectionIds()) {
74
+ if (!this.#currentAgentMap.has(connectionId))
75
+ continue;
76
+ this.#safeSend(connectionId, notification, "agent_state_changed");
77
+ }
78
+ }
79
+ /**
80
+ * Send agent_current_changed to the triggering connection ONLY.
81
+ * Routing rule: only the connection that called cello_use_agent receives this.
82
+ */
83
+ dispatchAgentCurrentChanged(connectionId, fromAgent, toAgent) {
84
+ const notification = {
85
+ notification: "agent_current_changed",
86
+ data: {
87
+ agent: toAgent,
88
+ type: "agent_current_changed",
89
+ fromAgent,
90
+ toAgent,
91
+ },
92
+ };
93
+ this.#safeSend(connectionId, notification, "agent_current_changed");
94
+ }
95
+ /**
96
+ * Send session_state_changed to connections where the affected agent is current.
97
+ * Routing rule: only connections with currentAgent === agentName receive this.
98
+ */
99
+ dispatchSessionStateChanged(agentName, sessionId, state, counterpartyPubkey) {
100
+ const notification = {
101
+ notification: "session_state_changed",
102
+ data: {
103
+ agent: agentName,
104
+ type: "session_state_changed",
105
+ agentName,
106
+ sessionId,
107
+ state,
108
+ counterpartyPubkey,
109
+ },
110
+ };
111
+ for (const connectionId of this.#getConnectionIds()) {
112
+ const currentAgent = this.#currentAgentMap.get(connectionId);
113
+ if (currentAgent === agentName) {
114
+ this.#safeSend(connectionId, notification, "session_state_changed");
115
+ }
116
+ }
117
+ }
118
+ #safeSend(connectionId, notification, notificationType) {
119
+ try {
120
+ const success = this.#sendNotification(connectionId, notification);
121
+ if (!success) {
122
+ this.#logger.debug("notification.dispatch.failed", {
123
+ connectionId,
124
+ notificationType,
125
+ error: "sendNotification returned false",
126
+ });
127
+ }
128
+ }
129
+ catch (err) {
130
+ this.#logger.debug("notification.dispatch.failed", {
131
+ connectionId,
132
+ notificationType,
133
+ error: err instanceof Error ? err.message : String(err),
134
+ });
135
+ }
136
+ }
137
+ }
138
+ //# sourceMappingURL=notification-dispatcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification-dispatcher.js","sourceRoot":"","sources":["../src/notification-dispatcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,69 @@
1
+ /**
2
+ * DaemonRegistrationContext — CELLO-M7-REGISTRATION (Action 2, step c part 2).
3
+ *
4
+ * Implements the RegistrationManager's RegistrationContext seam against daemon
5
+ * internals. The one non-trivial piece is the signaling bridge: the client wrote
6
+ * directly to a raw persistent libp2p Stream and ran its own read loop; the
7
+ * daemon's directory signaling lives behind SignalingManager. So this context:
8
+ * - sends frames via SignalingManager.sendRaw (which CBOR/length-prefix-encodes),
9
+ * - registers ONE inbound handler that routes the registration reply frames
10
+ * (dkg_ready / register_success / register_error) to whichever pending
11
+ * resolver RegistrationManager.register() has currently armed.
12
+ *
13
+ * register() drives the two stages strictly sequentially (await dkg_ready, then
14
+ * await register_success), so at most one resolver is armed at any moment — which
15
+ * is why a bare register_error can be routed to "whichever stage is waiting".
16
+ */
17
+ import type { CelloNode } from "@cello-protocol/transport";
18
+ import type { IThresholdSigner, KeyProvider } from "@cello-protocol/crypto";
19
+ import type { Logger } from "./types.js";
20
+ import type { DaemonRegistrationPersistence } from "./registration-persistence.js";
21
+ import type { RegistrationContext, SignalingSendResult } from "./registration-manager.js";
22
+ /**
23
+ * Structural slice of SignalingManager this context needs. The real
24
+ * SignalingManager satisfies this (status getter; sendRaw → OperationResult,
25
+ * assignable to SignalingSendResult; registerInboundHandler → unregister fn),
26
+ * and a fake satisfies it in tests.
27
+ */
28
+ export interface SignalingSeam {
29
+ readonly status: string;
30
+ sendRaw(frame: unknown): Promise<SignalingSendResult>;
31
+ registerInboundHandler(handler: (frame: Record<string, unknown>) => void): () => void;
32
+ }
33
+ export declare class DaemonRegistrationContext implements RegistrationContext {
34
+ #private;
35
+ readonly keyProvider: KeyProvider;
36
+ readonly logger: Logger;
37
+ readonly persistence: DaemonRegistrationPersistence | null;
38
+ readonly mlDsaKeyFile: string | undefined;
39
+ constructor(opts: {
40
+ signaling: SignalingSeam;
41
+ getDirectoryNode: () => CelloNode | null;
42
+ getDirectoryEndpoint: () => {
43
+ peer_id: string;
44
+ multiaddrs: string[];
45
+ } | null;
46
+ keyProvider: KeyProvider;
47
+ persistence: DaemonRegistrationPersistence | null;
48
+ logger: Logger;
49
+ mlDsaKeyFile?: string | undefined;
50
+ });
51
+ getNode(): CelloNode | null;
52
+ getMyPubkeyHex(): string | null;
53
+ setMyPubkeyHex(hex: string): void;
54
+ getDirectoryEndpoint(): {
55
+ peer_id: string;
56
+ multiaddrs: string[];
57
+ } | null;
58
+ getThresholdSigner(): IThresholdSigner | undefined;
59
+ setThresholdSigner(signer: IThresholdSigner): void;
60
+ getMyPrimaryPubkey(): Uint8Array | null;
61
+ setMyPrimaryPubkey(pubkey: Uint8Array): void;
62
+ isSignalingConnected(): boolean;
63
+ sendSignalingFrame(frame: Record<string, unknown>): Promise<SignalingSendResult>;
64
+ setPendingDkgReadyResolve(resolve: ((frame: Record<string, unknown>) => void) | null): void;
65
+ setPendingRegisterResolve(resolve: ((frame: Record<string, unknown>) => void) | null): void;
66
+ /** Stop routing inbound frames (call when the owning agent is torn down). */
67
+ dispose(): void;
68
+ }
69
+ //# sourceMappingURL=registration-context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registration-context.d.ts","sourceRoot":"","sources":["../src/registration-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,2BAA2B,CAAC;AAC3D,OAAO,KAAK,EAAE,gBAAgB,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC5E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,+BAA+B,CAAC;AACnF,OAAO,KAAK,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAE1F;;;;;GAKG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACtD,sBAAsB,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,GAAG,MAAM,IAAI,CAAC;CACvF;AAID,qBAAa,yBAA0B,YAAW,mBAAmB;;IACnE,QAAQ,CAAC,WAAW,EAAE,WAAW,CAAC;IAClC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,WAAW,EAAE,6BAA6B,GAAG,IAAI,CAAC;IAC3D,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,SAAS,CAAC;gBAa9B,IAAI,EAAE;QAChB,SAAS,EAAE,aAAa,CAAC;QACzB,gBAAgB,EAAE,MAAM,SAAS,GAAG,IAAI,CAAC;QACzC,oBAAoB,EAAE,MAAM;YAAE,OAAO,EAAE,MAAM,CAAC;YAAC,UAAU,EAAE,MAAM,EAAE,CAAA;SAAE,GAAG,IAAI,CAAC;QAC7E,WAAW,EAAE,WAAW,CAAC;QACzB,WAAW,EAAE,6BAA6B,GAAG,IAAI,CAAC;QAClD,MAAM,EAAE,MAAM,CAAC;QACf,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;KACnC;IAaD,OAAO,IAAI,SAAS,GAAG,IAAI;IAI3B,cAAc,IAAI,MAAM,GAAG,IAAI;IAI/B,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAIjC,oBAAoB,IAAI;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,EAAE,CAAA;KAAE,GAAG,IAAI;IAIxE,kBAAkB,IAAI,gBAAgB,GAAG,SAAS;IAIlD,kBAAkB,CAAC,MAAM,EAAE,gBAAgB,GAAG,IAAI;IAIlD,kBAAkB,IAAI,UAAU,GAAG,IAAI;IAIvC,kBAAkB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI;IAM5C,oBAAoB,IAAI,OAAO;IAIzB,kBAAkB,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAItF,yBAAyB,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI;IAI3F,yBAAyB,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC,GAAG,IAAI,GAAG,IAAI;IAI3F,6EAA6E;IAC7E,OAAO,IAAI,IAAI;CAuChB"}