import { CliExitError } from './chunk-7M6WZ65V.js';
import { loadEnvGraph } from './chunk-VT7SXRVK.js';
import { createResolver, parseEnvSpecDotEnvFile, parseOverrideProvenanceMetadata, selectOverrideValuesFromEnv, runWithWorkspaceInfo, prompts_default } from './chunk-LTYLEVHC.js';
import { getBackendInfo, getDaemonClient, ensureKey, decryptValue, encryptValue } from './chunk-JE2IMKMO.js';
import { ResolutionError, SchemaError } from './chunk-DRL5U3PK.js';
import { createDebug } from './chunk-QGM3LRUO.js';
import { __name } from './chunk-IBAHCH6O.js';
import fs from 'fs';
import path from 'path';

function writeBackValue(itemKey, newValueStr, sourceFilePath) {
  if (!sourceFilePath) {
    return { updated: false, reason: "missing-source-file" };
  }
  const currentContents = fs.readFileSync(sourceFilePath, "utf-8");
  const file = parseEnvSpecDotEnvFile(currentContents);
  const item = file.configItems.find((i) => i.key === itemKey);
  if (!item) {
    return { updated: false, reason: "item-not-found" };
  }
  const dummyFile = parseEnvSpecDotEnvFile(`_=${newValueStr}`);
  const dummyItem = dummyFile.configItems[0];
  if (!dummyItem?.value) {
    return { updated: false, reason: "item-not-found" };
  }
  item.data.value = dummyItem.value;
  item.value = dummyItem.value;
  fs.writeFileSync(sourceFilePath, file.toString());
  return { updated: true };
}
__name(writeBackValue, "writeBackValue");

