import {
  decryptMemoryDirToPlaintext,
  migrateMemoryDirToEncrypted
} from "./chunk-YNJHCGDT.js";
import {
  buildHeaderFromPassphrase,
  deriveKeyFromHeader,
  getKey,
  headerPath,
  lock,
  readHeader,
  secureStoreDir,
  status,
  unlock,
  verifyKey,
  writeHeader
} from "./chunk-BJMBJZ2Y.js";
import {
  DEFAULT_ARGON2ID_PARAMS,
  DEFAULT_SCRYPT_PARAMS,
  KDF_SALT_LENGTH
} from "./chunk-FP2373TW.js";
import {
  generateSalt
} from "./chunk-A6XUJE5D.js";

// src/secure-store/cli-handlers.ts
async function runSecureStoreInit(options) {
  const { memoryDir, readPassphrase } = options;
  if (typeof memoryDir !== "string" || memoryDir.length === 0) {
    throw new Error("secure-store init: memoryDir is required");
  }
  const existing = await readHeader(memoryDir);
  if (existing !== null) {
    throw new Error(
      `secure-store header already exists at ${headerPath(memoryDir)}. Run 'remnic secure-store status' to inspect, or remove the .secure-store directory explicitly to reinitialize.`
    );
  }
  const passphrase = await readPassphrase("Enter new passphrase: ", { confirm: true });
  validatePassphrase(passphrase);
  const algorithm = options.algorithm ?? "argon2id";
  const params = resolveParams(algorithm, options.params);
  const salt = options.salt ?? generateSalt();
  if (salt.length !== KDF_SALT_LENGTH) {
    throw new Error(`salt must be ${KDF_SALT_LENGTH} bytes, got ${salt.length}`);
  }
  const built = buildHeaderFromPassphrase({
    passphrase,
    salt,
    algorithm,
    params,
    ...options.note !== void 0 ? { note: options.note } : {},
    ...options.now ? { createdAt: options.now().toISOString() } : {}
  });
  built.derivedKey.fill(0);
  const writtenPath = await writeHeader(memoryDir, built.header);
  return {
    ok: true,
    headerPath: writtenPath,
    kdf: built.header.metadata.kdf,
    createdAt: built.header.createdAt
  };
}
async function runSecureStoreUnlock(options) {
  const { memoryDir, readPassphrase } = options;
  const header = await readHeader(memoryDir);
  if (!header) {
    return { ok: false, reason: "not-initialized" };
  }
  const passphrase = await readPassphrase("Enter passphrase: ");
  validatePassphrase(passphrase);
  const candidateKey = deriveKeyFromHeader(header, passphrase);
  if (!verifyKey(header, candidateKey)) {
    candidateKey.fill(0);
    return { ok: false, reason: "wrong-passphrase" };
  }
  const id = options.keyringId ?? secureStoreDir(memoryDir);
  const now = options.now ?? (() => /* @__PURE__ */ new Date());
  unlock(id, candidateKey, now);
  const status2 = status(id);
  return {
    ok: true,
    unlockedAt: status2.unlockedAt ?? now().toISOString(),
    algorithm: header.metadata.kdf.algorithm
  };
}
function runSecureStoreLock(options) {
  const id = options.keyringId ?? secureStoreDir(options.memoryDir);
  const cleared = lock(id);
  return { ok: true, cleared };
}
async function runSecureStoreMigrate(options) {
  const { memoryDir } = options;
  const header = await readHeader(memoryDir);
  if (!header) {
    return {
      ok: false,
      reason: "not-initialized",
      encrypted: 0,
      skipped: 0,
      errors: []
    };
  }
  const id = options.keyringId ?? secureStoreDir(memoryDir);
  const key = getKey(id);
  if (key === null) {
    return {
      ok: false,
      reason: "locked",
      encrypted: 0,
      skipped: 0,
      errors: []
    };
  }
  const result = await migrateMemoryDirToEncrypted(memoryDir, key);
  if (result.errors.length > 0) {
    return { ok: false, reason: "file-errors", ...result };
  }
  return { ok: true, ...result };
}
async function runSecureStoreDisable(options) {
  const { memoryDir } = options;
  const header = await readHeader(memoryDir);
  if (!header) {
    return {
      ok: false,
      reason: "not-initialized",
      decrypted: 0,
      skipped: 0,
      errors: []
    };
  }
  const id = options.keyringId ?? secureStoreDir(memoryDir);
  const key = getKey(id);
  if (key === null) {
    return {
      ok: false,
      reason: "locked",
      decrypted: 0,
      skipped: 0,
      errors: []
    };
  }
  const result = await decryptMemoryDirToPlaintext(memoryDir, key);
  if (result.errors.length > 0) {
    return { ok: false, reason: "file-errors", ...result };
  }
  return { ok: true, ...result };
}
async function runSecureStoreStatus(options) {
  const { memoryDir } = options;
  const id = options.keyringId ?? secureStoreDir(memoryDir);
  const header = await readHeader(memoryDir);
  const ks = status(id);
  const target = headerPath(memoryDir);
  if (!header) {
    return {
      initialized: false,
      headerPath: target,
      locked: !ks.unlocked,
      unlockedAt: ks.unlockedAt,
      kdf: null,
      createdAt: null
    };
  }
  return {
    initialized: true,
    headerPath: target,
    locked: !ks.unlocked,
    unlockedAt: ks.unlockedAt,
    kdf: header.metadata.kdf,
    createdAt: header.createdAt
  };
}
var MIN_PASSPHRASE_LENGTH = 8;
function validatePassphrase(passphrase) {
  if (typeof passphrase !== "string") {
    throw new Error("passphrase must be a string");
  }
  if (passphrase.length === 0) {
    throw new Error("passphrase must not be empty");
  }
  if (passphrase.length < MIN_PASSPHRASE_LENGTH) {
    throw new Error(`passphrase must be at least ${MIN_PASSPHRASE_LENGTH} characters`);
  }
}
function resolveParams(algorithm, override) {
  if (override !== void 0) return override;
  if (algorithm === "scrypt") return { ...DEFAULT_SCRYPT_PARAMS };
  return { ...DEFAULT_ARGON2ID_PARAMS };
}

