Ctrl K
ComunidadGuías…

lib/dm.js

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
var fs = require("fs");
var path = require("path");
var config = require("./config");

var DM_DIR = path.join(config.CONFIG_DIR, "dm");

// Ensure dm directory exists
function ensureDmDir() {
  fs.mkdirSync(DM_DIR, { recursive: true });
  config.chmodSafe(DM_DIR, 0o700);
}

// Generate deterministic DM key from two user IDs (sorted, order-independent)
function dmKey(userId1, userId2) {
  return [userId1, userId2].sort().join(":");
}

// File path for a DM conversation
function dmFilePath(key) {
  // Replace : with _ for safe filename
  return path.join(DM_DIR, key.replace(/:/g, "_") + ".jsonl");
}

// Load DM history from JSONL file
function loadHistory(key) {
  var filePath = dmFilePath(key);
  if (!fs.existsSync(filePath)) return [];
  try {
    var content = fs.readFileSync(filePath, "utf8").trim();
    if (!content) return [];
    var lines = content.split("\n");
    var messages = [];
    for (var i = 0; i < lines.length; i++) {
      if (!lines[i].trim()) continue;
      try {
        messages.push(JSON.parse(lines[i]));
      } catch (e) {
        // skip malformed lines
      }
    }
    return messages;
  } catch (e) {
    return [];
  }
}

// Append a message to DM JSONL file
function appendMessage(key, message) {
  ensureDmDir();
  var filePath = dmFilePath(key);
  var line = JSON.stringify(message) + "\n";
  fs.appendFileSync(filePath, line);
}

// Open a DM conversation (find or create)
function openDm(userId1, userId2) {
  var key = dmKey(userId1, userId2);
  var history = loadHistory(key);
  return { dmKey: key, messages: history };
}

// Send a DM message
function sendMessage(key, fromUserId, text) {
  var message = {
    type: "dm_message",
    ts: Date.now(),
    from: fromUserId,
    text: text,
  };
  appendMessage(key, message);
  return message;
}

// Get list of all DM conversations for a user
// Returns: [{ dmKey, otherUserId, lastMessage, lastTs }]
function getDmList(userId) {
  ensureDmDir();
  var files;
  try {
    files = fs.readdirSync(DM_DIR).filter(function (f) {
      return f.endsWith(".jsonl");
    });
  } catch (e) {
    return [];
  }

  var dms = [];
  for (var i = 0; i < files.length; i++) {
    // Reconstruct dmKey from filename (replace _ back to :)
    var key = files[i].replace(".jsonl", "").replace(/_/g, ":");
    var parts = key.split(":");
    if (parts.length !== 2) continue;

    // Check if this user is a participant
    var idx = parts.indexOf(userId);
    if (idx === -1) continue;

    var otherUserId = parts[idx === 0 ? 1 : 0];

    // Get last message
    var messages = loadHistory(key);
    var lastMessage = messages.length > 0 ? messages[messages.length - 1] : null;

    dms.push({
      dmKey: key,
      otherUserId: otherUserId,
      lastMessage: lastMessage ? lastMessage.text : null,
      lastTs: lastMessage ? lastMessage.ts : 0,
      messageCount: messages.length,
    });
  }

  // Sort by most recent activity
  dms.sort(function (a, b) {
    return b.lastTs - a.lastTs;
  });

  return dms;
}

// Check if a user ID looks like a mate (AI persona) by format only
function isMate(userId) {
  var mates = require("./mates");
  return mates.isMateIdFormat(userId);
}

module.exports = {
  dmKey: dmKey,
  openDm: openDm,
  sendMessage: sendMessage,
  getDmList: getDmList,
  loadHistory: loadHistory,
  isMate: isMate,
  DM_DIR: DM_DIR,
};