// src/lib/local-encrypt/builtin-resolver.ts
var LOCAL_PREFIX = "local:";
var PLUGIN_ICON = "mdi:fingerprint";
var pendingBatch;
function enqueueBatchEntry(entry) {
  let triggerBatch = false;
  if (!pendingBatch) {
    pendingBatch = [];
    triggerBatch = true;
  }
  pendingBatch.push(entry);
  if (triggerBatch) {
    setImmediate(() => executeBatch());
  }
}
__name(enqueueBatchEntry, "enqueueBatchEntry");
function enqueueDecrypt(ciphertext) {
  return new Promise((resolve, reject) => {
    enqueueBatchEntry({
      kind: "decrypt",
      ciphertext,
      resolve,
      reject
    });
  });
}
__name(enqueueDecrypt, "enqueueDecrypt");
function enqueuePrompt(execute) {
  return new Promise((resolve, reject) => {
    enqueueBatchEntry({
      kind: "prompt",
      execute,
      resolve,
      reject
    });
  });
}
__name(enqueuePrompt, "enqueuePrompt");
function bailRemaining(batch, startIndex, error) {
  for (let j = startIndex; j < batch.length; j++) {
    batch[j].reject(error);
  }
}
__name(bailRemaining, "bailRemaining");
async function executeBatch() {
  const batch = pendingBatch;
  pendingBatch = void 0;
  if (!batch?.length) return;
  batch.sort((a, b) => {
    if (a.kind === b.kind) return 0;
    return a.kind === "prompt" ? -1 : 1;
  });
  await ensureKey();
  for (let i = 0; i < batch.length; i++) {
    const entry = batch[i];
    try {
      if (entry.kind === "decrypt") {
        const plaintext = await decryptValue(entry.ciphertext);
        entry.resolve(plaintext);
      } else {
        const result = await entry.execute();
        entry.resolve(result);
      }
    } catch (err) {
      entry.reject(err);
      const msg = err instanceof Error ? err.message : String(err);
      if (msg.includes("cancelled") || msg.includes("canceled") || msg.includes("verification failed")) {
        bailRemaining(batch, i + 1, new ResolutionError("Skipped \u2014 user cancelled"));
        return;
      }
    }
  }
}
__name(executeBatch, "executeBatch");
function writeBackEncryptedValue(itemKey, ciphertext, sourceFilePath) {
  const prefixedCiphertext = `${LOCAL_PREFIX}${ciphertext}`;
  return writeBackValue(itemKey, `varlock("${prefixedCiphertext}")`, sourceFilePath);
}
__name(writeBackEncryptedValue, "writeBackEncryptedValue");
var VarlockResolver = createResolver({
  name: "varlock",
  label: "Decrypt locally encrypted value",
  icon: PLUGIN_ICON,
  impliesSensitive: true,
  argsSchema: {
    type: "mixed",
    arrayMinLength: 0
  },
  process() {
    const promptArg = this.objArgs?.prompt;
    const isPromptPositional = this.arrArgs?.length === 1 && this.arrArgs[0]?.isStatic && this.arrArgs[0].staticValue === "prompt";
    if (promptArg || isPromptPositional) {
      const parent = this.parent;
      const itemKey = parent?.key || "unknown";
      const dataSource = this.dataSource;
      const sourceFilePath = dataSource?.fullPath;
      return { mode: "prompt", itemKey, sourceFilePath };
    }
    if (!this.arrArgs || this.arrArgs.length !== 1) {
      throw new SchemaError("varlock() expects a single encrypted payload string, or prompt to enter a new value");
    }
    if (!this.arrArgs[0]?.isStatic) {
      throw new SchemaError("varlock() expects a single static encrypted payload string");
    }
    const payload = this.arrArgs[0].staticValue;
    if (typeof payload !== "string") {
      throw new SchemaError("varlock() expects a string argument");
    }
    return { mode: "decrypt", payload };
  },
  async resolve(state) {
    if (state.mode === "decrypt") {
      let ciphertext = state.payload;
      if (ciphertext.startsWith(LOCAL_PREFIX)) {
        ciphertext = ciphertext.slice(LOCAL_PREFIX.length);
      }
      try {
        return await enqueueDecrypt(ciphertext);
      } catch (err) {
        if (err instanceof ResolutionError) throw err;
        const backend = getBackendInfo();
        throw new ResolutionError(
          `Decryption failed: ${err instanceof Error ? err.message : err}`,
          {
            tip: [
              `Backend: ${backend.type} (${backend.hardwareBacked ? "hardware-backed" : "file-based"})`,
              "This usually means the value was encrypted with a different key or backend.",
              "Set a new value using `varlock encrypt` or `KEY=varlock(prompt)`."
            ].join("\n")
          }
        );
      }
    }
    const { itemKey, sourceFilePath } = state;
    return enqueuePrompt(async () => {
      const backend = getBackendInfo();
      if (backend.type === "secure-enclave" && backend.biometricAvailable) {
        const client = getDaemonClient();
        const ciphertext2 = await client.promptSecret({
          itemKey,
          message: `Enter the secret value for ${itemKey}:`
        });
        if (!ciphertext2) {
          throw new ResolutionError("Secret input was cancelled", {
            tip: "Run varlock again and enter a value, or replace prompt=1 with an encrypted value"
          });
        }
        const writeBackResult2 = writeBackEncryptedValue(itemKey, ciphertext2, sourceFilePath);
        if (!writeBackResult2.updated) {
          if (writeBackResult2.reason === "missing-source-file") {
            throw new ResolutionError(`Unable to persist encrypted value for ${itemKey}`, {
              tip: "varlock(prompt=1) can only persist values from file-backed sources. Use `varlock encrypt` to generate an encrypted value manually."
            });
          }
          throw new ResolutionError(`Unable to persist encrypted value for ${itemKey}`, {
            tip: `Could not find a writable \`${itemKey}=varlock(...)\` entry to update in ${sourceFilePath}.`
          });
        }
        return decryptValue(ciphertext2);
      }
      if (!process.stdout.isTTY || !process.stdin.isTTY) {
        throw new ResolutionError(
          `No encrypted value found for ${itemKey}`,
          {
            tip: `Run \`varlock encrypt --file ${sourceFilePath || "<your-env-file>"}\` to encrypt this value interactively.`
          }
        );
      }
      const rawValue = await prompts_default.password({ message: `Enter the secret value for ${itemKey}:`, hint: "for multi-line values, use `varlock encrypt`" });
      const isCanceled = typeof rawValue !== "string";
      if (isCanceled || !rawValue) {
        throw new ResolutionError("Secret input was cancelled", {
          tip: "Run varlock again and enter a value, or replace prompt=1 with an encrypted value"
        });
      }
      const ciphertext = await encryptValue(rawValue);
      const writeBackResult = writeBackEncryptedValue(itemKey, ciphertext, sourceFilePath);
      if (!writeBackResult.updated) {
        if (writeBackResult.reason === "missing-source-file") {
          throw new ResolutionError(`Unable to persist encrypted value for ${itemKey}`, {
            tip: "varlock(prompt=1) can only persist values from file-backed sources. Use `varlock encrypt` to generate an encrypted value manually."
          });
        }
        throw new ResolutionError(`Unable to persist encrypted value for ${itemKey}`, {
          tip: `Could not find a writable \`${itemKey}=varlock(...)\` entry to update in ${sourceFilePath}.`
        });
      }
      return rawValue;
    });
  }
});

