#!/usr/bin/env node
import {
  CONFIG_PATH,
  LOG_DIR
} from "./chunk-7RSBFN2G.js";

// ../../packages/shared/dist/logger.js
import { lstatSync, mkdirSync, readdirSync, renameSync, statSync, symlinkSync, unlinkSync } from "fs";
import { homedir } from "os";
import { basename, join } from "path";
import pino from "pino";
var DEFAULT_LOG_DIR = `${homedir()}/.dev-anywhere/logs`;
var DEFAULT_LOG_RETENTION = 50;
var PROCESS_LOG_RUN_ID = sanitizeRunId(`${(/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-")}-${process.pid}`);
function sanitizeRunId(runId) {
  return runId.replace(/[^a-zA-Z0-9._-]/g, "_");
}
function linkLatestLog(logDir, name, filePath, runId) {
  const latestPath = join(logDir, `${name}.log`);
  try {
    const stat = lstatSync(latestPath);
    if (stat.isSymbolicLink()) {
      unlinkSync(latestPath);
    } else {
      renameSync(latestPath, join(logDir, `${name}-legacy-${runId}.log`));
    }
  } catch (err) {
    const code = err.code;
    if (code !== "ENOENT")
      return;
  }
  try {
    symlinkSync(basename(filePath), latestPath);
  } catch {
  }
}
function resolveRetention(retention) {
  if (retention === void 0)
    return DEFAULT_LOG_RETENTION;
  return Number.isFinite(retention) && retention >= 0 ? Math.floor(retention) : DEFAULT_LOG_RETENTION;
}
function pruneOldLogs(logDir, name, currentFilePath, retention) {
  const keep = resolveRetention(retention);
  if (keep === 0)
    return;
  const currentFileName = basename(currentFilePath);
  const prefix = `${name}-`;
  const candidates = readdirSync(logDir).filter((entry) => entry.startsWith(prefix) && entry.endsWith(".log") && entry !== currentFileName).map((entry) => {
    const path = join(logDir, entry);
    try {
      return { path, mtimeMs: statSync(path).mtimeMs };
    } catch {
      return null;
    }
  }).filter((entry) => entry !== null).sort((a, b) => b.mtimeMs - a.mtimeMs);
  for (const stale of candidates.slice(Math.max(0, keep - 1))) {
    try {
      unlinkSync(stale.path);
    } catch {
    }
  }
}
var loggerMetaMap = /* @__PURE__ */ new WeakMap();
function buildPinoLogger(options) {
  const { name, level = "info", logDir = DEFAULT_LOG_DIR, retention, stdout = false, silent = false, sync = false } = options;
  if (silent) {
    return { logger: pino({ level: "silent" }), destination: null };
  }
  mkdirSync(logDir, { recursive: true });
  const runId = PROCESS_LOG_RUN_ID;
  const filePath = join(logDir, `${name}-${runId}.log`);
  linkLatestLog(logDir, name, filePath, runId);
  pruneOldLogs(logDir, name, filePath, retention);
  const destination = pino.destination({ dest: filePath, sync });
  const streams = [{ stream: destination }];
  if (stdout) {
    streams.unshift({ stream: process.stdout });
  }
  return { logger: pino({ level }, pino.multistream(streams)), destination };
}
function createLogger(options) {
  let real = null;
  const meta = { materialized: false, destination: null };
  const ensure = () => {
    if (!real) {
      const built = buildPinoLogger(options);
      real = built.logger;
      meta.materialized = true;
      meta.destination = built.destination;
    }
    return real;
  };
  const proxy = new Proxy(/* @__PURE__ */ Object.create(null), {
    get(_target, prop) {
      const target = ensure();
      const value = Reflect.get(target, prop, target);
      return typeof value === "function" ? value.bind(target) : value;
    },
    set(_target, prop, value) {
      return Reflect.set(ensure(), prop, value);
    },
    has(_target, prop) {
      return Reflect.has(ensure(), prop);
    },
    ownKeys() {
      return Reflect.ownKeys(ensure());
    },
    getOwnPropertyDescriptor(_target, prop) {
      return Reflect.getOwnPropertyDescriptor(ensure(), prop);
    }
  });
  loggerMetaMap.set(proxy, meta);
  return proxy;
}
async function flushLogger(logger, timeoutMs = 200) {
  const meta = loggerMetaMap.get(logger);
  if (!meta || !meta.materialized)
    return;
  const dest = meta.destination;
  if (!dest)
    return;
  if (dest.fd == null || dest.fd < 0) {
    const opened = await new Promise((resolve) => {
      const timer = setTimeout(() => resolve(false), timeoutMs);
      dest.once?.("ready", () => {
        clearTimeout(timer);
        resolve(true);
      });
      dest.once?.("error", () => {
        clearTimeout(timer);
        resolve(false);
      });
    });
    if (!opened)
      return;
  }
  try {
    dest.flushSync?.();
  } catch {
  }
}

// src/common/logger.ts
import { existsSync, readFileSync } from "fs";

// src/common/runtime-env.ts
var VALID_LOG_LEVELS = [
  "trace",
  "debug",
  "info",
  "warn",
  "error",
  "fatal",
  "silent"
];
function parseLogLevel(value) {
  if (!value) return void 0;
  if (VALID_LOG_LEVELS.includes(value)) return value;
  throw new Error(
    `Invalid LOG_LEVEL=${JSON.stringify(value)}; expected one of ${VALID_LOG_LEVELS.join(", ")}`
  );
}
function parsePort(value, source) {
  if (!value) return void 0;
  const port = Number(value);
  if (!Number.isInteger(port) || port < 1 || port > 65535) {
    throw new Error(`Invalid ${source}=${JSON.stringify(value)}: expected TCP port 1-65535`);
  }
  return port;
}
function nonEmpty(value) {
  return value && value.length > 0 ? value : void 0;
}
function loadProxyRuntimeEnv(env2 = process.env) {
  return {
    relayUrl: nonEmpty(env2.RELAY_URL),
    relayProxyToken: nonEmpty(env2.RELAY_PROXY_TOKEN),
    hookPort: parsePort(env2.DEV_ANYWHERE_HOOK_PORT, "DEV_ANYWHERE_HOOK_PORT"),
    claudeBin: nonEmpty(env2.CLAUDE_BIN),
    codexBin: nonEmpty(env2.CODEX_BIN),
    logLevel: parseLogLevel(env2.LOG_LEVEL),
    isVitest: !!env2.VITEST
  };
}

// src/common/logger.ts
var env = loadProxyRuntimeEnv();
function readConfigLogLevel() {
  if (env.logLevel) return void 0;
  if (!existsSync(CONFIG_PATH)) return void 0;
  try {
    const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
    if (typeof raw.logLevel !== "string") return void 0;
    return VALID_LOG_LEVELS.includes(raw.logLevel) ? raw.logLevel : void 0;
  } catch {
    return void 0;
  }
}
var overrideLevel = env.logLevel ?? readConfigLogLevel();
var serviceLogger = createLogger({
  name: "service",
  level: overrideLevel ?? "info",
  logDir: LOG_DIR,
  silent: env.isVitest
});
var terminalLogger = createLogger({
  name: "terminal",
  level: overrideLevel ?? "debug",
  logDir: LOG_DIR,
  silent: env.isVitest
});

export {
  flushLogger,
  VALID_LOG_LEVELS,
  loadProxyRuntimeEnv,
  serviceLogger,
  terminalLogger
};
//# sourceMappingURL=chunk-LWDOXOWY.js.map