@wipcomputer/wip-ldm-os 0.4.85-alpha.10 → 0.4.85-alpha.12

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wipcomputer/wip-ldm-os",
3
- "version": "0.4.85-alpha.10",
3
+ "version": "0.4.85-alpha.12",
4
4
  "type": "module",
5
5
  "description": "LDM OS: identity, memory, and sovereignty infrastructure for AI agents",
6
6
  "engines": {
@@ -1,80 +1,148 @@
1
1
  import { readFileSync } from "node:fs";
2
+ import {
3
+ buildCodexBootstrapPayload,
4
+ createCodexDaemonPubkeyRegistry,
5
+ } from "../src/hosted-mcp/codex-relay-e2ee-registry.mjs";
2
6
 
3
7
  const server = readFileSync("src/hosted-mcp/server.mjs", "utf8");
8
+ const registrySource = readFileSync("src/hosted-mcp/codex-relay-e2ee-registry.mjs", "utf8");
9
+ const deployScript = readFileSync("src/hosted-mcp/deploy.sh", "utf8");
4
10
 
5
- function assertContains(needle, label) {
6
- if (!server.includes(needle)) {
11
+ function assertContains(haystack, needle, label) {
12
+ if (!haystack.includes(needle)) {
7
13
  throw new Error(`${label} missing expected text: ${needle}`);
8
14
  }
9
15
  }
10
16
 
11
- function assertBefore(first, second, label) {
12
- const firstIndex = server.indexOf(first);
13
- const secondIndex = server.indexOf(second);
17
+ function assertBefore(haystack, first, second, label) {
18
+ const firstIndex = haystack.indexOf(first);
19
+ const secondIndex = haystack.indexOf(second);
14
20
  if (firstIndex === -1 || secondIndex === -1 || firstIndex >= secondIndex) {
15
21
  throw new Error(`${label} expected "${first}" before "${second}"`);
16
22
  }
17
23
  }
18
24
 
19
- assertContains("CREATE TABLE IF NOT EXISTS codex_daemon_e2ee_keys", "persistent key table");
20
- assertContains("async function loadCodexDaemonPubkeysFromDb()", "boot load helper");
21
- assertContains("await loadCodexDaemonPubkeysFromDb();", "boot load call");
22
- assertContains("async function persistCodexDaemonPubkey(agentId, pubkey, cryptoVersions)", "persist helper");
23
- assertContains("function registerCodexDaemonPubkey(agentId, pubkey, cryptoVersions, source)", "registration helper");
24
- assertContains("codexDaemonPubkeys.set(agentId, {", "registration updates in-memory bootstrap cache");
25
- assertContains("return persistCodexDaemonPubkey(agentId, pubkey, normalizedVersions)", "registration persists after cache update");
26
- assertContains("await registerCodexDaemonPubkey(identity.agentId, p.daemon_public_key, p.crypto_versions, \"pair-complete\");", "pair-complete persists key");
27
- assertContains("if (envelope?.type === \"daemon.identity\") {", "daemon reconnect identity frame");
28
- assertContains("envelope.daemon_public_key", "daemon identity carries public key");
29
- assertContains("envelope.crypto_versions", "daemon identity carries crypto versions");
30
- assertContains("\"daemon-reconnect\"", "daemon reconnect source marker");
31
- assertContains("const daemonKey = codexDaemonPubkeys.get(identity.agentId) || null;", "bootstrap uses loaded or registered key");
25
+ function assert(condition, label, detail = "") {
26
+ if (!condition) throw new Error(`${label}${detail ? ": " + detail : ""}`);
27
+ }
28
+
29
+ function bootstrapPayloadFor(registry, identity, threadId, daemonOnline = true) {
30
+ return buildCodexBootstrapPayload({
31
+ identity,
32
+ threadId,
33
+ daemonOnline,
34
+ daemonKey: registry.get(identity.agentId),
35
+ });
36
+ }
37
+
38
+ function createFakePrisma() {
39
+ const rows = new Map();
40
+ return {
41
+ rows,
42
+ async $executeRawUnsafe(sql, tenantId, pubkey, cryptoVersionsJson) {
43
+ if (/CREATE TABLE IF NOT EXISTS codex_daemon_e2ee_keys/.test(sql)) return;
44
+ if (/INSERT INTO codex_daemon_e2ee_keys/.test(sql)) {
45
+ rows.set(tenantId, {
46
+ tenant_id: tenantId,
47
+ pubkey,
48
+ crypto_versions_json: cryptoVersionsJson,
49
+ registered_at: new Date("2026-05-11T17:37:18.000Z"),
50
+ });
51
+ return;
52
+ }
53
+ throw new Error("unexpected fake prisma execute: " + sql);
54
+ },
55
+ async $queryRawUnsafe(sql) {
56
+ if (/FROM codex_daemon_e2ee_keys/.test(sql)) return [...rows.values()];
57
+ throw new Error("unexpected fake prisma query: " + sql);
58
+ },
59
+ };
60
+ }
61
+
62
+ function createSilentLogger() {
63
+ return { log() {}, error() {} };
64
+ }
65
+
66
+ assertContains(registrySource, "CREATE TABLE IF NOT EXISTS codex_daemon_e2ee_keys", "persistent key table");
67
+ assertContains(registrySource, "async function loadFromDb()", "boot load helper");
68
+ assertContains(registrySource, "async function persist(agentId, pubkey, cryptoVersions)", "persist helper");
69
+ assertContains(registrySource, "function register(agentId, pubkey, cryptoVersions, source)", "registration helper");
70
+ assertContains(registrySource, "pubkeys.set(agentId, {", "registration updates in-memory bootstrap cache");
71
+ assertContains(registrySource, "return persist(agentId, pubkey, normalizedVersions)", "registration persists after cache update");
72
+ assertContains(server, "await codexDaemonPubkeyRegistry.loadFromDb();", "server boot load call");
73
+ assertContains(server, "await codexDaemonPubkeyRegistry.register(identity.agentId, p.daemon_public_key, p.crypto_versions, \"pair-complete\");", "pair-complete persists key");
74
+ assertContains(server, "if (envelope?.type === \"daemon.identity\") {", "daemon reconnect identity frame");
75
+ assertContains(server, "codexDaemonPubkeyRegistry.register(", "daemon reconnect register call");
76
+ assertContains(server, "buildCodexBootstrapPayload({ identity, threadId, daemonOnline, daemonKey })", "bootstrap uses shared payload builder");
77
+ assertContains(deployScript, "codex-relay-e2ee-registry.mjs", "hosted deploy copies registry module");
32
78
  assertBefore(
33
- "await loadCodexDaemonPubkeysFromDb();",
79
+ server,
80
+ "await codexDaemonPubkeyRegistry.loadFromDb();",
34
81
  "function handleCodexBootstrap(req, res, threadId)",
35
82
  "persisted keys load before bootstrap handler",
36
83
  );
37
84
 
38
- const modelPubkeys = new Map();
39
- const persistedRows = new Map();
85
+ const identity = {
86
+ agentId: "acct:test-user-a",
87
+ tenantId: "acct:test-user-a",
88
+ handle: "Parker smoke test",
89
+ apiKey: "ck-test",
90
+ };
91
+ const threadId = "019dfa1e-0c3d-7f01-86b9-9a22cd452bde";
40
92
 
41
- function normalizeVersions(versions) {
42
- const out = Array.isArray(versions)
43
- ? versions.filter((v) => typeof v === "string" && v.length > 0 && v.length <= 32).slice(0, 8)
44
- : [];
45
- return out.length ? out : ["e2ee-v1"];
46
- }
93
+ const fakePrisma = createFakePrisma();
94
+ const registryBeforeRestart = createCodexDaemonPubkeyRegistry({
95
+ usePrisma: true,
96
+ prisma: fakePrisma,
97
+ devMode: false,
98
+ logger: createSilentLogger(),
99
+ });
100
+ await registryBeforeRestart.register(identity.agentId, "spki-key-before-restart", ["e2ee-v1"], "pair-complete");
47
101
 
48
- function modelRegister(agentId, pubkey, versions) {
49
- const normalized = normalizeVersions(versions);
50
- modelPubkeys.set(agentId, { pubkey, crypto_versions: normalized });
51
- persistedRows.set(agentId, { pubkey, crypto_versions_json: JSON.stringify(normalized) });
52
- }
102
+ const beforeRestartBootstrap = bootstrapPayloadFor(registryBeforeRestart, identity, threadId);
103
+ assert(beforeRestartBootstrap.e2ee_available === true, "bootstrap reports e2ee before restart");
104
+ assert(beforeRestartBootstrap.daemon_public_key === "spki-key-before-restart", "bootstrap returns registered daemon key before restart");
53
105
 
54
- function modelBootLoad() {
55
- const restored = new Map();
56
- for (const [agentId, row] of persistedRows) {
57
- restored.set(agentId, {
58
- pubkey: row.pubkey,
59
- crypto_versions: normalizeVersions(JSON.parse(row.crypto_versions_json)),
60
- });
61
- }
62
- return restored;
63
- }
106
+ const registryAfterRestart = createCodexDaemonPubkeyRegistry({
107
+ usePrisma: true,
108
+ prisma: fakePrisma,
109
+ devMode: false,
110
+ logger: createSilentLogger(),
111
+ });
112
+ await registryAfterRestart.loadFromDb();
64
113
 
65
- modelRegister("acct:user-a", "spki-key-a", ["e2ee-v1"]);
66
- const afterRestart = modelBootLoad();
67
- if (afterRestart.get("acct:user-a")?.pubkey !== "spki-key-a") {
68
- throw new Error("boot load did not restore persisted daemon pubkey");
69
- }
114
+ const afterRestartBootstrap = bootstrapPayloadFor(registryAfterRestart, identity, threadId);
115
+ assert(afterRestartBootstrap.e2ee_available === true, "bootstrap reports e2ee after restart from persisted key");
116
+ assert(afterRestartBootstrap.daemon_public_key === "spki-key-before-restart", "bootstrap restores persisted daemon key after restart");
117
+ assert(afterRestartBootstrap.daemon_crypto_versions?.[0] === "e2ee-v1", "bootstrap restores crypto versions after restart");
70
118
 
71
- modelRegister("acct:user-a", "spki-key-b", []);
72
- const afterReconnect = modelBootLoad();
73
- if (afterReconnect.get("acct:user-a")?.pubkey !== "spki-key-b") {
74
- throw new Error("daemon reconnect did not replace persisted daemon pubkey");
75
- }
76
- if (afterReconnect.get("acct:user-a")?.crypto_versions?.[0] !== "e2ee-v1") {
77
- throw new Error("daemon reconnect did not default crypto version");
78
- }
119
+ const emptyFakePrisma = createFakePrisma();
120
+ const registryBeforeReconnect = createCodexDaemonPubkeyRegistry({
121
+ usePrisma: true,
122
+ prisma: emptyFakePrisma,
123
+ devMode: false,
124
+ logger: createSilentLogger(),
125
+ });
126
+ await registryBeforeReconnect.loadFromDb();
127
+ const beforeReconnectBootstrap = bootstrapPayloadFor(registryBeforeReconnect, identity, threadId);
128
+ assert(beforeReconnectBootstrap.e2ee_available === false, "bootstrap is not e2ee available before daemon reconnect when no key exists");
129
+ assert(beforeReconnectBootstrap.daemon_public_key === null, "bootstrap has no daemon key before daemon reconnect");
130
+
131
+ await registryBeforeReconnect.register(identity.agentId, "spki-key-from-daemon-reconnect", [], "daemon-reconnect");
132
+ const afterReconnectBootstrap = bootstrapPayloadFor(registryBeforeReconnect, identity, threadId);
133
+ assert(afterReconnectBootstrap.e2ee_available === true, "bootstrap reports e2ee after daemon reconnect self-heal");
134
+ assert(afterReconnectBootstrap.daemon_public_key === "spki-key-from-daemon-reconnect", "bootstrap returns daemon reconnect key");
135
+ assert(afterReconnectBootstrap.daemon_crypto_versions?.[0] === "e2ee-v1", "daemon reconnect defaults crypto version");
136
+
137
+ const registryAfterReconnectRestart = createCodexDaemonPubkeyRegistry({
138
+ usePrisma: true,
139
+ prisma: emptyFakePrisma,
140
+ devMode: false,
141
+ logger: createSilentLogger(),
142
+ });
143
+ await registryAfterReconnectRestart.loadFromDb();
144
+ const afterReconnectRestartBootstrap = bootstrapPayloadFor(registryAfterReconnectRestart, identity, threadId);
145
+ assert(afterReconnectRestartBootstrap.e2ee_available === true, "daemon reconnect key is persisted for the next restart");
146
+ assert(afterReconnectRestartBootstrap.daemon_public_key === "spki-key-from-daemon-reconnect", "daemon reconnect key survives restart");
79
147
 
80
- console.log("crc e2ee key persistence checks passed");
148
+ console.log("crc e2ee key persistence restart regression checks passed");
@@ -0,0 +1,114 @@
1
+ export function normalizeCodexCryptoVersions(versions) {
2
+ const out = Array.isArray(versions)
3
+ ? versions.filter((v) => typeof v === "string" && v.length > 0 && v.length <= 32).slice(0, 8)
4
+ : [];
5
+ return out.length ? out : ["e2ee-v1"];
6
+ }
7
+
8
+ export function buildCodexBootstrapPayload({ identity, threadId, daemonOnline, daemonKey }) {
9
+ return {
10
+ handle: identity.handle,
11
+ thread_id: threadId,
12
+ daemon_online: daemonOnline,
13
+ daemon_public_key: daemonKey ? daemonKey.pubkey : null,
14
+ daemon_crypto_versions: daemonKey ? daemonKey.crypto_versions : null,
15
+ supported_crypto_versions: ["e2ee-v1"],
16
+ e2ee_available: !!daemonKey,
17
+ };
18
+ }
19
+
20
+ export function createCodexDaemonPubkeyRegistry({
21
+ usePrisma,
22
+ prisma,
23
+ devMode = false,
24
+ logger = console,
25
+ } = {}) {
26
+ const pubkeys = new Map();
27
+
28
+ async function ensureStore() {
29
+ if (!usePrisma) return;
30
+ await prisma.$executeRawUnsafe(`
31
+ CREATE TABLE IF NOT EXISTS codex_daemon_e2ee_keys (
32
+ tenant_id TEXT PRIMARY KEY,
33
+ pubkey TEXT NOT NULL,
34
+ crypto_versions_json TEXT NOT NULL,
35
+ registered_at TIMESTAMPTZ NOT NULL DEFAULT now()
36
+ )
37
+ `);
38
+ }
39
+
40
+ async function loadFromDb() {
41
+ if (!usePrisma) return;
42
+ try {
43
+ await ensureStore();
44
+ const rows = await prisma.$queryRawUnsafe(`
45
+ SELECT tenant_id, pubkey, crypto_versions_json, registered_at
46
+ FROM codex_daemon_e2ee_keys
47
+ `);
48
+ for (const row of rows) {
49
+ let cryptoVersions = ["e2ee-v1"];
50
+ try { cryptoVersions = normalizeCodexCryptoVersions(JSON.parse(row.crypto_versions_json)); } catch {}
51
+ pubkeys.set(row.tenant_id, {
52
+ pubkey: row.pubkey,
53
+ crypto_versions: cryptoVersions,
54
+ registered_at: row.registered_at instanceof Date ? row.registered_at.toISOString() : String(row.registered_at),
55
+ });
56
+ }
57
+ logger.log("codex-relay: loaded " + rows.length + " persisted E2EE daemon pubkey(s)");
58
+ } catch (err) {
59
+ logger.error("codex-relay: failed to load persisted E2EE daemon pubkeys:", err.message);
60
+ if (!devMode) process.exit(1);
61
+ }
62
+ }
63
+
64
+ async function persist(agentId, pubkey, cryptoVersions) {
65
+ if (!usePrisma) return;
66
+ await ensureStore();
67
+ await prisma.$executeRawUnsafe(
68
+ `INSERT INTO codex_daemon_e2ee_keys
69
+ (tenant_id, pubkey, crypto_versions_json, registered_at)
70
+ VALUES ($1, $2, $3, now())
71
+ ON CONFLICT (tenant_id)
72
+ DO UPDATE SET
73
+ pubkey = EXCLUDED.pubkey,
74
+ crypto_versions_json = EXCLUDED.crypto_versions_json,
75
+ registered_at = EXCLUDED.registered_at`,
76
+ agentId,
77
+ pubkey,
78
+ JSON.stringify(cryptoVersions),
79
+ );
80
+ }
81
+
82
+ function register(agentId, pubkey, cryptoVersions, source) {
83
+ if (typeof agentId !== "string" || !agentId) return Promise.resolve(false);
84
+ if (typeof pubkey !== "string" || !pubkey || pubkey.length > 1024) return Promise.resolve(false);
85
+ const normalizedVersions = normalizeCodexCryptoVersions(cryptoVersions);
86
+ const registeredAt = new Date().toISOString();
87
+ pubkeys.set(agentId, {
88
+ pubkey,
89
+ crypto_versions: normalizedVersions,
90
+ registered_at: registeredAt,
91
+ });
92
+ logger.log("codex-relay: registered E2EE pubkey for " + agentId + " via " + source);
93
+ return persist(agentId, pubkey, normalizedVersions)
94
+ .then(() => true)
95
+ .catch((err) => {
96
+ logger.error("codex-relay: failed to persist E2EE pubkey for " + agentId + ":", err.message);
97
+ if (!devMode) throw err;
98
+ return false;
99
+ });
100
+ }
101
+
102
+ return {
103
+ pubkeys,
104
+ ensureStore,
105
+ loadFromDb,
106
+ register,
107
+ get(agentId) {
108
+ return pubkeys.get(agentId) || null;
109
+ },
110
+ clearMemoryForTest() {
111
+ pubkeys.clear();
112
+ },
113
+ };
114
+ }
@@ -116,6 +116,7 @@ if [ "$SKIP_APP" -ne 1 ]; then
116
116
  add_file "server.mjs" "${APP_REMOTE_DIR}/server.mjs"
117
117
  add_file "inbox.mjs" "${APP_REMOTE_DIR}/inbox.mjs"
118
118
  add_file "tools.mjs" "${APP_REMOTE_DIR}/tools.mjs"
119
+ add_file "codex-relay-e2ee-registry.mjs" "${APP_REMOTE_DIR}/codex-relay-e2ee-registry.mjs"
119
120
  add_file "package.json" "${APP_REMOTE_DIR}/package.json"
120
121
  # Phone app static files (codex-remote-control, login).
121
122
  if [ -d "${SCRIPT_DIR}/app" ]; then
@@ -23,6 +23,10 @@ import {
23
23
  import QRCode from "qrcode";
24
24
  import { WebSocketServer } from "ws";
25
25
  import { parse as parseUrlQs } from "node:querystring";
26
+ import {
27
+ buildCodexBootstrapPayload,
28
+ createCodexDaemonPubkeyRegistry,
29
+ } from "./codex-relay-e2ee-registry.mjs";
26
30
 
27
31
  // ── Settings ─────────────────────────────────────────────────────────
28
32
 
@@ -2607,7 +2611,7 @@ const codexE2eeSessionRoutes = new Map(); // `${agentId}:${e2eeSession}` -> { th
2607
2611
 
2608
2612
  // E2EE substrate (Phase 2.5).
2609
2613
  //
2610
- // codexDaemonPubkeys: per tenant id, the most recently paired daemon's
2614
+ // codexDaemonPubkeyRegistry: per tenant id, the most recently paired daemon's
2611
2615
  // public key (P-256 SPKI base64url) + supported crypto versions +
2612
2616
  // registration timestamp. This is what the browser fetches via
2613
2617
  // bootstrap before opening an encrypted session.
@@ -2616,92 +2620,17 @@ const codexE2eeSessionRoutes = new Map(); // `${agentId}:${e2eeSession}` -> { th
2616
2620
  // ?token=ck-... in the browser WebSocket URL. Bound to a specific
2617
2621
  // (agentId, threadId) so a leaked ticket cannot drive a different
2618
2622
  // route, even by the same authenticated user.
2619
- const codexDaemonPubkeys = new Map(); // tenantId -> { pubkey, crypto_versions, registered_at }
2620
2623
  const codexRelayTickets = new Map(); // ticket -> { agentId, threadId, expires, used }
2621
2624
  const CODEX_RELAY_TICKET_TTL_MS = 60 * 1000; // 60s; browser must connect immediately
2622
2625
 
2623
- async function ensureCodexDaemonPubkeyStore() {
2624
- if (!usePrisma) return;
2625
- await prisma.$executeRawUnsafe(`
2626
- CREATE TABLE IF NOT EXISTS codex_daemon_e2ee_keys (
2627
- tenant_id TEXT PRIMARY KEY,
2628
- pubkey TEXT NOT NULL,
2629
- crypto_versions_json TEXT NOT NULL,
2630
- registered_at TIMESTAMPTZ NOT NULL DEFAULT now()
2631
- )
2632
- `);
2633
- }
2634
-
2635
- function normalizeCodexCryptoVersions(versions) {
2636
- const out = Array.isArray(versions)
2637
- ? versions.filter((v) => typeof v === "string" && v.length > 0 && v.length <= 32).slice(0, 8)
2638
- : [];
2639
- return out.length ? out : ["e2ee-v1"];
2640
- }
2641
-
2642
- async function loadCodexDaemonPubkeysFromDb() {
2643
- if (!usePrisma) return;
2644
- try {
2645
- await ensureCodexDaemonPubkeyStore();
2646
- const rows = await prisma.$queryRawUnsafe(`
2647
- SELECT tenant_id, pubkey, crypto_versions_json, registered_at
2648
- FROM codex_daemon_e2ee_keys
2649
- `);
2650
- for (const row of rows) {
2651
- let cryptoVersions = ["e2ee-v1"];
2652
- try { cryptoVersions = normalizeCodexCryptoVersions(JSON.parse(row.crypto_versions_json)); } catch {}
2653
- codexDaemonPubkeys.set(row.tenant_id, {
2654
- pubkey: row.pubkey,
2655
- crypto_versions: cryptoVersions,
2656
- registered_at: row.registered_at instanceof Date ? row.registered_at.toISOString() : String(row.registered_at),
2657
- });
2658
- }
2659
- console.log("codex-relay: loaded " + rows.length + " persisted E2EE daemon pubkey(s)");
2660
- } catch (err) {
2661
- console.error("codex-relay: failed to load persisted E2EE daemon pubkeys:", err.message);
2662
- if (!DEV_MODE) process.exit(1);
2663
- }
2664
- }
2665
-
2666
- async function persistCodexDaemonPubkey(agentId, pubkey, cryptoVersions) {
2667
- if (!usePrisma) return;
2668
- await ensureCodexDaemonPubkeyStore();
2669
- await prisma.$executeRawUnsafe(
2670
- `INSERT INTO codex_daemon_e2ee_keys
2671
- (tenant_id, pubkey, crypto_versions_json, registered_at)
2672
- VALUES ($1, $2, $3, now())
2673
- ON CONFLICT (tenant_id)
2674
- DO UPDATE SET
2675
- pubkey = EXCLUDED.pubkey,
2676
- crypto_versions_json = EXCLUDED.crypto_versions_json,
2677
- registered_at = EXCLUDED.registered_at`,
2678
- agentId,
2679
- pubkey,
2680
- JSON.stringify(cryptoVersions),
2681
- );
2682
- }
2683
-
2684
- function registerCodexDaemonPubkey(agentId, pubkey, cryptoVersions, source) {
2685
- if (typeof agentId !== "string" || !agentId) return Promise.resolve(false);
2686
- if (typeof pubkey !== "string" || !pubkey || pubkey.length > 1024) return Promise.resolve(false);
2687
- const normalizedVersions = normalizeCodexCryptoVersions(cryptoVersions);
2688
- const registeredAt = new Date().toISOString();
2689
- codexDaemonPubkeys.set(agentId, {
2690
- pubkey,
2691
- crypto_versions: normalizedVersions,
2692
- registered_at: registeredAt,
2693
- });
2694
- console.log("codex-relay: registered E2EE pubkey for " + agentId + " via " + source);
2695
- return persistCodexDaemonPubkey(agentId, pubkey, normalizedVersions)
2696
- .then(() => true)
2697
- .catch((err) => {
2698
- console.error("codex-relay: failed to persist E2EE pubkey for " + agentId + ":", err.message);
2699
- if (!DEV_MODE) throw err;
2700
- return false;
2701
- });
2702
- }
2626
+ const codexDaemonPubkeyRegistry = createCodexDaemonPubkeyRegistry({
2627
+ usePrisma,
2628
+ prisma,
2629
+ devMode: DEV_MODE,
2630
+ logger: console,
2631
+ });
2703
2632
 
2704
- await loadCodexDaemonPubkeysFromDb();
2633
+ await codexDaemonPubkeyRegistry.loadFromDb();
2705
2634
 
2706
2635
  function codexRelayKey(agentId, id) {
2707
2636
  return agentId + ":" + id;
@@ -2876,7 +2805,7 @@ async function handleCodexPairComplete(req, res) {
2876
2805
  // authenticated immutable tenant id. The display handle is returned
2877
2806
  // as metadata only.
2878
2807
  if (p.daemon_public_key) {
2879
- await registerCodexDaemonPubkey(identity.agentId, p.daemon_public_key, p.crypto_versions, "pair-complete");
2808
+ await codexDaemonPubkeyRegistry.register(identity.agentId, p.daemon_public_key, p.crypto_versions, "pair-complete");
2880
2809
  }
2881
2810
  delete codexPairingByCode[code];
2882
2811
  console.log("codex-relay: paired daemon for tenant " + identity.agentId + " handle " + identity.handle);
@@ -2901,16 +2830,8 @@ function handleCodexBootstrap(req, res, threadId) {
2901
2830
  if (!identity) { json(res, 401, { error: "Unauthorized" }); return; }
2902
2831
  if (!threadId) { json(res, 400, { error: "missing threadId" }); return; }
2903
2832
  const daemonOnline = codexDaemons.has(identity.agentId);
2904
- const daemonKey = codexDaemonPubkeys.get(identity.agentId) || null;
2905
- json(res, 200, {
2906
- handle: identity.handle,
2907
- thread_id: threadId,
2908
- daemon_online: daemonOnline,
2909
- daemon_public_key: daemonKey ? daemonKey.pubkey : null,
2910
- daemon_crypto_versions: daemonKey ? daemonKey.crypto_versions : null,
2911
- supported_crypto_versions: ["e2ee-v1"],
2912
- e2ee_available: !!daemonKey,
2913
- });
2833
+ const daemonKey = codexDaemonPubkeyRegistry.get(identity.agentId);
2834
+ json(res, 200, buildCodexBootstrapPayload({ identity, threadId, daemonOnline, daemonKey }));
2914
2835
  }
2915
2836
 
2916
2837
  // POST /api/codex-relay/ws-ticket
@@ -3141,7 +3062,7 @@ httpServer.on("upgrade", (req, socket, head) => {
3141
3062
  let envelope = null;
3142
3063
  try { envelope = JSON.parse(text); } catch {}
3143
3064
  if (envelope?.type === "daemon.identity") {
3144
- void registerCodexDaemonPubkey(
3065
+ void codexDaemonPubkeyRegistry.register(
3145
3066
  identity.agentId,
3146
3067
  envelope.daemon_public_key,
3147
3068
  envelope.crypto_versions,