From 1e4c6b04f7e9ce30687c3d7207899749cf4da21f Mon Sep 17 00:00:00 2001 From: Serge Alex Date: Sun, 1 Nov 2026 22:17:55 +0300 Subject: [PATCH] feat-memory-chats-registry-endpoint --- bridge/server.js | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/bridge/server.js b/bridge/server.js index 39431ab..fb28d6e 100644 --- a/bridge/server.js +++ b/bridge/server.js @@ -211,11 +211,12 @@ async function handle(req, res, pathname, body) { if (req.method === 'PUT') { const b = body || {}; const memOk = b.memories && typeof b.memories === 'object' && !Array.isArray(b.memories); - const next = { + let existingChats = {}; try { const cur = JSON.parse(fs.readFileSync(stateFile, 'utf8')); if (cur && cur.chats && typeof cur.chats === 'object') existingChats = cur.chats; } catch (e) { } const chatsOk = b.chats && typeof b.chats === 'object'; const next = { version: 1, updatedAt: new Date().toISOString(), memories: memOk ? b.memories : {}, skills: Array.isArray(b.skills) ? b.skills : [], + chats: chatsOk ? b.chats : existingChats, }; fs.mkdirSync(memDir, { recursive: true }); const tmp = stateFile + '.tmp'; @@ -225,6 +226,40 @@ async function handle(req, res, pathname, body) { } throw new ToolError('E_ARGS_INVALID', 'GET or PUT only'); } + case '/memory/chats': { + const memDir = resolveMemoryDir(config, BRIDGE_DIR); + const stateFile = path.join(memDir, 'state.json'); + let st = {}; + try { st = JSON.parse(fs.readFileSync(stateFile, 'utf8')); } catch (e) { st = {}; } + if (!st.chats || typeof st.chats !== 'object') st.chats = {}; + if (req.method === 'GET') { + const id = (body && body.chatId) ? String(body.chatId) : ''; + if (id) return { ok: true, data: st.chats[id] || null }; + return { ok: true, data: st.chats }; + } + if (req.method === 'POST') { + const b = body || {}; + const id = b.chatId ? String(b.chatId) : ''; + if (!id || id.length > 64 || id.indexOf('/') !== -1) throw new ToolError('E_ARGS_INVALID', 'bad chatId'); + const entry = (b.entry && typeof b.entry === 'object') ? b.entry : {}; + entry.updatedAt = Date.now(); + st.chats[id] = entry; + const ids = Object.keys(st.chats); + if (ids.length > 20) { + ids.sort(function (x, y) { return (st.chats[x].updatedAt || 0) - (st.chats[y].updatedAt || 0); }); + const drop = ids.length - 20; + for (let i = 0; i < drop; i++) delete st.chats[ids[i]]; + } + st.version = st.version || 1; + st.updatedAt = new Date().toISOString(); + fs.mkdirSync(memDir, { recursive: true }); + const tmp = stateFile + '.tmp'; + fs.writeFileSync(tmp, JSON.stringify(st, null, 2), 'utf8'); + fs.renameSync(tmp, stateFile); + return { ok: true, data: st.chats[id] }; + } + throw new ToolError('E_ARGS_INVALID', 'GET or POST only'); + } case '/log/append': { if (req.method !== 'POST') throw new ToolError('E_ARGS_INVALID', 'only POST'); const file = body && body.file;