// src/secure-store/cli-renderer.ts
function renderInitReport(report) {
  const lines = [];
  lines.push("=== Remnic secure-store initialized ===");
  lines.push("");
  lines.push(`header: ${report.headerPath}`);
  lines.push(`createdAt: ${report.createdAt}`);
  lines.push(...renderKdfLines(report.kdf));
  lines.push("");
  lines.push("Note: init does NOT auto-unlock the store. Run");
  lines.push("  remnic engram secure-store unlock");
  lines.push("to register the master key with the running daemon.");
  return lines.join("\n");
}
function renderUnlockReport(report) {
  if (report.ok) {
    return `OK \u2014 secure-store unlocked at ${report.unlockedAt} (algorithm=${report.algorithm}).`;
  }
  if (report.reason === "not-initialized") {
    return "ERR \u2014 secure-store is not initialized. Run 'remnic engram secure-store init' first.";
  }
  return "ERR \u2014 wrong passphrase.";
}
function renderLockReport(report) {
  if (report.cleared) {
    return "OK \u2014 secure-store key cleared from in-memory keyring.";
  }
  return "OK \u2014 secure-store was already locked (no in-memory key to clear).";
}
function renderMigrateReport(report) {
  if (!report.ok && report.reason === "not-initialized") {
    return "ERR \u2014 secure-store is not initialized. Run 'remnic engram secure-store init' first.";
  }
  if (!report.ok && report.reason === "locked") {
    return "ERR \u2014 secure-store is locked. Run 'remnic engram secure-store unlock' before migrate.";
  }
  const lines = [];
  lines.push(report.ok ? "OK \u2014 secure-store migration complete." : "ERR \u2014 secure-store migration completed with file errors.");
  lines.push(`encrypted: ${report.encrypted}`);
  lines.push(`skipped: ${report.skipped}`);
  lines.push(`errors: ${report.errors.length}`);
  for (const entry of report.errors.slice(0, 10)) {
    lines.push(`- ${entry.filePath}: ${entry.error}`);
  }
  if (report.errors.length > 10) {
    lines.push(`- ... ${report.errors.length - 10} more error(s)`);
  }
  return lines.join("\n");
}
function renderDisableReport(report) {
  if (!report.ok && report.reason === "not-initialized") {
    return "ERR \u2014 secure-store is not initialized. Run 'remnic engram secure-store init' first.";
  }
  if (!report.ok && report.reason === "locked") {
    return "ERR \u2014 secure-store is locked. Run 'remnic engram secure-store unlock' before disable.";
  }
  const lines = [];
  lines.push(report.ok ? "OK \u2014 secure-store disable complete." : "ERR \u2014 secure-store disable completed with file errors.");
  lines.push(`decrypted: ${report.decrypted}`);
  lines.push(`skipped: ${report.skipped}`);
  lines.push(`errors: ${report.errors.length}`);
  for (const entry of report.errors.slice(0, 10)) {
    lines.push(`- ${entry.filePath}: ${entry.error}`);
  }
  if (report.errors.length > 10) {
    lines.push(`- ... ${report.errors.length - 10} more error(s)`);
  }
  lines.push("header: kept");
  return lines.join("\n");
}
function renderStatusReport(report) {
  const lines = [];
  lines.push("=== Remnic secure-store status ===");
  lines.push("");
  lines.push(`header: ${report.headerPath}`);
  lines.push(`initialized: ${report.initialized ? "yes" : "no"}`);
  if (!report.initialized) {
    lines.push("");
    lines.push("Run 'remnic engram secure-store init' to initialize a new store.");
    return lines.join("\n");
  }
  lines.push(`createdAt: ${report.createdAt ?? "n/a"}`);
  lines.push(`locked: ${report.locked ? "yes" : "no"}`);
  if (!report.locked) {
    lines.push(`lastUnlockAt: ${report.unlockedAt ?? "n/a"}`);
  }
  if (report.kdf) {
    lines.push(...renderKdfLines(report.kdf));
  }
  return lines.join("\n");
}
function renderKdfLines(kdf) {
  const lines = [];
  lines.push(`kdf.algorithm: ${kdf.algorithm}`);
  if (kdf.algorithm === "scrypt") {
    const { N, r, p, keyLength, maxmem } = kdf.params;
    lines.push(`kdf.params: N=${N} r=${r} p=${p} keyLength=${keyLength} maxmem=${maxmem}`);
  } else {
    const { memoryKiB, iterations, parallelism, keyLength } = kdf.params;
    lines.push(
      `kdf.params: memoryKiB=${memoryKiB} iterations=${iterations} parallelism=${parallelism} keyLength=${keyLength}`
    );
  }
  return lines;
}