// src/lib/local-encrypt/keychain-resolver.ts
function writeBackKeychainRef(itemKey, ref, sourceFilePath) {
  let argsStr;
  if (!ref.account && !ref.keychain) {
    argsStr = `"${ref.service}"`;
  } else {
    const parts = [`service="${ref.service}"`];
    if (ref.account) parts.push(`account="${ref.account}"`);
    if (ref.keychain) parts.push(`keychain="${ref.keychain}"`);
    argsStr = parts.join(", ");
  }
  writeBackValue(itemKey, `keychain(${argsStr})`, sourceFilePath);
}
__name(writeBackKeychainRef, "writeBackKeychainRef");
var KeychainResolver = createResolver({
  name: "keychain",
  label: "Read from macOS Keychain",
  icon: "mdi:key-chain",
  impliesSensitive: true,
  argsSchema: {
    type: "mixed",
    arrayMinLength: 0
  },
  process() {
    if (process.platform !== "darwin") {
      throw new SchemaError("keychain() is only supported on macOS");
    }
    const promptArg = this.objArgs?.prompt;
    const isPromptPositional = this.arrArgs?.length === 1 && this.arrArgs[0]?.isStatic && this.arrArgs[0].staticValue === "prompt";
    if (promptArg || isPromptPositional) {
      const parent = this.parent;
      const itemKey = parent?.key || "unknown";
      const dataSource = this.dataSource;
      const sourceFilePath = dataSource?.fullPath;
      return { mode: "prompt", itemKey, sourceFilePath };
    }
    const serviceArg = this.objArgs?.service;
    const accountArg = this.objArgs?.account;
    const keychainArg = this.objArgs?.keychain;
    const fieldArg = this.objArgs?.field;
    const account = accountArg?.isStatic ? accountArg.staticValue : void 0;
    const keychain = keychainArg?.isStatic ? keychainArg.staticValue : void 0;
    const field = fieldArg?.isStatic ? fieldArg.staticValue : void 0;
    if (serviceArg) {
      if (!serviceArg.isStatic || typeof serviceArg.staticValue !== "string") {
        throw new SchemaError("keychain() service must be a static string");
      }
      return {
        mode: "get",
        service: serviceArg.staticValue,
        account,
        keychain,
        field
      };
    }
    if (accountArg) {
      return {
        mode: "get",
        account,
        keychain,
        field
      };
    }
    if (this.arrArgs?.length === 1 && this.arrArgs[0]?.isStatic) {
      const value = this.arrArgs[0].staticValue;
      if (typeof value !== "string") {
        throw new SchemaError("keychain() expects a string service name");
      }
      return { mode: "get", service: value, field };
    }
    throw new SchemaError(
      'keychain() requires service name, account, or prompt mode. Usage: keychain(service="com.example"), keychain("com.example"), or keychain(prompt)'
    );
  },
  async resolve(state) {
    const client = getDaemonClient();
    if (state.mode === "get") {
      try {
        return await client.keychainGet({
          service: state.service,
          account: state.account,
          keychain: state.keychain,
          field: state.field
        });
      } catch (err) {
        throw new ResolutionError(
          `Failed to read keychain item: ${err instanceof Error ? err.message : err}`,
          {
            tip: [
              state.service ? `Service: ${state.service}` : null,
              state.account ? `Account: ${state.account}` : null,
              state.keychain ? `Keychain: ${state.keychain}` : null,
              state.field ? `Field: ${state.field}` : null,
              "Make sure the item exists in your Keychain and VarlockEnclave has access.",
              "You can grant access via: keychain(prompt)"
            ].filter(Boolean).join("\n")
          }
        );
      }
    }
    const { itemKey, sourceFilePath } = state;
    const selected = await client.keychainPick({ itemKey });
    if (!selected) {
      throw new ResolutionError("Keychain item selection was cancelled", {
        tip: 'Run varlock again and select an item, or use keychain(service="...") with an explicit service name'
      });
    }
    writeBackKeychainRef(itemKey, selected, sourceFilePath);
    try {
      return await client.keychainGet({
        service: selected.service,
        account: selected.account,
        keychain: selected.keychain
      });
    } catch (err) {
      throw new ResolutionError(
        `Selected keychain item but failed to read value: ${err instanceof Error ? err.message : err}`,
        {
          tip: "The item reference has been written to your config. Try running varlock again."
        }
      );
    }
  }
});
function readVarlockPackageJsonConfig(opts) {
  const cwd = opts?.cwd ?? process.cwd();
  const pkgPath = path.join(cwd, "package.json");
  if (!fs.existsSync(pkgPath)) return void 0;
  try {
    const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8"));
    if (pkg.varlock && typeof pkg.varlock === "object") {
      return pkg.varlock;
    }
  } catch {
  }
  return void 0;
}
__name(readVarlockPackageJsonConfig, "readVarlockPackageJsonConfig");

