{"version":3,"file":"dev-logs.cjs","names":["join","stripAnsi","existsSync","mkdir","writeFile","appendFile","readFile","readFileSync","statSync","readdirSync"],"sources":["../src/dev-logs.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync, statSync } from \"node:fs\";\nimport { appendFile, mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { stripAnsi } from \"./dev-log-pipeline\";\n\nexport interface LogEntry {\n  timestamp: number;\n  source: string;\n  line: string;\n  isError?: boolean;\n}\n\nexport interface DevLogger {\n  logFile: string;\n  latestFile: string;\n  write: (entry: LogEntry) => Promise<void>;\n  readLatest: (opts?: { tail?: number }) => Promise<string>;\n}\n\nexport function getBosDir(configDir: string): string {\n  return join(configDir, \".bos\");\n}\n\nexport function getLogsDir(configDir: string): string {\n  return join(getBosDir(configDir), \"logs\");\n}\n\nexport function formatLogLine(entry: LogEntry): string {\n  const ts = new Date(entry.timestamp).toISOString();\n  const prefix = entry.isError ? \"ERR\" : \"OUT\";\n  const clean = stripAnsi(entry.line);\n  const head = `[${ts}] [${entry.source}] [${prefix}] `;\n  const pad = \" \".repeat(head.length);\n  const [first, ...rest] = clean.split(\"\\n\");\n  return [`${head}${first}`, ...rest.map((line) => `${pad}${line}`)].join(\"\\n\");\n}\n\nexport async function createDevLogger(configDir: string, description: string): Promise<DevLogger> {\n  const dir = getLogsDir(configDir);\n  if (!existsSync(dir)) {\n    await mkdir(dir, { recursive: true });\n  }\n\n  const now = new Date();\n  const ts = now.toISOString().replace(/[:.]/g, \"-\").slice(0, 19);\n  const logFile = join(dir, `dev-${ts}-${process.pid}.log`);\n  const latestFile = join(dir, `dev-latest-${process.pid}.log`);\n\n  const header =\n    `# everything-dev dev session: ${description}\\n` + `# Started: ${now.toISOString()}\\n\\n`;\n  // Overwrite each run so dev-latest.log is always actionable.\n  await writeFile(logFile, header, \"utf8\");\n  await writeFile(latestFile, header, \"utf8\");\n\n  let chain = Promise.resolve();\n  const enqueue = (fn: () => Promise<void>) => {\n    chain = chain.then(fn, fn);\n    return chain;\n  };\n\n  return {\n    logFile,\n    latestFile,\n    write: (entry) =>\n      enqueue(async () => {\n        const line = `${formatLogLine(entry)}\\n`;\n        await appendFile(logFile, line);\n        await appendFile(latestFile, line);\n      }),\n    readLatest: async (opts) => {\n      const text = await readFile(latestFile, \"utf8\").catch(() => \"\");\n      const tail = opts?.tail;\n      if (!tail || tail <= 0) return text;\n      const lines = text.split(\"\\n\");\n      return lines.slice(Math.max(0, lines.length - tail)).join(\"\\n\");\n    },\n  };\n}\n\nexport function resolveDevLatestFile(configDir: string): string {\n  const dir = getLogsDir(configDir);\n  const latestFile = join(dir, \"dev-latest.log\");\n  if (existsSync(latestFile)) return latestFile;\n  const STARTED_RE = /^# Started: (.+)$/m;\n  const startedMsOf = (name: string): number => {\n    const header = readFileSync(join(dir, name), \"utf8\").slice(0, 256);\n    const started = STARTED_RE.exec(header)?.[1];\n    const parsed = started ? Date.parse(started) : NaN;\n    return Number.isNaN(parsed) ? statSync(join(dir, name)).mtimeMs : parsed;\n  };\n  const pidOf = (name: string): number => Number(/^dev-latest-(\\d+)\\.log$/.exec(name)?.[1] ?? 0);\n  const candidates = readdirSync(dir)\n    .filter((name) => /^dev-latest-\\d+\\.log$/.test(name))\n    .map((name) => ({ name, startedMs: startedMsOf(name), pid: pidOf(name) }))\n    .sort((a, b) => b.startedMs - a.startedMs || b.pid - a.pid || a.name.localeCompare(b.name));\n  return candidates.length > 0 ? join(dir, candidates[0]!.name) : latestFile;\n}\n\nexport async function readDevLatestLog(\n  configDir: string,\n  opts?: { tail?: number },\n): Promise<string> {\n  const latestFile = resolveDevLatestFile(configDir);\n  const text = await readFile(latestFile, \"utf8\").catch(() => \"\");\n  const tail = opts?.tail;\n  if (!tail || tail <= 0) return text;\n  const lines = text.split(\"\\n\");\n  return lines.slice(Math.max(0, lines.length - tail)).join(\"\\n\");\n}\n"],"mappings":"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"}