@synthaer/resonance 0.1.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.
Files changed (94) hide show
  1. package/README.md +19 -0
  2. package/dist/cli.d.ts +9 -0
  3. package/dist/cli.d.ts.map +1 -0
  4. package/dist/cli.js +40 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/config.d.ts +24 -0
  7. package/dist/config.d.ts.map +1 -0
  8. package/dist/config.js +44 -0
  9. package/dist/config.js.map +1 -0
  10. package/dist/contracts.d.ts +4 -0
  11. package/dist/contracts.d.ts.map +1 -0
  12. package/dist/contracts.js +2 -0
  13. package/dist/contracts.js.map +1 -0
  14. package/dist/db/local.d.ts +21 -0
  15. package/dist/db/local.d.ts.map +1 -0
  16. package/dist/db/local.js +158 -0
  17. package/dist/db/local.js.map +1 -0
  18. package/dist/db-types.d.ts +14 -0
  19. package/dist/db-types.d.ts.map +1 -0
  20. package/dist/db-types.js +2 -0
  21. package/dist/db-types.js.map +1 -0
  22. package/dist/dikw-pipeline.d.ts +31 -0
  23. package/dist/dikw-pipeline.d.ts.map +1 -0
  24. package/dist/dikw-pipeline.js +130 -0
  25. package/dist/dikw-pipeline.js.map +1 -0
  26. package/dist/embedding-provider.d.ts +25 -0
  27. package/dist/embedding-provider.d.ts.map +1 -0
  28. package/dist/embedding-provider.js +62 -0
  29. package/dist/embedding-provider.js.map +1 -0
  30. package/dist/embeddings/local.d.ts +31 -0
  31. package/dist/embeddings/local.d.ts.map +1 -0
  32. package/dist/embeddings/local.js +72 -0
  33. package/dist/embeddings/local.js.map +1 -0
  34. package/dist/encryption.d.ts +22 -0
  35. package/dist/encryption.d.ts.map +1 -0
  36. package/dist/encryption.js +39 -0
  37. package/dist/encryption.js.map +1 -0
  38. package/dist/index.d.ts +22 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +15 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/mcp-server.d.ts +362 -0
  43. package/dist/mcp-server.d.ts.map +1 -0
  44. package/dist/mcp-server.js +722 -0
  45. package/dist/mcp-server.js.map +1 -0
  46. package/dist/pki.d.ts +160 -0
  47. package/dist/pki.d.ts.map +1 -0
  48. package/dist/pki.js +502 -0
  49. package/dist/pki.js.map +1 -0
  50. package/dist/ratification.d.ts +125 -0
  51. package/dist/ratification.d.ts.map +1 -0
  52. package/dist/ratification.js +315 -0
  53. package/dist/ratification.js.map +1 -0
  54. package/dist/schema.d.ts +4 -0
  55. package/dist/schema.d.ts.map +1 -0
  56. package/dist/schema.js +119 -0
  57. package/dist/schema.js.map +1 -0
  58. package/dist/search.d.ts +33 -0
  59. package/dist/search.d.ts.map +1 -0
  60. package/dist/search.js +132 -0
  61. package/dist/search.js.map +1 -0
  62. package/dist/server.d.ts +11 -0
  63. package/dist/server.d.ts.map +1 -0
  64. package/dist/server.js +297 -0
  65. package/dist/server.js.map +1 -0
  66. package/dist/store.d.ts +77 -0
  67. package/dist/store.d.ts.map +1 -0
  68. package/dist/store.js +572 -0
  69. package/dist/store.js.map +1 -0
  70. package/dist/tools/cloud-gate.d.ts +72 -0
  71. package/dist/tools/cloud-gate.d.ts.map +1 -0
  72. package/dist/tools/cloud-gate.js +79 -0
  73. package/dist/tools/cloud-gate.js.map +1 -0
  74. package/dist/tools/experiences.d.ts +20 -0
  75. package/dist/tools/experiences.d.ts.map +1 -0
  76. package/dist/tools/experiences.js +135 -0
  77. package/dist/tools/experiences.js.map +1 -0
  78. package/dist/tools/knowledge.d.ts +37 -0
  79. package/dist/tools/knowledge.d.ts.map +1 -0
  80. package/dist/tools/knowledge.js +213 -0
  81. package/dist/tools/knowledge.js.map +1 -0
  82. package/dist/tools/sessions.d.ts +11 -0
  83. package/dist/tools/sessions.d.ts.map +1 -0
  84. package/dist/tools/sessions.js +66 -0
  85. package/dist/tools/sessions.js.map +1 -0
  86. package/dist/tools/trust.d.ts +18 -0
  87. package/dist/tools/trust.d.ts.map +1 -0
  88. package/dist/tools/trust.js +42 -0
  89. package/dist/tools/trust.js.map +1 -0
  90. package/dist/types.d.ts +75 -0
  91. package/dist/types.d.ts.map +1 -0
  92. package/dist/types.js +16 -0
  93. package/dist/types.js.map +1 -0
  94. package/package.json +50 -0