// src/lib/load-graph.ts
var debug = createDebug("varlock:load");
function getGraphEnvOverridesFromRuntimeEnv() {
  const provenance = parseOverrideProvenanceMetadata(process.env.__VARLOCK_ENV);
  if (!provenance) return void 0;
  return selectOverrideValuesFromEnv(process.env, provenance.overrideKeys);
}
__name(getGraphEnvOverridesFromRuntimeEnv, "getGraphEnvOverridesFromRuntimeEnv");
function normalizePkgLoadPath(pkgLoadPath) {
  if (Array.isArray(pkgLoadPath)) return pkgLoadPath;
  return [pkgLoadPath];
}
__name(normalizePkgLoadPath, "normalizePkgLoadPath");
function loadFromPaths(rawPaths, config) {
  const resolvedPaths = rawPaths.map((p) => path.resolve(p));
  if (resolvedPaths.length === 1) {
    debug("using path from %s: %s", config.source, resolvedPaths[0]);
  } else {
    debug("using %d paths from %s: %s", resolvedPaths.length, config.source, resolvedPaths.join(", "));
  }
  for (const resolvedPath of resolvedPaths) {
    if (!fs.existsSync(resolvedPath)) {
      throw new CliExitError(`${config.errorPrefix}: ${resolvedPath}`, {
        suggestion: config.errorSuggestion
      });
    }
  }
  return runWithWorkspaceInfo(() => loadEnvGraph({
    currentEnvFallback: config.currentEnvFallback,
    entryFilePaths: resolvedPaths,
    overrideValues: config.overrideValues,
    processEnvOverride: config.overrideValues,
    clearCache: config.clearCache,
    skipCache: config.skipCache,
    afterInit: /* @__PURE__ */ __name(async (g) => {
      g.registerResolver(VarlockResolver);
      g.registerResolver(KeychainResolver);
    }, "afterInit")
  }));
}
__name(loadFromPaths, "loadFromPaths");
function loadVarlockEnvGraph(opts) {
  const runtimeOverrideValues = getGraphEnvOverridesFromRuntimeEnv();
  const cliPaths = opts?.entryFilePaths?.filter(Boolean);
  if (cliPaths && cliPaths.length > 0) {
    return loadFromPaths(cliPaths, {
      source: "--path flag",
      errorPrefix: "The --path value does not exist",
      errorSuggestion: "Use `--path` to specify a valid file or directory.",
      currentEnvFallback: opts?.currentEnvFallback,
      overrideValues: runtimeOverrideValues,
      clearCache: opts?.clearCache,
      skipCache: opts?.skipCache
    });
  }
  const pkgLoadPath = readVarlockPackageJsonConfig()?.loadPath;
  const pkgLoadPaths = pkgLoadPath ? normalizePkgLoadPath(pkgLoadPath) : void 0;
  if (pkgLoadPaths) {
    return loadFromPaths(pkgLoadPaths, {
      source: "package.json varlock.loadPath",
      errorPrefix: "A path in `varlock.loadPath` configured in package.json does not exist",
      errorSuggestion: "Update `varlock.loadPath` in your package.json to point to valid files or directories.",
      currentEnvFallback: opts?.currentEnvFallback,
      overrideValues: runtimeOverrideValues,
      clearCache: opts?.clearCache,
      skipCache: opts?.skipCache
    });
  }
  debug("no path configured, using cwd: %s", process.cwd());
  return runWithWorkspaceInfo(() => loadEnvGraph({
    currentEnvFallback: opts?.currentEnvFallback,
    overrideValues: runtimeOverrideValues,
    processEnvOverride: runtimeOverrideValues,
    clearCache: opts?.clearCache,
    skipCache: opts?.skipCache,
    afterInit: /* @__PURE__ */ __name(async (g) => {
      g.registerResolver(VarlockResolver);
      g.registerResolver(KeychainResolver);
    }, "afterInit")
  }));
}
__name(loadVarlockEnvGraph, "loadVarlockEnvGraph");

export { loadVarlockEnvGraph, writeBackValue };
//# sourceMappingURL=chunk-5SI4EGRL.js.map
//# sourceMappingURL=chunk-5SI4EGRL.js.map