// src/secure-store/passphrase-reader.ts
import { createInterface } from "readline";
import { StringDecoder } from "string_decoder";
function createPassphraseReader(options = {}) {
  const input = options.input ?? process.stdin;
  const output = options.output ?? process.stdout;
  const errorStream = options.errorStream ?? process.stderr;
  let nonTtyReader = null;
  let nonTtyWarned = false;
  return async function readPassphrase(prompt, readerOptions) {
    const first = await readSinglePassphrase(prompt);
    if (readerOptions?.confirm) {
      const second = await readSinglePassphrase("Confirm passphrase: ");
      if (first !== second) {
        throw new Error("passphrases did not match");
      }
    }
    return first;
  };
  async function readSinglePassphrase(prompt) {
    const inputAsAny = input;
    if (inputAsAny.isTTY && typeof inputAsAny.setRawMode === "function") {
      return readNoEcho(prompt, inputAsAny, output);
    }
    if (!nonTtyWarned) {
      errorStream.write(
        "[remnic secure-store] warning: stdin is not a TTY; reading passphrase as a plain line. Take care that the passphrase is not exposed in shell history.\n"
      );
      nonTtyWarned = true;
    }
    errorStream.write(prompt);
    if (!nonTtyReader) nonTtyReader = createNonTtyLineReader(input);
    return nonTtyReader.next();
  }
}
function readNoEcho(prompt, input, output) {
  return new Promise((resolve, reject) => {
    output.write(prompt);
    let buffer = "";
    let settled = false;
    const wasRaw = input.isRaw === true;
    const decoder = new StringDecoder("utf8");
    if (input.setRawMode) input.setRawMode(true);
    input.resume();
    const cleanup = () => {
      input.pause();
      input.removeListener("data", onData);
      decoder.end();
      if (input.setRawMode) input.setRawMode(wasRaw);
      output.write("\n");
    };
    const onData = (chunk) => {
      const str = decoder.write(chunk);
      for (const ch of str) {
        if (settled) return;
        const code = ch.charCodeAt(0);
        if (ch === "\n" || ch === "\r") {
          settled = true;
          cleanup();
          resolve(buffer);
          return;
        }
        if (code === 3) {
          settled = true;
          cleanup();
          reject(new Error("passphrase entry aborted (Ctrl+C)"));
          return;
        }
        if (code === 4) {
          settled = true;
          cleanup();
          if (buffer.length === 0) {
            reject(new Error("passphrase entry aborted (EOF)"));
          } else {
            resolve(buffer);
          }
          return;
        }
        if (code === 8 || code === 127) {
          if (buffer.length > 0) {
            const codePoints = Array.from(buffer);
            buffer = codePoints.slice(0, -1).join("");
          }
          continue;
        }
        if (code < 32) {
          continue;
        }
        buffer += ch;
      }
    };
    input.on("data", onData);
  });
}
function createNonTtyLineReader(input) {
  const rl = createInterface({ input, terminal: false });
  const lineQueue = [];
  const waiterQueue = [];
  const errorQueue = [];
  let closed = false;
  let error = null;
  rl.on("line", (line) => {
    const waiter = waiterQueue.shift();
    if (waiter) {
      waiter(line);
    } else {
      lineQueue.push(line);
    }
  });
  rl.on("close", () => {
    closed = true;
    while (waiterQueue.length > 0) {
      const w = waiterQueue.shift();
      errorQueue.shift();
      w("");
    }
  });
  rl.on("error", (err) => {
    error = err;
    while (errorQueue.length > 0) {
      const r = errorQueue.shift();
      waiterQueue.shift();
      r(err);
    }
  });
  return {
    next() {
      if (error) return Promise.reject(error);
      const queued = lineQueue.shift();
      if (queued !== void 0) return Promise.resolve(queued);
      if (closed) return Promise.resolve("");
      return new Promise((resolve, reject) => {
        waiterQueue.push(resolve);
        errorQueue.push(reject);
      });
    }
  };
}

export {
  runSecureStoreInit,
  runSecureStoreUnlock,
  runSecureStoreLock,
  runSecureStoreMigrate,
  runSecureStoreDisable,
  runSecureStoreStatus,
  MIN_PASSPHRASE_LENGTH,
  renderInitReport,
  renderUnlockReport,
  renderLockReport,
  renderMigrateReport,
  renderDisableReport,
  renderStatusReport,
  createPassphraseReader
};
//# sourceMappingURL=chunk-CK5NTM2S.js.map