meshsig 0.5.0

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/peers.js ADDED
@@ -0,0 +1,227 @@
1
+ // ============================================================================
2
+ // MeshSig — Peer Networking
3
+ // Connect MeshSig instances across machines/VPS. The mesh grows.
4
+ // ============================================================================
5
+ import { WebSocket } from 'ws';
6
+ import { randomUUID } from 'node:crypto';
7
+ import { EventEmitter } from 'node:events';
8
+ export class PeerNetwork extends EventEmitter {
9
+ peers = new Map();
10
+ registry;
11
+ serverName;
12
+ reconnectTimers = new Map();
13
+ syncInterval = null;
14
+ constructor(registry, serverName) {
15
+ super();
16
+ this.registry = registry;
17
+ this.serverName = serverName;
18
+ // When local agents change, announce to peers
19
+ this.registry.on('mesh-event', (event) => {
20
+ if (event.type === 'agent:register' && event.data?.origin !== 'remote') {
21
+ this.announceAll();
22
+ }
23
+ });
24
+ // Periodic re-announce every 15 seconds to keep agents synced
25
+ this.syncInterval = setInterval(() => this.announceAll(), 15_000);
26
+ }
27
+ // -- Outgoing connections --------------------------------------------------
28
+ connectTo(url) {
29
+ const id = randomUUID().slice(0, 8);
30
+ const wsUrl = url.replace(/^http/, 'ws') + (url.includes('?') ? '&' : '?') + `role=peer&from=${this.serverName}`;
31
+ const ws = new WebSocket(wsUrl);
32
+ const peer = {
33
+ id, url, ws, status: 'connecting', name: null,
34
+ agents: [], connectedAt: new Date().toISOString(),
35
+ };
36
+ ws.on('open', () => {
37
+ peer.status = 'connected';
38
+ this.emit('peer-event', { type: 'peer:connected', data: { url, agents: 0 } });
39
+ this.sendAnnounce(ws);
40
+ });
41
+ ws.on('message', (data) => {
42
+ try {
43
+ const msg = JSON.parse(data.toString());
44
+ this.handlePeerMessage(peer, msg);
45
+ }
46
+ catch { }
47
+ });
48
+ ws.on('close', () => {
49
+ peer.status = 'disconnected';
50
+ this.emit('peer-event', { type: 'peer:disconnected', data: { url } });
51
+ // Auto-reconnect after 5s
52
+ const timer = setTimeout(() => {
53
+ if (this.peers.has(id)) {
54
+ this.peers.delete(id);
55
+ this.connectTo(url);
56
+ }
57
+ }, 5000);
58
+ this.reconnectTimers.set(id, timer);
59
+ });
60
+ ws.on('error', () => { }); // Suppress errors, close handler deals with it
61
+ this.peers.set(id, peer);
62
+ return peer;
63
+ }
64
+ // -- Incoming connections --------------------------------------------------
65
+ handleIncoming(ws, fromName) {
66
+ const id = randomUUID().slice(0, 8);
67
+ const peer = {
68
+ id, url: `incoming:${fromName}`, ws, status: 'connected',
69
+ name: fromName, agents: [], connectedAt: new Date().toISOString(),
70
+ };
71
+ this.emit('peer-event', { type: 'peer:connected', data: { url: `incoming:${fromName}`, agents: 0 } });
72
+ ws.on('message', (data) => {
73
+ try {
74
+ const msg = JSON.parse(data.toString());
75
+ this.handlePeerMessage(peer, msg);
76
+ }
77
+ catch { }
78
+ });
79
+ ws.on('close', () => {
80
+ this.peers.delete(id);
81
+ this.emit('peer-event', { type: 'peer:disconnected', data: { url: peer.url } });
82
+ });
83
+ this.peers.set(id, peer);
84
+ this.sendAnnounce(ws);
85
+ }
86
+ // -- Protocol --------------------------------------------------------------
87
+ sendAnnounce(ws) {
88
+ // Only announce LOCAL agents — don't re-broadcast remote ones
89
+ const agents = this.registry.listAgents('active').filter(a => a.origin === 'local');
90
+ ws.send(JSON.stringify({
91
+ type: 'peer:announce',
92
+ serverName: this.serverName,
93
+ agents: agents.map(a => ({
94
+ did: a.did, name: a.displayName, displayName: a.displayName,
95
+ capabilities: a.capabilities, publicKey: a.publicKey,
96
+ trustScore: a.trustScore,
97
+ })),
98
+ }));
99
+ }
100
+ announceAll() {
101
+ for (const [, peer] of this.peers) {
102
+ if (peer.status === 'connected' && peer.ws.readyState === WebSocket.OPEN) {
103
+ this.sendAnnounce(peer.ws);
104
+ }
105
+ }
106
+ }
107
+ handlePeerMessage(peer, msg) {
108
+ switch (msg.type) {
109
+ case 'peer:announce': {
110
+ peer.name = msg.serverName;
111
+ peer.agents = (msg.agents || []).map((a) => a.did);
112
+ // Import remote agents into local registry — this is what makes them
113
+ // appear on the dashboard. Every agent from every connected server
114
+ // becomes visible in the unified network view.
115
+ let imported = 0;
116
+ for (const agent of msg.agents || []) {
117
+ const existing = this.registry.getAgent(agent.did);
118
+ if (!existing) {
119
+ this.registry.importRemoteAgent({
120
+ did: agent.did,
121
+ name: agent.name || agent.displayName,
122
+ publicKey: agent.publicKey,
123
+ capabilities: agent.capabilities || [],
124
+ originServer: msg.serverName || peer.url,
125
+ });
126
+ imported++;
127
+ }
128
+ else if (existing.origin === 'remote') {
129
+ // Touch to keep alive
130
+ this.registry.touchAgent(agent.did);
131
+ }
132
+ }
133
+ this.emit('peer-event', {
134
+ type: 'peer:connected',
135
+ data: {
136
+ url: peer.url, agents: peer.agents.length,
137
+ name: msg.serverName, imported,
138
+ },
139
+ });
140
+ break;
141
+ }
142
+ case 'peer:discover': {
143
+ const results = this.registry.discover(msg.query || {});
144
+ peer.ws.send(JSON.stringify({
145
+ type: 'peer:discover:result',
146
+ requestId: msg.requestId,
147
+ agents: results,
148
+ }));
149
+ break;
150
+ }
151
+ case 'peer:message': {
152
+ // Relay signed message to local dashboard/handlers
153
+ this.emit('peer-message', msg);
154
+ break;
155
+ }
156
+ }
157
+ }
158
+ // -- Routing ---------------------------------------------------------------
159
+ /**
160
+ * Try to route a message to a remote agent on a connected peer.
161
+ */
162
+ routeToRemote(toDid, payload) {
163
+ for (const [, peer] of this.peers) {
164
+ if (peer.status === 'connected' && peer.agents.includes(toDid)) {
165
+ peer.ws.send(JSON.stringify({
166
+ type: 'peer:message',
167
+ toDid,
168
+ payload,
169
+ }));
170
+ return true;
171
+ }
172
+ }
173
+ return false;
174
+ }
175
+ /**
176
+ * Query all peers for discovery.
177
+ */
178
+ async discoverRemote(query, timeoutMs = 3000) {
179
+ const requestId = randomUUID();
180
+ const results = [];
181
+ const promises = [...this.peers.values()]
182
+ .filter(p => p.status === 'connected' && p.ws.readyState === WebSocket.OPEN)
183
+ .map(peer => new Promise((resolve) => {
184
+ const timer = setTimeout(() => resolve([]), timeoutMs);
185
+ const handler = (data) => {
186
+ try {
187
+ const msg = JSON.parse(data.toString());
188
+ if (msg.type === 'peer:discover:result' && msg.requestId === requestId) {
189
+ clearTimeout(timer);
190
+ peer.ws.off('message', handler);
191
+ resolve(msg.agents || []);
192
+ }
193
+ }
194
+ catch { }
195
+ };
196
+ peer.ws.on('message', handler);
197
+ peer.ws.send(JSON.stringify({ type: 'peer:discover', requestId, query }));
198
+ }));
199
+ const settled = await Promise.allSettled(promises);
200
+ for (const r of settled) {
201
+ if (r.status === 'fulfilled')
202
+ results.push(...r.value);
203
+ }
204
+ return results;
205
+ }
206
+ // -- Info ------------------------------------------------------------------
207
+ listPeers() {
208
+ return [...this.peers.values()].map(({ ws, ...info }) => info);
209
+ }
210
+ getConnectedCount() {
211
+ return [...this.peers.values()].filter(p => p.status === 'connected').length;
212
+ }
213
+ // -- Cleanup ---------------------------------------------------------------
214
+ close() {
215
+ if (this.syncInterval)
216
+ clearInterval(this.syncInterval);
217
+ for (const [, timer] of this.reconnectTimers)
218
+ clearTimeout(timer);
219
+ for (const [, peer] of this.peers) {
220
+ try {
221
+ peer.ws.close();
222
+ }
223
+ catch { }
224
+ }
225
+ }
226
+ }
227
+ //# sourceMappingURL=peers.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"peers.js","sourceRoot":"","sources":["../src/peers.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import type { AgentIdentity, Capability } from './crypto.js';
3
+ export interface AgentRecord {
4
+ id: string;
5
+ did: string;
6
+ publicKey: string;
7
+ displayName: string;
8
+ capabilities: Capability[];
9
+ status: string;
10
+ lastSeenAt: string | null;
11
+ trustScore: number;
12
+ interactionsTotal: number;
13
+ interactionsSuccess: number;
14
+ online: boolean;
15
+ origin: string;
16
+ originServer: string;
17
+ metadata: Record<string, unknown>;
18
+ createdAt: string;
19
+ }
20
+ export interface ConnectionRecord {
21
+ id: string;
22
+ agentADid: string;
23
+ agentBDid: string;
24
+ channelId: string;
25
+ status: string;
26
+ trustScore: number;
27
+ messagesExchanged: number;
28
+ createdAt: string;
29
+ }
30
+ export interface MeshEvent {
31
+ type: string;
32
+ timestamp: string;
33
+ data: any;
34
+ }
35
+ export declare class Registry extends EventEmitter {
36
+ private db;
37
+ constructor(dbPath?: string);
38
+ private emit_event;
39
+ registerAgent(name: string, capabilities?: Capability[], meta?: Record<string, unknown>): Promise<{
40
+ identity: AgentIdentity;
41
+ record: AgentRecord;
42
+ }>;
43
+ /**
44
+ * Import a remote agent from a peer server.
45
+ * No keypair generated — just stores the public identity.
46
+ */
47
+ importRemoteAgent(agent: {
48
+ did: string;
49
+ name: string;
50
+ publicKey: string;
51
+ capabilities: Capability[];
52
+ originServer: string;
53
+ }): AgentRecord | null;
54
+ getAgent(did: string): AgentRecord | null;
55
+ listAgents(status?: string): AgentRecord[];
56
+ touchAgent(did: string): void;
57
+ discover(query: {
58
+ capability?: string;
59
+ minConfidence?: number;
60
+ limit?: number;
61
+ }): AgentRecord[];
62
+ createConnection(agentADid: string, agentBDid: string): ConnectionRecord;
63
+ getConnections(did?: string): ConnectionRecord[];
64
+ logMessage(fromDid: string, toDid: string, content: string, signature: string, verified: boolean): void;
65
+ getMessages(limit?: number): any[];
66
+ /**
67
+ * Record a trust event between agents (positive or negative).
68
+ */
69
+ recordTrustEvent(fromDid: string, toDid: string, type: string, delta: number, reason: string): void;
70
+ /**
71
+ * Get trust history for an agent.
72
+ */
73
+ getTrustHistory(did: string, limit?: number): any[];
74
+ /**
75
+ * Check if agent is online (seen in last 30 seconds).
76
+ */
77
+ isOnline(did: string): boolean;
78
+ stats(): Record<string, number>;
79
+ snapshot(): {
80
+ agents: AgentRecord[];
81
+ connections: ConnectionRecord[];
82
+ };
83
+ close(): void;
84
+ private _rowToAgent;
85
+ }
@@ -0,0 +1,311 @@
1
+ // ============================================================================
2
+ // MeshSig — Registry with Event Emission
3
+ // Every mutation emits an event for live visualization.
4
+ // ============================================================================
5
+ import Database from 'better-sqlite3';
6
+ import { randomUUID } from 'node:crypto';
7
+ import { EventEmitter } from 'node:events';
8
+ import { generateIdentity } from './crypto.js';
9
+ const SCHEMA = `
10
+ CREATE TABLE IF NOT EXISTS agents (
11
+ id TEXT PRIMARY KEY, did TEXT UNIQUE NOT NULL, public_key TEXT NOT NULL,
12
+ display_name TEXT NOT NULL, capabilities TEXT NOT NULL DEFAULT '[]',
13
+ status TEXT NOT NULL DEFAULT 'active', last_seen_at TEXT,
14
+ trust_score REAL NOT NULL DEFAULT 0.0,
15
+ interactions_total INTEGER NOT NULL DEFAULT 0,
16
+ interactions_success INTEGER NOT NULL DEFAULT 0,
17
+ origin TEXT NOT NULL DEFAULT 'local',
18
+ origin_server TEXT NOT NULL DEFAULT '',
19
+ metadata TEXT NOT NULL DEFAULT '{}', created_at TEXT NOT NULL, updated_at TEXT NOT NULL
20
+ );
21
+ CREATE TABLE IF NOT EXISTS connections (
22
+ id TEXT PRIMARY KEY, agent_a_did TEXT NOT NULL, agent_b_did TEXT NOT NULL,
23
+ channel_id TEXT UNIQUE NOT NULL, status TEXT NOT NULL DEFAULT 'active',
24
+ trust_score REAL NOT NULL DEFAULT 0.0,
25
+ messages_exchanged INTEGER NOT NULL DEFAULT 0,
26
+ created_at TEXT NOT NULL, UNIQUE(agent_a_did, agent_b_did),
27
+ FOREIGN KEY (agent_a_did) REFERENCES agents(did) ON DELETE CASCADE,
28
+ FOREIGN KEY (agent_b_did) REFERENCES agents(did) ON DELETE CASCADE
29
+ );
30
+ CREATE TABLE IF NOT EXISTS messages (
31
+ id INTEGER PRIMARY KEY AUTOINCREMENT, from_did TEXT NOT NULL, to_did TEXT NOT NULL,
32
+ content TEXT NOT NULL, signature TEXT NOT NULL, verified INTEGER NOT NULL DEFAULT 0,
33
+ created_at TEXT NOT NULL
34
+ );
35
+ CREATE TABLE IF NOT EXISTS trust_events (
36
+ id INTEGER PRIMARY KEY AUTOINCREMENT,
37
+ from_did TEXT NOT NULL, to_did TEXT NOT NULL,
38
+ event_type TEXT NOT NULL,
39
+ score_delta REAL NOT NULL,
40
+ reason TEXT,
41
+ created_at TEXT NOT NULL
42
+ );
43
+ CREATE TABLE IF NOT EXISTS audit_log (
44
+ id INTEGER PRIMARY KEY AUTOINCREMENT, event_type TEXT NOT NULL, agent_did TEXT NOT NULL,
45
+ target_did TEXT, payload_hash TEXT NOT NULL, signature TEXT NOT NULL,
46
+ metadata TEXT NOT NULL DEFAULT '{}', created_at TEXT NOT NULL
47
+ );
48
+ CREATE INDEX IF NOT EXISTS idx_agents_did ON agents(did);
49
+ CREATE INDEX IF NOT EXISTS idx_agents_status ON agents(status);
50
+ CREATE INDEX IF NOT EXISTS idx_connections_a ON connections(agent_a_did);
51
+ CREATE INDEX IF NOT EXISTS idx_connections_b ON connections(agent_b_did);
52
+ CREATE INDEX IF NOT EXISTS idx_messages_time ON messages(created_at DESC);
53
+ CREATE INDEX IF NOT EXISTS idx_trust_from ON trust_events(from_did, created_at DESC);
54
+ CREATE INDEX IF NOT EXISTS idx_trust_to ON trust_events(to_did, created_at DESC);
55
+ `;
56
+ export class Registry extends EventEmitter {
57
+ db;
58
+ constructor(dbPath = ':memory:') {
59
+ super();
60
+ this.db = new Database(dbPath);
61
+ this.db.pragma('journal_mode = WAL');
62
+ this.db.pragma('foreign_keys = ON');
63
+ this.db.exec(SCHEMA);
64
+ // Migrate existing databases — add new columns if missing
65
+ try {
66
+ this.db.exec('ALTER TABLE agents ADD COLUMN origin TEXT NOT NULL DEFAULT \'local\'');
67
+ }
68
+ catch { }
69
+ try {
70
+ this.db.exec('ALTER TABLE agents ADD COLUMN origin_server TEXT NOT NULL DEFAULT \'\'');
71
+ }
72
+ catch { }
73
+ try {
74
+ this.db.exec('ALTER TABLE connections ADD COLUMN trust_score REAL NOT NULL DEFAULT 0.0');
75
+ }
76
+ catch { }
77
+ try {
78
+ this.db.exec('ALTER TABLE connections ADD COLUMN messages_exchanged INTEGER NOT NULL DEFAULT 0');
79
+ }
80
+ catch { }
81
+ try {
82
+ this.db.exec('ALTER TABLE agents ADD COLUMN trust_score REAL NOT NULL DEFAULT 0.0');
83
+ }
84
+ catch { }
85
+ try {
86
+ this.db.exec('ALTER TABLE agents ADD COLUMN interactions_total INTEGER NOT NULL DEFAULT 0');
87
+ }
88
+ catch { }
89
+ try {
90
+ this.db.exec('ALTER TABLE agents ADD COLUMN interactions_success INTEGER NOT NULL DEFAULT 0');
91
+ }
92
+ catch { }
93
+ }
94
+ emit_event(type, data) {
95
+ const event = { type, timestamp: new Date().toISOString(), data };
96
+ this.emit('mesh-event', event);
97
+ }
98
+ // -- Agents ----------------------------------------------------------------
99
+ async registerAgent(name, capabilities = [], meta) {
100
+ const identity = await generateIdentity();
101
+ const now = new Date().toISOString();
102
+ const id = randomUUID();
103
+ this.db.prepare(`
104
+ INSERT INTO agents (id, did, public_key, display_name, capabilities, status, last_seen_at, origin, origin_server, metadata, created_at, updated_at)
105
+ VALUES (?, ?, ?, ?, ?, 'active', ?, 'local', '', ?, ?, ?)
106
+ `).run(id, identity.did, identity.publicKey, name, JSON.stringify(capabilities), now, JSON.stringify(meta || {}), now, now);
107
+ const record = this._rowToAgent(this.db.prepare('SELECT * FROM agents WHERE did = ?').get(identity.did));
108
+ this.emit_event('agent:register', {
109
+ did: identity.did, name, capabilities,
110
+ publicKey: identity.publicKey,
111
+ origin: 'local',
112
+ });
113
+ return { identity, record };
114
+ }
115
+ /**
116
+ * Import a remote agent from a peer server.
117
+ * No keypair generated — just stores the public identity.
118
+ */
119
+ importRemoteAgent(agent) {
120
+ const existing = this.getAgent(agent.did);
121
+ if (existing) {
122
+ // Update last seen and origin
123
+ const now = new Date().toISOString();
124
+ this.db.prepare(`
125
+ UPDATE agents SET last_seen_at = ?, origin = 'remote', origin_server = ?, updated_at = ?, status = 'active'
126
+ WHERE did = ?
127
+ `).run(now, agent.originServer, now, agent.did);
128
+ return this.getAgent(agent.did);
129
+ }
130
+ const now = new Date().toISOString();
131
+ const id = randomUUID();
132
+ this.db.prepare(`
133
+ INSERT INTO agents (id, did, public_key, display_name, capabilities, status, last_seen_at, origin, origin_server, metadata, created_at, updated_at)
134
+ VALUES (?, ?, ?, ?, ?, 'active', ?, 'remote', ?, '{}', ?, ?)
135
+ `).run(id, agent.did, agent.publicKey, agent.name, JSON.stringify(agent.capabilities), now, agent.originServer, now, now);
136
+ const record = this._rowToAgent(this.db.prepare('SELECT * FROM agents WHERE did = ?').get(agent.did));
137
+ this.emit_event('agent:register', {
138
+ did: agent.did, name: agent.name, capabilities: agent.capabilities,
139
+ publicKey: agent.publicKey,
140
+ origin: 'remote', originServer: agent.originServer,
141
+ });
142
+ return record;
143
+ }
144
+ getAgent(did) {
145
+ const row = this.db.prepare('SELECT * FROM agents WHERE did = ?').get(did);
146
+ return row ? this._rowToAgent(row) : null;
147
+ }
148
+ listAgents(status) {
149
+ const q = status
150
+ ? this.db.prepare('SELECT * FROM agents WHERE status = ? ORDER BY created_at')
151
+ : this.db.prepare('SELECT * FROM agents ORDER BY created_at');
152
+ return (status ? q.all(status) : q.all()).map((r) => this._rowToAgent(r));
153
+ }
154
+ touchAgent(did) {
155
+ const now = new Date().toISOString();
156
+ this.db.prepare('UPDATE agents SET last_seen_at = ?, updated_at = ? WHERE did = ?').run(now, now, did);
157
+ this.emit_event('agent:heartbeat', { did, timestamp: now });
158
+ }
159
+ // -- Discovery -------------------------------------------------------------
160
+ discover(query) {
161
+ let agents = this.listAgents('active');
162
+ if (query.capability) {
163
+ agents = agents.filter(a => a.capabilities.some(c => c.type === query.capability && (c.confidence ?? 1) >= (query.minConfidence ?? 0)));
164
+ }
165
+ return query.limit ? agents.slice(0, query.limit) : agents;
166
+ }
167
+ // -- Connections -----------------------------------------------------------
168
+ createConnection(agentADid, agentBDid) {
169
+ const id = randomUUID();
170
+ const channelId = randomUUID();
171
+ const now = new Date().toISOString();
172
+ this.db.prepare(`
173
+ INSERT INTO connections (id, agent_a_did, agent_b_did, channel_id, status, trust_score, messages_exchanged, created_at)
174
+ VALUES (?, ?, ?, ?, 'active', 0.0, 0, ?)
175
+ `).run(id, agentADid, agentBDid, channelId, now);
176
+ const conn = { id, agentADid, agentBDid, channelId, status: 'active', trustScore: 0, messagesExchanged: 0, createdAt: now };
177
+ const agentA = this.getAgent(agentADid);
178
+ const agentB = this.getAgent(agentBDid);
179
+ this.emit_event('connection:established', {
180
+ channelId,
181
+ agentA: { did: agentADid, name: agentA?.displayName },
182
+ agentB: { did: agentBDid, name: agentB?.displayName },
183
+ });
184
+ return conn;
185
+ }
186
+ getConnections(did) {
187
+ const q = did
188
+ ? this.db.prepare('SELECT * FROM connections WHERE (agent_a_did = ? OR agent_b_did = ?) AND status = ?')
189
+ : this.db.prepare('SELECT * FROM connections WHERE status = ?');
190
+ const rows = did ? q.all(did, did, 'active') : q.all('active');
191
+ return rows.map(r => ({
192
+ id: r.id, agentADid: r.agent_a_did, agentBDid: r.agent_b_did,
193
+ channelId: r.channel_id, status: r.status, trustScore: r.trust_score || 0,
194
+ messagesExchanged: r.messages_exchanged || 0, createdAt: r.created_at,
195
+ }));
196
+ }
197
+ // -- Messages --------------------------------------------------------------
198
+ logMessage(fromDid, toDid, content, signature, verified) {
199
+ const now = new Date().toISOString();
200
+ this.db.prepare(`
201
+ INSERT INTO messages (from_did, to_did, content, signature, verified, created_at)
202
+ VALUES (?, ?, ?, ?, ?, ?)
203
+ `).run(fromDid, toDid, content, signature, verified ? 1 : 0, now);
204
+ // Update connection message count and trust
205
+ this.db.prepare(`
206
+ UPDATE connections SET messages_exchanged = messages_exchanged + 1,
207
+ trust_score = MIN(1.0, trust_score + CASE WHEN ? THEN 0.02 ELSE -0.05 END)
208
+ WHERE ((agent_a_did = ? AND agent_b_did = ?) OR (agent_a_did = ? AND agent_b_did = ?))
209
+ AND status = 'active'
210
+ `).run(verified ? 1 : 0, fromDid, toDid, toDid, fromDid);
211
+ // Update sender agent trust
212
+ this.db.prepare(`
213
+ UPDATE agents SET interactions_total = interactions_total + 1,
214
+ interactions_success = interactions_success + CASE WHEN ? THEN 1 ELSE 0 END,
215
+ trust_score = CAST(interactions_success + CASE WHEN ? THEN 1 ELSE 0 END AS REAL) / (interactions_total + 1)
216
+ WHERE did = ?
217
+ `).run(verified ? 1 : 0, verified ? 1 : 0, fromDid);
218
+ // Log trust event
219
+ if (verified) {
220
+ this.db.prepare(`
221
+ INSERT INTO trust_events (from_did, to_did, event_type, score_delta, reason, created_at)
222
+ VALUES (?, ?, 'message:verified', 0.02, 'Verified signed message', ?)
223
+ `).run(fromDid, toDid, now);
224
+ }
225
+ const fromAgent = this.getAgent(fromDid);
226
+ const toAgent = this.getAgent(toDid);
227
+ this.emit_event('message:sent', {
228
+ from: { did: fromDid, name: fromAgent?.displayName, trustScore: fromAgent?.trustScore },
229
+ to: { did: toDid, name: toAgent?.displayName, trustScore: toAgent?.trustScore },
230
+ preview: content.slice(0, 80),
231
+ verified,
232
+ signature: signature.slice(0, 20) + '...',
233
+ });
234
+ }
235
+ getMessages(limit = 50) {
236
+ return this.db.prepare('SELECT * FROM messages ORDER BY created_at DESC LIMIT ?').all(limit);
237
+ }
238
+ // -- Trust Scoring ---------------------------------------------------------
239
+ /**
240
+ * Record a trust event between agents (positive or negative).
241
+ */
242
+ recordTrustEvent(fromDid, toDid, type, delta, reason) {
243
+ const now = new Date().toISOString();
244
+ this.db.prepare(`
245
+ INSERT INTO trust_events (from_did, to_did, event_type, score_delta, reason, created_at)
246
+ VALUES (?, ?, ?, ?, ?, ?)
247
+ `).run(fromDid, toDid, type, delta, reason, now);
248
+ // Update connection trust
249
+ this.db.prepare(`
250
+ UPDATE connections SET trust_score = MAX(0, MIN(1.0, trust_score + ?))
251
+ WHERE ((agent_a_did = ? AND agent_b_did = ?) OR (agent_a_did = ? AND agent_b_did = ?))
252
+ AND status = 'active'
253
+ `).run(delta, fromDid, toDid, toDid, fromDid);
254
+ this.emit_event('trust:update', {
255
+ from: fromDid, to: toDid, type, delta, reason,
256
+ fromName: this.getAgent(fromDid)?.displayName,
257
+ toName: this.getAgent(toDid)?.displayName,
258
+ });
259
+ }
260
+ /**
261
+ * Get trust history for an agent.
262
+ */
263
+ getTrustHistory(did, limit = 20) {
264
+ return this.db.prepare(`
265
+ SELECT * FROM trust_events WHERE from_did = ? OR to_did = ? ORDER BY created_at DESC LIMIT ?
266
+ `).all(did, did, limit);
267
+ }
268
+ // -- Heartbeat (online detection) ------------------------------------------
269
+ /**
270
+ * Check if agent is online (seen in last 30 seconds).
271
+ */
272
+ isOnline(did) {
273
+ const agent = this.getAgent(did);
274
+ if (!agent || !agent.lastSeenAt)
275
+ return false;
276
+ return (Date.now() - new Date(agent.lastSeenAt).getTime()) < 30_000;
277
+ }
278
+ // -- Stats -----------------------------------------------------------------
279
+ stats() {
280
+ const agents = this.db.prepare("SELECT COUNT(*) as n FROM agents").get().n;
281
+ const active = this.db.prepare("SELECT COUNT(*) as n FROM agents WHERE status='active'").get().n;
282
+ const connections = this.db.prepare("SELECT COUNT(*) as n FROM connections WHERE status='active'").get().n;
283
+ const messages = this.db.prepare("SELECT COUNT(*) as n FROM messages").get().n;
284
+ return { agents, active, connections, messages };
285
+ }
286
+ // -- Snapshot (full state for dashboard) -----------------------------------
287
+ snapshot() {
288
+ return {
289
+ agents: this.listAgents('active'),
290
+ connections: this.getConnections(),
291
+ };
292
+ }
293
+ close() { this.db.close(); }
294
+ _rowToAgent(row) {
295
+ const lastSeen = row.last_seen_at;
296
+ const online = lastSeen ? (Date.now() - new Date(lastSeen).getTime()) < 30_000 : false;
297
+ return {
298
+ id: row.id, did: row.did, publicKey: row.public_key,
299
+ displayName: row.display_name, capabilities: JSON.parse(row.capabilities),
300
+ status: row.status, lastSeenAt: lastSeen,
301
+ trustScore: row.trust_score || 0,
302
+ interactionsTotal: row.interactions_total || 0,
303
+ interactionsSuccess: row.interactions_success || 0,
304
+ online,
305
+ origin: row.origin || 'local',
306
+ originServer: row.origin_server || '',
307
+ metadata: JSON.parse(row.metadata), createdAt: row.created_at,
308
+ };
309
+ }
310
+ }
311
+ //# sourceMappingURL=registry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"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"}