package/dist/pki.js ADDED
@@ -0,0 +1,502 @@
1
+ /**
2
+ * PKI Certificate Chain Integration for Local MCP
3
+ *
4
+ * Trust chain: Hedonistic Root CA -> Synthaer Intermediate CA -> Local MCP Cert -> Agent Certs
5
+ *
6
+ * On first launch:
7
+ * 1. Generate Ed25519 keypair
8
+ * 2. Create CSR (Certificate Signing Request)
9
+ * 3. Send CSR to Synthaer Cloud PKI for signing
10
+ * 4. Receive signed certificate chaining to Synthaer CA
11
+ * 5. Use this cert to sign all local operations
12
+ *
13
+ * Each agent gets its own cert signed by the local cert.
14
+ * All writes go through cloud for ratification (content signed by agent cert -> local cert -> cloud signing key).
15
+ */
16
+ import crypto from 'node:crypto';
17
+ import { readFile, writeFile, mkdir, access, constants } from 'node:fs/promises';
18
+ import { join } from 'node:path';
19
+ // ---------------------------------------------------------------------------
20
+ // Constants
21
+ // ---------------------------------------------------------------------------
22
+ const IDENTITY_DIR = 'identity';
23
+ const AGENTS_DIR = 'agents';
24
+ const PRIVATE_KEY_FILE = 'local.key';
25
+ const PUBLIC_KEY_FILE = 'local.pub';
26
+ const CSR_FILE = 'local.csr';
27
+ const CERT_FILE = 'local.crt';
28
+ const MACHINE_ID_FILE = 'machine-id';
29
+ const AGENT_KEY_FILE = 'agent.key';
30
+ const AGENT_PUB_FILE = 'agent.pub';
31
+ const AGENT_CERT_FILE = 'agent.crt';
32
+ const SIGNING_ALGORITHM = 'Ed25519';
33
+ /** Default validity for local MCP certs (used by cloud during signing). */
34
+ export const CERT_VALIDITY_DAYS = 365;
35
+ const AGENT_CERT_VALIDITY_DAYS = 90;
36
+ // ---------------------------------------------------------------------------
37
+ // File helpers
38
+ // ---------------------------------------------------------------------------
39
+ async function fileExists(path) {
40
+ try {
41
+ await access(path, constants.F_OK);
42
+ return true;
43
+ }
44
+ catch {
45
+ return false;
46
+ }
47
+ }
48
+ async function ensureDir(path) {
49
+ await mkdir(path, { recursive: true });
50
+ }
51
+ // ---------------------------------------------------------------------------
52
+ // Machine ID
53
+ // ---------------------------------------------------------------------------
54
+ async function getOrCreateMachineId(identityDir) {
55
+ const machineIdPath = join(identityDir, MACHINE_ID_FILE);
56
+ if (await fileExists(machineIdPath)) {
57
+ const existing = await readFile(machineIdPath, 'utf-8');
58
+ return existing.trim();
59
+ }
60
+ const machineId = crypto.randomUUID();
61
+ await writeFile(machineIdPath, machineId, { mode: 0o600 });
62
+ return machineId;
63
+ }
64
+ // ---------------------------------------------------------------------------
65
+ // Key generation
66
+ // ---------------------------------------------------------------------------
67
+ function generateEd25519Keypair() {
68
+ const { privateKey, publicKey } = crypto.generateKeyPairSync('ed25519');
69
+ return { privateKey, publicKey };
70
+ }
71
+ function exportPrivateKeyPem(key) {
72
+ return key.export({ type: 'pkcs8', format: 'pem' });
73
+ }
74
+ function exportPublicKeyPem(key) {
75
+ return key.export({ type: 'spki', format: 'pem' });
76
+ }
77
+ function importPrivateKeyPem(pem) {
78
+ return crypto.createPrivateKey({ key: pem, format: 'pem', type: 'pkcs8' });
79
+ }
80
+ function importPublicKeyPem(pem) {
81
+ return crypto.createPublicKey({ key: pem, format: 'pem', type: 'spki' });
82
+ }
83
+ // ---------------------------------------------------------------------------
84
+ // CSR generation
85
+ // ---------------------------------------------------------------------------
86
+ /**
87
+ * Build a CSR-like structure. Node.js does not have a built-in X.509 CSR
88
+ * generator, so we produce a JSON-encoded CSR that contains the public key
89
+ * in SPKI PEM, the machine ID, and a self-signature proving possession of
90
+ * the private key. The cloud PKI endpoint accepts this format.
91
+ */
92
+ export function createCSR(machineId, publicKey, privateKey) {
93
+ const publicKeyPem = exportPublicKeyPem(publicKey);
94
+ const csrPayload = {
95
+ version: 1,
96
+ subject: `CN=local-mcp-${machineId},O=Synthaer User`,
97
+ machineId,
98
+ publicKey: publicKeyPem,
99
+ requestedAt: new Date().toISOString(),
100
+ };
101
+ const payloadBytes = Buffer.from(JSON.stringify(csrPayload), 'utf-8');
102
+ const signature = crypto.sign(null, payloadBytes, privateKey);
103
+ const csr = {
104
+ payload: csrPayload,
105
+ signature: signature.toString('base64'),
106
+ signatureAlgorithm: SIGNING_ALGORITHM,
107
+ };
108
+ return JSON.stringify(csr, null, 2);
109
+ }
110
+ /**
111
+ * Validate that a CSR is self-consistent: the signature matches the
112
+ * public key embedded in the payload.
113
+ */
114
+ export function validateCSR(csrJson) {
115
+ try {
116
+ const csr = JSON.parse(csrJson);
117
+ const publicKey = importPublicKeyPem(csr.payload.publicKey);
118
+ const payloadBytes = Buffer.from(JSON.stringify(csr.payload), 'utf-8');
119
+ const signature = Buffer.from(csr.signature, 'base64');
120
+ return crypto.verify(null, payloadBytes, publicKey, signature);
121
+ }
122
+ catch {
123
+ return false;
124
+ }
125
+ }
126
+ // ---------------------------------------------------------------------------
127
+ // Certificate helpers
128
+ // ---------------------------------------------------------------------------
129
+ /**
130
+ * Compute SHA-256 fingerprint of a PEM-encoded certificate or public key.
131
+ */
132
+ export function computeFingerprint(pem) {
133
+ return crypto.createHash('sha256').update(pem).digest('hex');
134
+ }
135
+ /**
136
+ * Build a locally-signed certificate. This produces a JSON-based certificate
137
+ * structure that can be verified against the signing key. When the cloud PKI
138
+ * issues real X.509 certs, this format will be superseded, but the interface
139
+ * remains the same.
140
+ */
141
+ export function issueCertificate(subject, subjectPublicKey, issuerPrivateKey, issuerSubject, validityDays, extensions) {
142
+ const now = new Date();
143
+ const expiresAt = new Date(now.getTime() + validityDays * 24 * 60 * 60 * 1000);
144
+ const serialNumber = crypto.randomUUID();
145
+ const subjectPem = exportPublicKeyPem(subjectPublicKey);
146
+ const certPayload = {
147
+ version: 1,
148
+ serialNumber,
149
+ subject,
150
+ issuer: issuerSubject,
151
+ publicKey: subjectPem,
152
+ validFrom: now.toISOString(),
153
+ validTo: expiresAt.toISOString(),
154
+ extensions: extensions ?? {},
155
+ fingerprint: computeFingerprint(subjectPem),
156
+ };
157
+ const payloadBytes = Buffer.from(JSON.stringify(certPayload), 'utf-8');
158
+ const signature = crypto.sign(null, payloadBytes, issuerPrivateKey);
159
+ const cert = {
160
+ payload: certPayload,
161
+ signature: signature.toString('base64'),
162
+ signatureAlgorithm: SIGNING_ALGORITHM,
163
+ };
164
+ return JSON.stringify(cert, null, 2);
165
+ }
166
+ /**
167
+ * Parse a certificate and return structured info.
168
+ */
169
+ export function parseCertificate(certJson) {
170
+ try {
171
+ const cert = JSON.parse(certJson);
172
+ return {
173
+ subject: cert.payload.subject,
174
+ issuer: cert.payload.issuer,
175
+ validFrom: cert.payload.validFrom,
176
+ validTo: cert.payload.validTo,
177
+ fingerprint: cert.payload.fingerprint,
178
+ serialNumber: cert.payload.serialNumber,
179
+ };
180
+ }
181
+ catch {
182
+ return null;
183
+ }
184
+ }
185
+ /**
186
+ * Verify a certificate was signed by the given issuer public key.
187
+ */
188
+ export function verifyCertificateSignature(certJson, issuerPublicKey) {
189
+ try {
190
+ const cert = JSON.parse(certJson);
191
+ const payloadBytes = Buffer.from(JSON.stringify(cert.payload), 'utf-8');
192
+ const signature = Buffer.from(cert.signature, 'base64');
193
+ return crypto.verify(null, payloadBytes, issuerPublicKey, signature);
194
+ }
195
+ catch {
196
+ return false;
197
+ }
198
+ }
199
+ /**
200
+ * Check if a certificate is expired.
201
+ */
202
+ export function isCertificateExpired(certJson) {
203
+ const info = parseCertificate(certJson);
204
+ if (!info)
205
+ return true;
206
+ return new Date(info.validTo) < new Date();
207
+ }
208
+ // ---------------------------------------------------------------------------
209
+ // Content signing
210
+ // ---------------------------------------------------------------------------
211
+ /**
212
+ * Sign arbitrary content with a private key. Returns the signature,
213
+ * fingerprint of the signing cert, algorithm, and timestamp.
214
+ */
215
+ export function signContent(content, privateKey, fingerprint) {
216
+ const contentHash = crypto.createHash('sha256').update(content, 'utf-8').digest();
217
+ const signature = crypto.sign(null, contentHash, privateKey);
218
+ return {
219
+ signature: signature.toString('base64'),
220
+ fingerprint,
221
+ algorithm: SIGNING_ALGORITHM,
222
+ timestamp: new Date().toISOString(),
223
+ };
224
+ }
225
+ /**
226
+ * Verify a content signature against a public key.
227
+ */
228
+ export function verifyContentSignature(content, sig, publicKey) {
229
+ try {
230
+ const contentHash = crypto.createHash('sha256').update(content, 'utf-8').digest();
231
+ const signature = Buffer.from(sig.signature, 'base64');
232
+ return crypto.verify(null, contentHash, publicKey, signature);
233
+ }
234
+ catch {
235
+ return false;
236
+ }
237
+ }
238
+ // ---------------------------------------------------------------------------
239
+ // Certificate chain verification
240
+ // ---------------------------------------------------------------------------
241
+ /**
242
+ * Verify a full certificate chain. Each certificate in the chain must be
243
+ * signed by the next certificate's public key. The last certificate in the
244
+ * chain is the root/CA and must be self-signed or trusted.
245
+ *
246
+ * @param chain - Array of JSON certificate strings, from leaf to root
247
+ * @returns true if the entire chain is valid
248
+ */
249
+ export function verifyCertificateChain(chain) {
250
+ if (chain.length === 0)
251
+ return false;
252
+ for (let i = 0; i < chain.length - 1; i++) {
253
+ const current = chain[i];
254
+ const issuer = chain[i + 1];
255
+ if (!current || !issuer)
256
+ return false;
257
+ // Extract issuer's public key
258
+ try {
259
+ const issuerCert = JSON.parse(issuer);
260
+ const issuerPublicKey = importPublicKeyPem(issuerCert.payload.publicKey);
261
+ if (!verifyCertificateSignature(current, issuerPublicKey)) {
262
+ return false;
263
+ }
264
+ }
265
+ catch {
266
+ return false;
267
+ }
268
+ }
269
+ return true;
270
+ }
271
+ // ---------------------------------------------------------------------------
272
+ // PKI initialization
273
+ // ---------------------------------------------------------------------------
274
+ /**
275
+ * Initialize the local PKI identity. On first run, generates a keypair and
276
+ * CSR. On subsequent runs, loads the existing identity. If a signed
277
+ * certificate exists and is not expired, uses it. If expired, the caller
278
+ * should request re-signing.
279
+ */
280
+ export async function initializePKI(config) {
281
+ const identityDir = join(config.dataDir, IDENTITY_DIR);
282
+ await ensureDir(identityDir);
283
+ const privateKeyPath = join(identityDir, PRIVATE_KEY_FILE);
284
+ const publicKeyPath = join(identityDir, PUBLIC_KEY_FILE);
285
+ const csrPath = join(identityDir, CSR_FILE);
286
+ const certPath = join(identityDir, CERT_FILE);
287
+ const machineId = await getOrCreateMachineId(identityDir);
288
+ let privateKey;
289
+ let publicKey;
290
+ if (await fileExists(privateKeyPath)) {
291
+ // Load existing keypair
292
+ const privateKeyPem = await readFile(privateKeyPath, 'utf-8');
293
+ const publicKeyPem = await readFile(publicKeyPath, 'utf-8');
294
+ privateKey = importPrivateKeyPem(privateKeyPem);
295
+ publicKey = importPublicKeyPem(publicKeyPem);
296
+ }
297
+ else {
298
+ // Generate new keypair
299
+ const keypair = generateEd25519Keypair();
300
+ privateKey = keypair.privateKey;
301
+ publicKey = keypair.publicKey;
302
+ await writeFile(privateKeyPath, exportPrivateKeyPem(privateKey), { mode: 0o600 });
303
+ await writeFile(publicKeyPath, exportPublicKeyPem(publicKey), { mode: 0o644 });
304
+ }
305
+ // Generate/load CSR
306
+ let csr;
307
+ if (await fileExists(csrPath)) {
308
+ csr = await readFile(csrPath, 'utf-8');
309
+ }
310
+ else {
311
+ csr = createCSR(machineId, publicKey, privateKey);
312
+ await writeFile(csrPath, csr, { mode: 0o644 });
313
+ }
314
+ // Load certificate if it exists
315
+ let certificate = null;
316
+ let fingerprint = null;
317
+ let issuedAt = null;
318
+ let expiresAt = null;
319
+ if (await fileExists(certPath)) {
320
+ certificate = await readFile(certPath, 'utf-8');
321
+ const info = parseCertificate(certificate);
322
+ if (info) {
323
+ fingerprint = info.fingerprint;
324
+ issuedAt = new Date(info.validFrom);
325
+ expiresAt = new Date(info.validTo);
326
+ // If expired, null out the certificate so caller knows to re-request
327
+ if (isCertificateExpired(certificate)) {
328
+ certificate = null;
329
+ fingerprint = null;
330
+ issuedAt = null;
331
+ expiresAt = null;
332
+ }
333
+ }
334
+ }
335
+ return {
336
+ privateKey,
337
+ publicKey,
338
+ certificate,
339
+ fingerprint,
340
+ machineId,
341
+ csr,
342
+ issuedAt,
343
+ expiresAt,
344
+ };
345
+ }
346
+ // ---------------------------------------------------------------------------
347
+ // Cloud certificate signing
348
+ // ---------------------------------------------------------------------------
349
+ /**
350
+ * Send CSR to the Synthaer Cloud PKI for signing. The cloud validates the
351
+ * CSR, signs with the Synthaer Intermediate CA, and returns the signed
352
+ * certificate in JSON format.
353
+ *
354
+ * @param csr - The CSR string (JSON format from createCSR)
355
+ * @param authToken - JWT from Synthaer Auth
356
+ * @param cloudUrl - Base URL of the cloud PKI (e.g., https://api.synthaer.ai)
357
+ * @param dataDir - Local data directory for saving the signed cert
358
+ * @returns The signed certificate as a JSON string
359
+ */
360
+ export async function requestCertificateSigning(csr, authToken, cloudUrl, dataDir) {
361
+ const csrParsed = JSON.parse(csr);
362
+ const machineId = csrParsed.payload.machineId;
363
+ const response = await fetch(`${cloudUrl}/api/v1/pki/sign-csr`, {
364
+ method: 'POST',
365
+ headers: {
366
+ 'Content-Type': 'application/json',
367
+ 'Authorization': `Bearer ${authToken}`,
368
+ },
369
+ body: JSON.stringify({ csr, machineId }),
370
+ });
371
+ if (!response.ok) {
372
+ const errorText = await response.text();
373
+ throw new Error(`Cloud PKI signing failed (${response.status}): ${errorText}`);
374
+ }
375
+ const result = await response.json();
376
+ const certificate = result.certificate;
377
+ // Save the signed certificate
378
+ const certPath = join(dataDir, IDENTITY_DIR, CERT_FILE);
379
+ await ensureDir(join(dataDir, IDENTITY_DIR));
380
+ await writeFile(certPath, certificate, { mode: 0o644 });
381
+ return certificate;
382
+ }
383
+ /**
384
+ * Fetch the Synthaer CA bundle from the cloud PKI endpoint.
385
+ * This is a public endpoint (no auth required).
386
+ */
387
+ export async function fetchCABundle(cloudUrl) {
388
+ const response = await fetch(`${cloudUrl}/api/v1/pki/ca-bundle`);
389
+ if (!response.ok) {
390
+ const errorText = await response.text();
391
+ throw new Error(`Failed to fetch CA bundle (${response.status}): ${errorText}`);
392
+ }
393
+ return response.json();
394
+ }
395
+ // ---------------------------------------------------------------------------
396
+ // Agent certificate issuance
397
+ // ---------------------------------------------------------------------------
398
+ /**
399
+ * Create a certificate for a specific agent, signed by the local MCP's
400
+ * identity. Each agent gets its own keypair and certificate, stored
401
+ * under {dataDir}/agents/{agentId}/.
402
+ */
403
+ export async function createAgentCertificate(agentId, platform, identity, dataDir) {
404
+ if (!identity.certificate || !identity.fingerprint) {
405
+ throw new Error('Local identity must have a signed certificate before issuing agent certs');
406
+ }
407
+ const agentDir = join(dataDir, AGENTS_DIR, agentId);
408
+ await ensureDir(agentDir);
409
+ const agentKeyPath = join(agentDir, AGENT_KEY_FILE);
410
+ const agentPubPath = join(agentDir, AGENT_PUB_FILE);
411
+ const agentCertPath = join(agentDir, AGENT_CERT_FILE);
412
+ let agentPrivateKey;
413
+ let agentPublicKey;
414
+ // Load or generate agent keypair
415
+ if (await fileExists(agentKeyPath)) {
416
+ const keyPem = await readFile(agentKeyPath, 'utf-8');
417
+ const pubPem = await readFile(agentPubPath, 'utf-8');
418
+ agentPrivateKey = importPrivateKeyPem(keyPem);
419
+ agentPublicKey = importPublicKeyPem(pubPem);
420
+ }
421
+ else {
422
+ const keypair = generateEd25519Keypair();
423
+ agentPrivateKey = keypair.privateKey;
424
+ agentPublicKey = keypair.publicKey;
425
+ await writeFile(agentKeyPath, exportPrivateKeyPem(agentPrivateKey), { mode: 0o600 });
426
+ await writeFile(agentPubPath, exportPublicKeyPem(agentPublicKey), { mode: 0o644 });
427
+ }
428
+ // Extract local identity subject for issuer field
429
+ const localCertInfo = parseCertificate(identity.certificate);
430
+ const issuerSubject = localCertInfo?.subject ?? `CN=local-mcp-${identity.machineId},O=Synthaer User`;
431
+ // Issue agent certificate signed by local identity
432
+ const agentSubject = `CN=agent-${agentId},O=Synthaer Agent,L=${platform}`;
433
+ const certificate = issueCertificate(agentSubject, agentPublicKey, identity.privateKey, issuerSubject, AGENT_CERT_VALIDITY_DAYS, { agentId, platform, parentFingerprint: identity.fingerprint });
434
+ await writeFile(agentCertPath, certificate, { mode: 0o644 });
435
+ const certInfo = parseCertificate(certificate);
436
+ return {
437
+ agentId,
438
+ platform,
439
+ privateKey: agentPrivateKey,
440
+ publicKey: agentPublicKey,
441
+ certificate,
442
+ fingerprint: certInfo?.fingerprint ?? computeFingerprint(exportPublicKeyPem(agentPublicKey)),
443
+ parentFingerprint: identity.fingerprint,
444
+ issuedAt: certInfo ? new Date(certInfo.validFrom) : new Date(),
445
+ expiresAt: certInfo ? new Date(certInfo.validTo) : new Date(Date.now() + AGENT_CERT_VALIDITY_DAYS * 24 * 60 * 60 * 1000),
446
+ };
447
+ }
448
+ /**
449
+ * Load an existing agent identity from disk.
450
+ */
451
+ export async function loadAgentIdentity(agentId, dataDir) {
452
+ const agentDir = join(dataDir, AGENTS_DIR, agentId);
453
+ const agentKeyPath = join(agentDir, AGENT_KEY_FILE);
454
+ const agentPubPath = join(agentDir, AGENT_PUB_FILE);
455
+ const agentCertPath = join(agentDir, AGENT_CERT_FILE);
456
+ if (!(await fileExists(agentKeyPath)) || !(await fileExists(agentCertPath))) {
457
+ return null;
458
+ }
459
+ const keyPem = await readFile(agentKeyPath, 'utf-8');
460
+ const pubPem = await readFile(agentPubPath, 'utf-8');
461
+ const certificate = await readFile(agentCertPath, 'utf-8');
462
+ const privateKey = importPrivateKeyPem(keyPem);
463
+ const publicKey = importPublicKeyPem(pubPem);
464
+ const certInfo = parseCertificate(certificate);
465
+ if (!certInfo)
466
+ return null;
467
+ // Extract agent metadata from cert extensions
468
+ const certParsed = JSON.parse(certificate);
469
+ return {
470
+ agentId: certParsed.payload.extensions.agentId ?? agentId,
471
+ platform: certParsed.payload.extensions.platform ?? 'unknown',
472
+ privateKey,
473
+ publicKey,
474
+ certificate,
475
+ fingerprint: certInfo.fingerprint,
476
+ parentFingerprint: certParsed.payload.extensions.parentFingerprint ?? '',
477
+ issuedAt: new Date(certInfo.validFrom),
478
+ expiresAt: new Date(certInfo.validTo),
479
+ };
480
+ }
481
+ // ---------------------------------------------------------------------------
482
+ // Ratification signing
483
+ // ---------------------------------------------------------------------------
484
+ /**
485
+ * Build a ratification payload: content signed by agent cert, with the
486
+ * local identity cert attached for chain verification.
487
+ */
488
+ export function buildRatificationPayload(content, agentIdentity, localIdentity) {
489
+ if (!localIdentity.certificate || !localIdentity.fingerprint) {
490
+ throw new Error('Local identity must have a signed certificate for ratification');
491
+ }
492
+ const agentSignature = signContent(content, agentIdentity.privateKey, agentIdentity.fingerprint);
493
+ const localSignature = signContent(content, localIdentity.privateKey, localIdentity.fingerprint);
494
+ return {
495
+ content,
496
+ agentSignature,
497
+ localSignature,
498
+ agentCertificate: agentIdentity.certificate,
499
+ localCertificate: localIdentity.certificate,
500
+ };
501
+ }
502
+ //# sourceMappingURL=pki.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pki.js","sourceRoot":"","sources":["../src/pki.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * Ratification Flow — wires PKI signing into the DIKW pipeline.
3
+ *
4
+ * Flow:
5
+ * 1. Agent writes knowledge/experience locally (stored immediately)
6
+ * 2. Content signed by agent cert + local identity cert (dual signatures)
7
+ * 3. Async message queued to Resonance Cloud with both signatures
8
+ * 4. Cloud verifies the chain (agent -> local -> Synthaer CA -> Root)
9
+ * 5. Cloud system-signs with the appropriate CI signer
10
+ * 6. Cloud stores both signatures on the entry
11
+ * 7. SSE notification sent back with cloud ratification signature
12
+ * 8. Local updates its record — entry is now "ratified"
13
+ */
14
+ import type { PKIConfig, LocalIdentity, AgentIdentity, ContentSignature } from './pki.js';
15
+ export type RatificationStatus = 'pending' | 'submitted' | 'ratified' | 'rejected';
16
+ export interface RatificationPayload {
17
+ operation: string;
18
+ contentHash: string;
19
+ agentSignature: ContentSignature;
20
+ localSignature: ContentSignature;
21
+ agentCertificate: string;
22
+ localCertificate: string;
23
+ timestamp: string;
24
+ nonce: string;
25
+ }
26
+ export interface QueueEntry {
27
+ id: string;
28
+ payload: RatificationPayload;
29
+ status: RatificationStatus;
30
+ recordId: string;
31
+ recordTable: string;
32
+ attempts: number;
33
+ lastAttemptAt: string | null;
34
+ nextRetryAt: string | null;
35
+ cloudSignature: ContentSignature | null;
36
+ createdAt: string;
37
+ updatedAt: string;
38
+ errorMessage: string | null;
39
+ }
40
+ export interface RatificationResponse {
41
+ entryId: string;
42
+ status: 'ratified' | 'rejected';
43
+ cloudSignature?: ContentSignature;
44
+ reason?: string;
45
+ }
46
+ export interface RatificationManagerOptions {
47
+ config: PKIConfig;
48
+ localIdentity: LocalIdentity;
49
+ cloudBaseUrl: string;
50
+ authToken: string;
51
+ maxRetries?: number;
52
+ baseRetryDelayMs?: number;
53
+ }
54
+ export interface SignerMapping {
55
+ signer: string;
56
+ layerCode: string;
57
+ }
58
+ /**
59
+ * Map a Resonance MCP operation name to its designated CI signer.
60
+ * Returns null for operations that do not require ratification.
61
+ */
62
+ export declare function mapOperationToSigner(operation: string): SignerMapping | null;
63
+ /**
64
+ * Build the ratification payload sent to cloud. The content itself is NOT
65
+ * included — only its SHA-256 hash, plus the dual signatures and certs.
66
+ */
67
+ export declare function buildRatificationPayload(operation: string, content: string, agentSignature: ContentSignature, localSignature: ContentSignature, agentCertificate: string, localCertificate: string): RatificationPayload;
68
+ export declare class RatificationManager {
69
+ private queue;
70
+ private loaded;
71
+ private readonly config;
72
+ private readonly localIdentity;
73
+ private readonly cloudBaseUrl;
74
+ private readonly authToken;
75
+ private readonly maxRetries;
76
+ private readonly baseRetryDelayMs;
77
+ constructor(options: RatificationManagerOptions);
78
+ /**
79
+ * Load persisted queue from disk. Safe to call multiple times.
80
+ */
81
+ loadQueue(): Promise<void>;
82
+ /**
83
+ * Return a snapshot of the current queue.
84
+ */
85
+ getQueue(): ReadonlyArray<QueueEntry>;
86
+ /**
87
+ * Get a single queue entry by ID.
88
+ */
89
+ getEntry(id: string): QueueEntry | undefined;
90
+ /**
91
+ * Sign content with both agent and local identity certs, build the
92
+ * ratification payload, and add it to the queue for async cloud submission.
93
+ */
94
+ signAndQueue(operation: string, content: string, agentIdentity: AgentIdentity, recordId: string, recordTable: string): Promise<string>;
95
+ /**
96
+ * Process all pending/retryable queue entries by sending them to cloud.
97
+ * Returns the number of entries that were submitted.
98
+ */
99
+ processQueue(): Promise<{
100
+ submitted: number;
101
+ ratified: number;
102
+ rejected: number;
103
+ errors: number;
104
+ }>;
105
+ /**
106
+ * Handle a ratification response (e.g., from SSE push or manual poll).
107
+ * Updates the queue entry and returns whether the entry was found.
108
+ */
109
+ handleRatificationResponse(response: RatificationResponse): boolean;
110
+ /**
111
+ * Persist current queue state to disk.
112
+ */
113
+ persistQueue(): Promise<void>;
114
+ /**
115
+ * Get all entries with a given status.
116
+ */
117
+ getEntriesByStatus(status: RatificationStatus): QueueEntry[];
118
+ /**
119
+ * Remove completed (ratified/rejected) entries older than the given age.
120
+ */
121
+ pruneCompleted(maxAgeMs: number): Promise<number>;
122
+ private applyResponse;
123
+ private submitToCloud;
124
+ }
125
+ //# sourceMappingURL=ratification.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ratification.d.ts","sourceRoot":"","sources":["../src/ratification.ts"],"names":[],"mappings":"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"}