diff --git a/lib/daemon.js b/lib/daemon.js index a9c2a088..1972368b 100644 --- a/lib/daemon.js +++ b/lib/daemon.js @@ -1400,6 +1400,43 @@ var ipc = createIPCServer(socketPath(), function (msg) { })(); } + case "push_message": { + // Validate inputs before searching — never crash, always return {ok, error}. + if (!msg.sessionId || typeof msg.sessionId !== "string") { + return { ok: false, error: "missing or invalid sessionId" }; + } + if (!msg.text || typeof msg.text !== "string") { + return { ok: false, error: "missing or invalid text" }; + } + try { + // Search for the session by cliSessionId across all registered projects. + // relay.forEachProject iterates (ctx, slug); ctx.sm.sessions is a Map of + // localId -> session. The relay-agent-claims path sets cliSessionId from + // the SDK session UUID — that is the identifier the relay knows. + var found = null; + relay.forEachProject(function (ctx) { + if (found) return; + ctx.sm.sessions.forEach(function (s) { + if (!found && s.cliSessionId === msg.sessionId) { + found = { ctx: ctx, session: s }; + } + }); + }); + if (!found) { + console.log("[daemon] push_message failed: session not found: " + msg.sessionId); + return { ok: false, error: "session not found: " + msg.sessionId }; + } + // Delegate to sdk-bridge pushMessage — same path as the operator typing in the UI. + // Third arg (images) is null: relay turns are plain text. + found.ctx.sdk.pushMessage(found.session, msg.text, null); + console.log("[daemon] push_message delivered to session " + msg.sessionId); + return { ok: true }; + } catch (e) { + console.log("[daemon] push_message failed: " + e.message); + return { ok: false, error: e.message }; + } + } + default: return { ok: false, error: "unknown command: " + msg.cmd }; }