claude-code-webui
Version:
Web-based interface for the Claude Code CLI with streaming chat interface
1,443 lines (1,425 loc) • 90.7 kB
JavaScript
#!/usr/bin/env node
var __defProp = Object.defineProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
// app.ts
import { Hono } from "hono";
import { cors } from "hono/cors";
// middleware/config.ts
import { createMiddleware } from "hono/factory";
function createConfigMiddleware(options) {
return createMiddleware(async (c, next) => {
c.set("config", options);
await next();
});
}
// utils/fs.ts
import { promises as fs } from "node:fs";
import { constants as fsConstants } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
async function readTextFile(path) {
return await fs.readFile(path, "utf8");
}
async function readBinaryFile(path) {
const buffer = await fs.readFile(path);
return new Uint8Array(buffer);
}
async function writeTextFile(path, content, options) {
await fs.writeFile(path, content, "utf8");
if (options?.mode !== void 0) {
await fs.chmod(path, options.mode);
}
}
async function exists(path) {
try {
await fs.access(path, fsConstants.F_OK);
return true;
} catch {
return false;
}
}
async function stat(path) {
const stats = await fs.stat(path);
return {
isFile: stats.isFile(),
isDirectory: stats.isDirectory(),
isSymlink: stats.isSymbolicLink(),
size: stats.size,
mtime: stats.mtime
};
}
async function* readDir(path) {
const entries = await fs.readdir(path, { withFileTypes: true });
for (const entry of entries) {
yield {
name: entry.name,
isFile: entry.isFile(),
isDirectory: entry.isDirectory(),
isSymlink: entry.isSymbolicLink()
};
}
}
async function withTempDir(callback) {
const tempDir = await fs.mkdtemp(join(tmpdir(), "claude-code-webui-temp-"));
try {
return await callback(tempDir);
} finally {
try {
await fs.rm(tempDir, { recursive: true, force: true });
} catch {
}
}
}
// utils/os.ts
import { homedir } from "node:os";
import process2 from "node:process";
function getEnv(key) {
return process2.env[key];
}
function getArgs() {
return process2.argv.slice(2);
}
function getPlatform() {
switch (process2.platform) {
case "win32":
return "windows";
case "darwin":
return "darwin";
case "linux":
return "linux";
default:
return "linux";
}
}
function getHomeDir() {
try {
return homedir();
} catch {
return void 0;
}
}
function exit(code) {
process2.exit(code);
}
// history/pathUtils.ts
async function getEncodedProjectName(projectPath) {
const homeDir = getHomeDir();
if (!homeDir) {
return null;
}
const projectsDir = `${homeDir}/.claude/projects`;
try {
const entries = [];
for await (const entry of readDir(projectsDir)) {
if (entry.isDirectory) {
entries.push(entry.name);
}
}
const normalizedPath = projectPath.replace(/\/$/, "");
const expectedEncoded = normalizedPath.replace(/[/\\:._]/g, "-");
if (entries.includes(expectedEncoded)) {
return expectedEncoded;
}
return null;
} catch {
return null;
}
}
function validateEncodedProjectName(encodedName) {
if (!encodedName) {
return false;
}
const dangerousChars = /[<>:"|?*\x00-\x1f\/\\]/;
if (dangerousChars.test(encodedName)) {
return false;
}
return true;
}
// node_modules/@logtape/logtape/dist/filter.js
function toFilter(filter) {
if (typeof filter === "function") return filter;
return getLevelFilter(filter);
}
function getLevelFilter(level) {
if (level == null) return () => false;
if (level === "fatal") return (record) => record.level === "fatal";
else if (level === "error") return (record) => record.level === "fatal" || record.level === "error";
else if (level === "warning") return (record) => record.level === "fatal" || record.level === "error" || record.level === "warning";
else if (level === "info") return (record) => record.level === "fatal" || record.level === "error" || record.level === "warning" || record.level === "info";
else if (level === "debug") return (record) => record.level === "fatal" || record.level === "error" || record.level === "warning" || record.level === "info" || record.level === "debug";
else if (level === "trace") return () => true;
throw new TypeError(`Invalid log level: ${level}.`);
}
// node_modules/@logtape/logtape/dist/level.js
var logLevels = [
"trace",
"debug",
"info",
"warning",
"error",
"fatal"
];
function compareLogLevel(a, b) {
const aIndex = logLevels.indexOf(a);
if (aIndex < 0) throw new TypeError(`Invalid log level: ${JSON.stringify(a)}.`);
const bIndex = logLevels.indexOf(b);
if (bIndex < 0) throw new TypeError(`Invalid log level: ${JSON.stringify(b)}.`);
return aIndex - bIndex;
}
// node_modules/@logtape/logtape/dist/logger.js
function getLogger(category = []) {
return LoggerImpl.getLogger(category);
}
var globalRootLoggerSymbol = Symbol.for("logtape.rootLogger");
var LoggerImpl = class LoggerImpl2 {
parent;
children;
category;
sinks;
parentSinks = "inherit";
filters;
lowestLevel = "trace";
contextLocalStorage;
static getLogger(category = []) {
let rootLogger = globalRootLoggerSymbol in globalThis ? globalThis[globalRootLoggerSymbol] ?? null : null;
if (rootLogger == null) {
rootLogger = new LoggerImpl2(null, []);
globalThis[globalRootLoggerSymbol] = rootLogger;
}
if (typeof category === "string") return rootLogger.getChild(category);
if (category.length === 0) return rootLogger;
return rootLogger.getChild(category);
}
constructor(parent, category) {
this.parent = parent;
this.children = {};
this.category = category;
this.sinks = [];
this.filters = [];
}
getChild(subcategory) {
const name = typeof subcategory === "string" ? subcategory : subcategory[0];
const childRef = this.children[name];
let child = childRef instanceof LoggerImpl2 ? childRef : childRef?.deref();
if (child == null) {
child = new LoggerImpl2(this, [...this.category, name]);
this.children[name] = "WeakRef" in globalThis ? new WeakRef(child) : child;
}
if (typeof subcategory === "string" || subcategory.length === 1) return child;
return child.getChild(subcategory.slice(1));
}
/**
* Reset the logger. This removes all sinks and filters from the logger.
*/
reset() {
while (this.sinks.length > 0) this.sinks.shift();
this.parentSinks = "inherit";
while (this.filters.length > 0) this.filters.shift();
this.lowestLevel = "trace";
}
/**
* Reset the logger and all its descendants. This removes all sinks and
* filters from the logger and all its descendants.
*/
resetDescendants() {
for (const child of Object.values(this.children)) {
const logger2 = child instanceof LoggerImpl2 ? child : child.deref();
if (logger2 != null) logger2.resetDescendants();
}
this.reset();
}
with(properties) {
return new LoggerCtx(this, { ...properties });
}
filter(record) {
for (const filter of this.filters) if (!filter(record)) return false;
if (this.filters.length < 1) return this.parent?.filter(record) ?? true;
return true;
}
*getSinks(level) {
if (this.lowestLevel === null || compareLogLevel(level, this.lowestLevel) < 0) return;
if (this.parent != null && this.parentSinks === "inherit") for (const sink of this.parent.getSinks(level)) yield sink;
for (const sink of this.sinks) yield sink;
}
emit(record, bypassSinks) {
const fullRecord = "category" in record ? record : {
...record,
category: this.category
};
if (this.lowestLevel === null || compareLogLevel(fullRecord.level, this.lowestLevel) < 0 || !this.filter(fullRecord)) return;
for (const sink of this.getSinks(fullRecord.level)) {
if (bypassSinks?.has(sink)) continue;
try {
sink(fullRecord);
} catch (error) {
const bypassSinks2 = new Set(bypassSinks);
bypassSinks2.add(sink);
metaLogger.log("fatal", "Failed to emit a log record to sink {sink}: {error}", {
sink,
error,
record: fullRecord
}, bypassSinks2);
}
}
}
log(level, rawMessage, properties, bypassSinks) {
const implicitContext = LoggerImpl2.getLogger().contextLocalStorage?.getStore() ?? {};
let cachedProps = void 0;
const record = typeof properties === "function" ? {
category: this.category,
level,
timestamp: Date.now(),
get message() {
return parseMessageTemplate(rawMessage, this.properties);
},
rawMessage,
get properties() {
if (cachedProps == null) cachedProps = {
...implicitContext,
...properties()
};
return cachedProps;
}
} : {
category: this.category,
level,
timestamp: Date.now(),
message: parseMessageTemplate(rawMessage, {
...implicitContext,
...properties
}),
rawMessage,
properties: {
...implicitContext,
...properties
}
};
this.emit(record, bypassSinks);
}
logLazily(level, callback, properties = {}) {
const implicitContext = LoggerImpl2.getLogger().contextLocalStorage?.getStore() ?? {};
let rawMessage = void 0;
let msg = void 0;
function realizeMessage() {
if (msg == null || rawMessage == null) {
msg = callback((tpl, ...values) => {
rawMessage = tpl;
return renderMessage(tpl, values);
});
if (rawMessage == null) throw new TypeError("No log record was made.");
}
return [msg, rawMessage];
}
this.emit({
category: this.category,
level,
get message() {
return realizeMessage()[0];
},
get rawMessage() {
return realizeMessage()[1];
},
timestamp: Date.now(),
properties: {
...implicitContext,
...properties
}
});
}
logTemplate(level, messageTemplate, values, properties = {}) {
const implicitContext = LoggerImpl2.getLogger().contextLocalStorage?.getStore() ?? {};
this.emit({
category: this.category,
level,
message: renderMessage(messageTemplate, values),
rawMessage: messageTemplate,
timestamp: Date.now(),
properties: {
...implicitContext,
...properties
}
});
}
trace(message, ...values) {
if (typeof message === "string") this.log("trace", message, values[0] ?? {});
else if (typeof message === "function") this.logLazily("trace", message);
else if (!Array.isArray(message)) this.log("trace", "{*}", message);
else this.logTemplate("trace", message, values);
}
debug(message, ...values) {
if (typeof message === "string") this.log("debug", message, values[0] ?? {});
else if (typeof message === "function") this.logLazily("debug", message);
else if (!Array.isArray(message)) this.log("debug", "{*}", message);
else this.logTemplate("debug", message, values);
}
info(message, ...values) {
if (typeof message === "string") this.log("info", message, values[0] ?? {});
else if (typeof message === "function") this.logLazily("info", message);
else if (!Array.isArray(message)) this.log("info", "{*}", message);
else this.logTemplate("info", message, values);
}
warn(message, ...values) {
if (typeof message === "string") this.log("warning", message, values[0] ?? {});
else if (typeof message === "function") this.logLazily("warning", message);
else if (!Array.isArray(message)) this.log("warning", "{*}", message);
else this.logTemplate("warning", message, values);
}
warning(message, ...values) {
this.warn(message, ...values);
}
error(message, ...values) {
if (typeof message === "string") this.log("error", message, values[0] ?? {});
else if (typeof message === "function") this.logLazily("error", message);
else if (!Array.isArray(message)) this.log("error", "{*}", message);
else this.logTemplate("error", message, values);
}
fatal(message, ...values) {
if (typeof message === "string") this.log("fatal", message, values[0] ?? {});
else if (typeof message === "function") this.logLazily("fatal", message);
else if (!Array.isArray(message)) this.log("fatal", "{*}", message);
else this.logTemplate("fatal", message, values);
}
};
var LoggerCtx = class LoggerCtx2 {
logger;
properties;
constructor(logger2, properties) {
this.logger = logger2;
this.properties = properties;
}
get category() {
return this.logger.category;
}
get parent() {
return this.logger.parent;
}
getChild(subcategory) {
return this.logger.getChild(subcategory).with(this.properties);
}
with(properties) {
return new LoggerCtx2(this.logger, {
...this.properties,
...properties
});
}
log(level, message, properties, bypassSinks) {
this.logger.log(level, message, typeof properties === "function" ? () => ({
...this.properties,
...properties()
}) : {
...this.properties,
...properties
}, bypassSinks);
}
logLazily(level, callback) {
this.logger.logLazily(level, callback, this.properties);
}
logTemplate(level, messageTemplate, values) {
this.logger.logTemplate(level, messageTemplate, values, this.properties);
}
emit(record) {
const recordWithContext = {
...record,
properties: {
...this.properties,
...record.properties
}
};
this.logger.emit(recordWithContext);
}
trace(message, ...values) {
if (typeof message === "string") this.log("trace", message, values[0] ?? {});
else if (typeof message === "function") this.logLazily("trace", message);
else if (!Array.isArray(message)) this.log("trace", "{*}", message);
else this.logTemplate("trace", message, values);
}
debug(message, ...values) {
if (typeof message === "string") this.log("debug", message, values[0] ?? {});
else if (typeof message === "function") this.logLazily("debug", message);
else if (!Array.isArray(message)) this.log("debug", "{*}", message);
else this.logTemplate("debug", message, values);
}
info(message, ...values) {
if (typeof message === "string") this.log("info", message, values[0] ?? {});
else if (typeof message === "function") this.logLazily("info", message);
else if (!Array.isArray(message)) this.log("info", "{*}", message);
else this.logTemplate("info", message, values);
}
warn(message, ...values) {
if (typeof message === "string") this.log("warning", message, values[0] ?? {});
else if (typeof message === "function") this.logLazily("warning", message);
else if (!Array.isArray(message)) this.log("warning", "{*}", message);
else this.logTemplate("warning", message, values);
}
warning(message, ...values) {
this.warn(message, ...values);
}
error(message, ...values) {
if (typeof message === "string") this.log("error", message, values[0] ?? {});
else if (typeof message === "function") this.logLazily("error", message);
else if (!Array.isArray(message)) this.log("error", "{*}", message);
else this.logTemplate("error", message, values);
}
fatal(message, ...values) {
if (typeof message === "string") this.log("fatal", message, values[0] ?? {});
else if (typeof message === "function") this.logLazily("fatal", message);
else if (!Array.isArray(message)) this.log("fatal", "{*}", message);
else this.logTemplate("fatal", message, values);
}
};
var metaLogger = LoggerImpl.getLogger(["logtape", "meta"]);
function parseMessageTemplate(template, properties) {
const length = template.length;
if (length === 0) return [""];
if (!template.includes("{")) return [template];
const message = [];
let startIndex = 0;
for (let i = 0; i < length; i++) {
const char = template[i];
if (char === "{") {
const nextChar = i + 1 < length ? template[i + 1] : "";
if (nextChar === "{") {
i++;
continue;
}
const closeIndex = template.indexOf("}", i + 1);
if (closeIndex === -1) continue;
const beforeText = template.slice(startIndex, i);
message.push(beforeText.replace(/{{/g, "{").replace(/}}/g, "}"));
const key = template.slice(i + 1, closeIndex);
let prop;
const trimmedKey = key.trim();
if (trimmedKey === "*") prop = key in properties ? properties[key] : "*" in properties ? properties["*"] : properties;
else if (key !== trimmedKey) prop = key in properties ? properties[key] : properties[trimmedKey];
else prop = properties[key];
message.push(prop);
i = closeIndex;
startIndex = i + 1;
} else if (char === "}" && i + 1 < length && template[i + 1] === "}") i++;
}
const remainingText = template.slice(startIndex);
message.push(remainingText.replace(/{{/g, "{").replace(/}}/g, "}"));
return message;
}
function renderMessage(template, values) {
const args = [];
for (let i = 0; i < template.length; i++) {
args.push(template[i]);
if (i < values.length) args.push(values[i]);
}
return args;
}
// node_modules/@logtape/logtape/dist/util.node.js
var util_node_exports = {};
__export(util_node_exports, {
inspect: () => inspect
});
import util from "node:util";
function inspect(obj, options) {
return util.inspect(obj, options);
}
// node_modules/@logtape/logtape/dist/formatter.js
var levelAbbreviations = {
"trace": "TRC",
"debug": "DBG",
"info": "INF",
"warning": "WRN",
"error": "ERR",
"fatal": "FTL"
};
var inspect2 = typeof document !== "undefined" || typeof navigator !== "undefined" && navigator.product === "ReactNative" ? (v) => JSON.stringify(v) : "Deno" in globalThis && "inspect" in globalThis.Deno && typeof globalThis.Deno.inspect === "function" ? (v, opts) => globalThis.Deno.inspect(v, {
strAbbreviateSize: Infinity,
iterableLimit: Infinity,
...opts
}) : util_node_exports != null && "inspect" in util_node_exports && typeof inspect === "function" ? (v, opts) => inspect(v, {
maxArrayLength: Infinity,
maxStringLength: Infinity,
...opts
}) : (v) => JSON.stringify(v);
function padZero(num) {
return num < 10 ? `0${num}` : `${num}`;
}
function padThree(num) {
return num < 10 ? `00${num}` : num < 100 ? `0${num}` : `${num}`;
}
var timestampFormatters = {
"date-time-timezone": (ts) => {
const d = new Date(ts);
const year = d.getUTCFullYear();
const month = padZero(d.getUTCMonth() + 1);
const day = padZero(d.getUTCDate());
const hour = padZero(d.getUTCHours());
const minute = padZero(d.getUTCMinutes());
const second = padZero(d.getUTCSeconds());
const ms = padThree(d.getUTCMilliseconds());
return `${year}-${month}-${day} ${hour}:${minute}:${second}.${ms} +00:00`;
},
"date-time-tz": (ts) => {
const d = new Date(ts);
const year = d.getUTCFullYear();
const month = padZero(d.getUTCMonth() + 1);
const day = padZero(d.getUTCDate());
const hour = padZero(d.getUTCHours());
const minute = padZero(d.getUTCMinutes());
const second = padZero(d.getUTCSeconds());
const ms = padThree(d.getUTCMilliseconds());
return `${year}-${month}-${day} ${hour}:${minute}:${second}.${ms} +00`;
},
"date-time": (ts) => {
const d = new Date(ts);
const year = d.getUTCFullYear();
const month = padZero(d.getUTCMonth() + 1);
const day = padZero(d.getUTCDate());
const hour = padZero(d.getUTCHours());
const minute = padZero(d.getUTCMinutes());
const second = padZero(d.getUTCSeconds());
const ms = padThree(d.getUTCMilliseconds());
return `${year}-${month}-${day} ${hour}:${minute}:${second}.${ms}`;
},
"time-timezone": (ts) => {
const d = new Date(ts);
const hour = padZero(d.getUTCHours());
const minute = padZero(d.getUTCMinutes());
const second = padZero(d.getUTCSeconds());
const ms = padThree(d.getUTCMilliseconds());
return `${hour}:${minute}:${second}.${ms} +00:00`;
},
"time-tz": (ts) => {
const d = new Date(ts);
const hour = padZero(d.getUTCHours());
const minute = padZero(d.getUTCMinutes());
const second = padZero(d.getUTCSeconds());
const ms = padThree(d.getUTCMilliseconds());
return `${hour}:${minute}:${second}.${ms} +00`;
},
"time": (ts) => {
const d = new Date(ts);
const hour = padZero(d.getUTCHours());
const minute = padZero(d.getUTCMinutes());
const second = padZero(d.getUTCSeconds());
const ms = padThree(d.getUTCMilliseconds());
return `${hour}:${minute}:${second}.${ms}`;
},
"date": (ts) => {
const d = new Date(ts);
const year = d.getUTCFullYear();
const month = padZero(d.getUTCMonth() + 1);
const day = padZero(d.getUTCDate());
return `${year}-${month}-${day}`;
},
"rfc3339": (ts) => new Date(ts).toISOString(),
"none": () => null
};
var levelRenderersCache = {
ABBR: levelAbbreviations,
abbr: {
trace: "trc",
debug: "dbg",
info: "inf",
warning: "wrn",
error: "err",
fatal: "ftl"
},
FULL: {
trace: "TRACE",
debug: "DEBUG",
info: "INFO",
warning: "WARNING",
error: "ERROR",
fatal: "FATAL"
},
full: {
trace: "trace",
debug: "debug",
info: "info",
warning: "warning",
error: "error",
fatal: "fatal"
},
L: {
trace: "T",
debug: "D",
info: "I",
warning: "W",
error: "E",
fatal: "F"
},
l: {
trace: "t",
debug: "d",
info: "i",
warning: "w",
error: "e",
fatal: "f"
}
};
function getTextFormatter(options = {}) {
const timestampRenderer = (() => {
const tsOption = options.timestamp;
if (tsOption == null) return timestampFormatters["date-time-timezone"];
else if (tsOption === "disabled") return timestampFormatters["none"];
else if (typeof tsOption === "string" && tsOption in timestampFormatters) return timestampFormatters[tsOption];
else return tsOption;
})();
const categorySeparator = options.category ?? "\xB7";
const valueRenderer = options.value ?? inspect2;
const levelRenderer = (() => {
const levelOption = options.level;
if (levelOption == null || levelOption === "ABBR") return (level) => levelRenderersCache.ABBR[level];
else if (levelOption === "abbr") return (level) => levelRenderersCache.abbr[level];
else if (levelOption === "FULL") return (level) => levelRenderersCache.FULL[level];
else if (levelOption === "full") return (level) => levelRenderersCache.full[level];
else if (levelOption === "L") return (level) => levelRenderersCache.L[level];
else if (levelOption === "l") return (level) => levelRenderersCache.l[level];
else return levelOption;
})();
const formatter = options.format ?? (({ timestamp, level, category, message }) => `${timestamp ? `${timestamp} ` : ""}[${level}] ${category}: ${message}`);
return (record) => {
const msgParts = record.message;
const msgLen = msgParts.length;
let message;
if (msgLen === 1) message = msgParts[0];
else if (msgLen <= 6) {
message = "";
for (let i = 0; i < msgLen; i++) message += i % 2 === 0 ? msgParts[i] : valueRenderer(msgParts[i]);
} else {
const parts = new Array(msgLen);
for (let i = 0; i < msgLen; i++) parts[i] = i % 2 === 0 ? msgParts[i] : valueRenderer(msgParts[i]);
message = parts.join("");
}
const timestamp = timestampRenderer(record.timestamp);
const level = levelRenderer(record.level);
const category = typeof categorySeparator === "function" ? categorySeparator(record.category) : record.category.join(categorySeparator);
const values = {
timestamp,
level,
category,
message,
record
};
return `${formatter(values)}
`;
};
}
var defaultTextFormatter = getTextFormatter();
var RESET = "\x1B[0m";
var ansiColors = {
black: "\x1B[30m",
red: "\x1B[31m",
green: "\x1B[32m",
yellow: "\x1B[33m",
blue: "\x1B[34m",
magenta: "\x1B[35m",
cyan: "\x1B[36m",
white: "\x1B[37m"
};
var ansiStyles = {
bold: "\x1B[1m",
dim: "\x1B[2m",
italic: "\x1B[3m",
underline: "\x1B[4m",
strikethrough: "\x1B[9m"
};
var defaultLevelColors = {
trace: null,
debug: "blue",
info: "green",
warning: "yellow",
error: "red",
fatal: "magenta"
};
function getAnsiColorFormatter(options = {}) {
const format = options.format;
const timestampStyle = typeof options.timestampStyle === "undefined" ? "dim" : options.timestampStyle;
const timestampColor = options.timestampColor ?? null;
const timestampPrefix = `${timestampStyle == null ? "" : ansiStyles[timestampStyle]}${timestampColor == null ? "" : ansiColors[timestampColor]}`;
const timestampSuffix = timestampStyle == null && timestampColor == null ? "" : RESET;
const levelStyle = typeof options.levelStyle === "undefined" ? "bold" : options.levelStyle;
const levelColors = options.levelColors ?? defaultLevelColors;
const categoryStyle = typeof options.categoryStyle === "undefined" ? "dim" : options.categoryStyle;
const categoryColor = options.categoryColor ?? null;
const categoryPrefix = `${categoryStyle == null ? "" : ansiStyles[categoryStyle]}${categoryColor == null ? "" : ansiColors[categoryColor]}`;
const categorySuffix = categoryStyle == null && categoryColor == null ? "" : RESET;
return getTextFormatter({
timestamp: "date-time-tz",
value(value) {
return inspect2(value, { colors: true });
},
...options,
format({ timestamp, level, category, message, record }) {
const levelColor = levelColors[record.level];
timestamp = `${timestampPrefix}${timestamp}${timestampSuffix}`;
level = `${levelStyle == null ? "" : ansiStyles[levelStyle]}${levelColor == null ? "" : ansiColors[levelColor]}${level}${levelStyle == null && levelColor == null ? "" : RESET}`;
return format == null ? `${timestamp} ${level} ${categoryPrefix}${category}:${categorySuffix} ${message}` : format({
timestamp,
level,
category: `${categoryPrefix}${category}${categorySuffix}`,
message,
record
});
}
});
}
var ansiColorFormatter = getAnsiColorFormatter();
function getJsonLinesFormatter(options = {}) {
if (!options.categorySeparator && !options.message && !options.properties) return (record) => {
if (record.message.length === 3) return JSON.stringify({
"@timestamp": new Date(record.timestamp).toISOString(),
level: record.level === "warning" ? "WARN" : record.level.toUpperCase(),
message: record.message[0] + JSON.stringify(record.message[1]) + record.message[2],
logger: record.category.join("."),
properties: record.properties
}) + "\n";
if (record.message.length === 1) return JSON.stringify({
"@timestamp": new Date(record.timestamp).toISOString(),
level: record.level === "warning" ? "WARN" : record.level.toUpperCase(),
message: record.message[0],
logger: record.category.join("."),
properties: record.properties
}) + "\n";
let msg = record.message[0];
for (let i = 1; i < record.message.length; i++) msg += i & 1 ? JSON.stringify(record.message[i]) : record.message[i];
return JSON.stringify({
"@timestamp": new Date(record.timestamp).toISOString(),
level: record.level === "warning" ? "WARN" : record.level.toUpperCase(),
message: msg,
logger: record.category.join("."),
properties: record.properties
}) + "\n";
};
const isTemplateMessage = options.message === "template";
const propertiesOption = options.properties ?? "nest:properties";
let joinCategory;
if (typeof options.categorySeparator === "function") joinCategory = options.categorySeparator;
else {
const separator = options.categorySeparator ?? ".";
joinCategory = (category) => category.join(separator);
}
let getProperties;
if (propertiesOption === "flatten") getProperties = (properties) => properties;
else if (propertiesOption.startsWith("prepend:")) {
const prefix = propertiesOption.substring(8);
if (prefix === "") throw new TypeError(`Invalid properties option: ${JSON.stringify(propertiesOption)}. It must be of the form "prepend:<prefix>" where <prefix> is a non-empty string.`);
getProperties = (properties) => {
const result = {};
for (const key in properties) result[`${prefix}${key}`] = properties[key];
return result;
};
} else if (propertiesOption.startsWith("nest:")) {
const key = propertiesOption.substring(5);
getProperties = (properties) => ({ [key]: properties });
} else throw new TypeError(`Invalid properties option: ${JSON.stringify(propertiesOption)}. It must be "flatten", "prepend:<prefix>", or "nest:<key>".`);
let getMessage;
if (isTemplateMessage) getMessage = (record) => {
if (typeof record.rawMessage === "string") return record.rawMessage;
let msg = "";
for (let i = 0; i < record.rawMessage.length; i++) msg += i % 2 < 1 ? record.rawMessage[i] : "{}";
return msg;
};
else getMessage = (record) => {
const msgLen = record.message.length;
if (msgLen === 1) return record.message[0];
let msg = "";
for (let i = 0; i < msgLen; i++) msg += i % 2 < 1 ? record.message[i] : JSON.stringify(record.message[i]);
return msg;
};
return (record) => {
return JSON.stringify({
"@timestamp": new Date(record.timestamp).toISOString(),
level: record.level === "warning" ? "WARN" : record.level.toUpperCase(),
message: getMessage(record),
logger: joinCategory(record.category),
...getProperties(record.properties)
}) + "\n";
};
}
var jsonLinesFormatter = getJsonLinesFormatter();
var logLevelStyles = {
"trace": "background-color: gray; color: white;",
"debug": "background-color: gray; color: white;",
"info": "background-color: white; color: black;",
"warning": "background-color: orange; color: black;",
"error": "background-color: red; color: white;",
"fatal": "background-color: maroon; color: white;"
};
function defaultConsoleFormatter(record) {
let msg = "";
const values = [];
for (let i = 0; i < record.message.length; i++) if (i % 2 === 0) msg += record.message[i];
else {
msg += "%o";
values.push(record.message[i]);
}
const date = new Date(record.timestamp);
const time = `${date.getUTCHours().toString().padStart(2, "0")}:${date.getUTCMinutes().toString().padStart(2, "0")}:${date.getUTCSeconds().toString().padStart(2, "0")}.${date.getUTCMilliseconds().toString().padStart(3, "0")}`;
return [
`%c${time} %c${levelAbbreviations[record.level]}%c %c${record.category.join("\xB7")} %c${msg}`,
"color: gray;",
logLevelStyles[record.level],
"background-color: default;",
"color: gray;",
"color: default;",
...values
];
}
// node_modules/@logtape/logtape/dist/sink.js
function getConsoleSink(options = {}) {
const formatter = options.formatter ?? defaultConsoleFormatter;
const levelMap = {
trace: "debug",
debug: "debug",
info: "info",
warning: "warn",
error: "error",
fatal: "error",
...options.levelMap ?? {}
};
const console2 = options.console ?? globalThis.console;
const baseSink = (record) => {
const args = formatter(record);
const method = levelMap[record.level];
if (method === void 0) throw new TypeError(`Invalid log level: ${record.level}.`);
if (typeof args === "string") {
const msg = args.replace(/\r?\n$/, "");
console2[method](msg);
} else console2[method](...args);
};
if (!options.nonBlocking) return baseSink;
const nonBlockingConfig = options.nonBlocking === true ? {} : options.nonBlocking;
const bufferSize = nonBlockingConfig.bufferSize ?? 100;
const flushInterval = nonBlockingConfig.flushInterval ?? 100;
const buffer = [];
let flushTimer = null;
let disposed = false;
let flushScheduled = false;
const maxBufferSize = bufferSize * 2;
function flush() {
if (buffer.length === 0) return;
const records = buffer.splice(0);
for (const record of records) try {
baseSink(record);
} catch {
}
}
function scheduleFlush() {
if (flushScheduled) return;
flushScheduled = true;
setTimeout(() => {
flushScheduled = false;
flush();
}, 0);
}
function startFlushTimer() {
if (flushTimer !== null || disposed) return;
flushTimer = setInterval(() => {
flush();
}, flushInterval);
}
const nonBlockingSink = (record) => {
if (disposed) return;
if (buffer.length >= maxBufferSize) buffer.shift();
buffer.push(record);
if (buffer.length >= bufferSize) scheduleFlush();
else if (flushTimer === null) startFlushTimer();
};
nonBlockingSink[Symbol.dispose] = () => {
disposed = true;
if (flushTimer !== null) {
clearInterval(flushTimer);
flushTimer = null;
}
flush();
};
return nonBlockingSink;
}
// node_modules/@logtape/logtape/dist/config.js
var currentConfig = null;
var strongRefs = /* @__PURE__ */ new Set();
var disposables = /* @__PURE__ */ new Set();
var asyncDisposables = /* @__PURE__ */ new Set();
function isLoggerConfigMeta(cfg) {
return cfg.category.length === 0 || cfg.category.length === 1 && cfg.category[0] === "logtape" || cfg.category.length === 2 && cfg.category[0] === "logtape" && cfg.category[1] === "meta";
}
async function configure(config) {
if (currentConfig != null && !config.reset) throw new ConfigError("Already configured; if you want to reset, turn on the reset flag.");
await reset();
try {
configureInternal(config, true);
} catch (e) {
if (e instanceof ConfigError) await reset();
throw e;
}
}
function configureInternal(config, allowAsync) {
currentConfig = config;
let metaConfigured = false;
const configuredCategories = /* @__PURE__ */ new Set();
for (const cfg of config.loggers) {
if (isLoggerConfigMeta(cfg)) metaConfigured = true;
const categoryKey = Array.isArray(cfg.category) ? JSON.stringify(cfg.category) : JSON.stringify([cfg.category]);
if (configuredCategories.has(categoryKey)) throw new ConfigError(`Duplicate logger configuration for category: ${categoryKey}. Each category can only be configured once.`);
configuredCategories.add(categoryKey);
const logger2 = LoggerImpl.getLogger(cfg.category);
for (const sinkId of cfg.sinks ?? []) {
const sink = config.sinks[sinkId];
if (!sink) throw new ConfigError(`Sink not found: ${sinkId}.`);
logger2.sinks.push(sink);
}
logger2.parentSinks = cfg.parentSinks ?? "inherit";
if (cfg.lowestLevel !== void 0) logger2.lowestLevel = cfg.lowestLevel;
for (const filterId of cfg.filters ?? []) {
const filter = config.filters?.[filterId];
if (filter === void 0) throw new ConfigError(`Filter not found: ${filterId}.`);
logger2.filters.push(toFilter(filter));
}
strongRefs.add(logger2);
}
LoggerImpl.getLogger().contextLocalStorage = config.contextLocalStorage;
for (const sink of Object.values(config.sinks)) {
if (Symbol.asyncDispose in sink) if (allowAsync) asyncDisposables.add(sink);
else throw new ConfigError("Async disposables cannot be used with configureSync().");
if (Symbol.dispose in sink) disposables.add(sink);
}
for (const filter of Object.values(config.filters ?? {})) {
if (filter == null || typeof filter === "string") continue;
if (Symbol.asyncDispose in filter) if (allowAsync) asyncDisposables.add(filter);
else throw new ConfigError("Async disposables cannot be used with configureSync().");
if (Symbol.dispose in filter) disposables.add(filter);
}
if ("process" in globalThis && !("Deno" in globalThis)) {
const proc = globalThis.process;
if (proc?.on) proc.on("exit", allowAsync ? dispose : disposeSync);
} else addEventListener("unload", allowAsync ? dispose : disposeSync);
const meta = LoggerImpl.getLogger(["logtape", "meta"]);
if (!metaConfigured) meta.sinks.push(getConsoleSink());
meta.info("LogTape loggers are configured. Note that LogTape itself uses the meta logger, which has category {metaLoggerCategory}. The meta logger purposes to log internal errors such as sink exceptions. If you are seeing this message, the meta logger is automatically configured. It's recommended to configure the meta logger with a separate sink so that you can easily notice if logging itself fails or is misconfigured. To turn off this message, configure the meta logger with higher log levels than {dismissLevel}. See also <https://logtape.org/manual/categories#meta-logger>.", {
metaLoggerCategory: ["logtape", "meta"],
dismissLevel: "info"
});
}
async function reset() {
await dispose();
resetInternal();
}
function resetInternal() {
const rootLogger = LoggerImpl.getLogger([]);
rootLogger.resetDescendants();
delete rootLogger.contextLocalStorage;
strongRefs.clear();
currentConfig = null;
}
async function dispose() {
disposeSync();
const promises = [];
for (const disposable of asyncDisposables) {
promises.push(disposable[Symbol.asyncDispose]());
asyncDisposables.delete(disposable);
}
await Promise.all(promises);
}
function disposeSync() {
for (const disposable of disposables) disposable[Symbol.dispose]();
disposables.clear();
}
var ConfigError = class extends Error {
/**
* Constructs a new configuration error.
* @param message The error message.
*/
constructor(message) {
super(message);
this.name = "ConfigureError";
}
};
// node_modules/@logtape/pretty/dist/terminal.js
function isTerminal() {
try {
if (typeof Deno !== "undefined") {
if (Deno.stdout.isTerminal) return Deno.stdout.isTerminal();
}
if (typeof process !== "undefined" && process.stdout) return Boolean(process.stdout.isTTY);
if (typeof window !== "undefined") return false;
return false;
} catch {
return false;
}
}
function getTerminalWidth() {
try {
if (typeof Deno !== "undefined") {
if (Deno.consoleSize) {
const size = Deno.consoleSize();
return size?.columns || null;
}
}
if (typeof process !== "undefined" && process.stdout) return process.stdout.columns || null;
const envColumns = typeof Deno !== "undefined" ? Deno.env.get("COLUMNS") : process?.env?.COLUMNS;
if (envColumns) {
const parsed = parseInt(envColumns, 10);
return isNaN(parsed) ? null : parsed;
}
return null;
} catch {
return null;
}
}
function getOptimalWordWrapWidth(defaultWidth = 80) {
if (!isTerminal()) return defaultWidth;
const terminalWidth = getTerminalWidth();
return terminalWidth || defaultWidth;
}
// node_modules/@logtape/pretty/dist/truncate.js
function truncateCategory(category, maxWidth, separator = ".", strategy = "middle") {
if (!strategy || maxWidth <= 0) return category.join(separator);
const full = category.join(separator);
if (full.length <= maxWidth) return full;
const minWidth = 5;
if (maxWidth < minWidth) return "\u2026";
if (strategy === "end") return full.substring(0, maxWidth - 1) + "\u2026";
if (category.length <= 2) return full.substring(0, maxWidth - 1) + "\u2026";
const first = category[0];
const last = category[category.length - 1];
const ellipsis = "\u2026";
const minimalLength = first.length + ellipsis.length + last.length;
if (minimalLength > maxWidth) return full.substring(0, maxWidth - 1) + "\u2026";
return `${first}${ellipsis}${last}`;
}
// node_modules/@logtape/pretty/dist/wcwidth.js
var ANSI_PATTERN = /\x1b\[[0-9;]*m/g;
function stripAnsi(text) {
return text.replace(ANSI_PATTERN, "");
}
function getDisplayWidth(text) {
const cleanText = stripAnsi(text);
if (cleanText.length === 0) return 0;
let width = 0;
let i = 0;
while (i < cleanText.length) {
const code = cleanText.codePointAt(i);
if (code === void 0) {
i++;
continue;
}
const charWidth = wcwidth(code);
if (charWidth >= 0) width += charWidth;
i += code > 65535 ? 2 : 1;
}
return width;
}
function wcwidth(code) {
if (code < 32 || code >= 127 && code < 160) return -1;
if (isZeroWidth(code)) return 0;
if (isWideCharacter(code)) return 2;
return 1;
}
var ZERO_WIDTH_RANGES = [
[768, 879],
[1155, 1161],
[1425, 1469],
[1473, 1474],
[1476, 1477],
[1552, 1562],
[1611, 1631],
[1750, 1756],
[1759, 1764],
[1767, 1768],
[1770, 1773],
[1840, 1866],
[1958, 1968],
[2027, 2035],
[2070, 2073],
[2075, 2083],
[2085, 2087],
[2089, 2093],
[2137, 2139],
[2259, 2273],
[2275, 2306],
[2369, 2376],
[2385, 2391],
[2402, 2403],
[2497, 2500],
[2530, 2531],
[2561, 2562],
[2625, 2626],
[2631, 2632],
[2635, 2637],
[2672, 2673],
[2689, 2690],
[2753, 2757],
[2759, 2760],
[2786, 2787],
[2810, 2815],
[2881, 2884],
[2901, 2902],
[2914, 2915],
[3134, 3136],
[3142, 3144],
[3146, 3149],
[3157, 3158],
[3170, 3171],
[3276, 3277],
[3298, 3299],
[3328, 3329],
[3387, 3388],
[3426, 3427],
[3538, 3540],
[3636, 3642],
[3655, 3662],
[3764, 3772],
[3784, 3789],
[3864, 3865],
[3953, 3966],
[3968, 3972],
[3974, 3975],
[3981, 3991],
[3993, 4028],
[4141, 4144],
[4146, 4151],
[4153, 4154],
[4157, 4158],
[4184, 4185],
[4190, 4192],
[4209, 4212],
[4229, 4230],
[4957, 4959],
[5906, 5908],
[5938, 5940],
[5970, 5971],
[6002, 6003],
[6068, 6069],
[6071, 6077],
[6089, 6099],
[6155, 6157],
[6277, 6278],
[6432, 6434],
[6439, 6440],
[6457, 6459],
[6679, 6680],
[6744, 6750],
[6757, 6764],
[6771, 6780],
[6832, 6846],
[6912, 6915],
[6966, 6970],
[7019, 7027],
[7040, 7041],
[7074, 7077],
[7080, 7081],
[7083, 7085],
[7144, 7145],
[7151, 7153],
[7212, 7219],
[7222, 7223],
[7376, 7378],
[7380, 7392],
[7394, 7400],
[7416, 7417],
[7616, 7673],
[7675, 7679],
[8203, 8207],
[8234, 8238],
[8288, 8292],
[8294, 8303],
[65024, 65039],
[65056, 65071]
];
var ZERO_WIDTH_SINGLES = /* @__PURE__ */ new Set([
1471,
1479,
1648,
1809,
2045,
2362,
2364,
2381,
2433,
2492,
2509,
2558,
2620,
2641,
2677,
2748,
2765,
2817,
2876,
2879,
2893,
2946,
3008,
3021,
3072,
3076,
3201,
3260,
3263,
3270,
3393,
3396,
3405,
3457,
3530,
3542,
3633,
3761,
3893,
3895,
3897,
4038,
4226,
4237,
4253,
6086,
6109,
6313,
6450,
6683,
6742,
6752,
6754,
6783,
6964,
6972,
6978,
7142,
7149,
7405,
7412,
65279
]);
function isInRanges(code, ranges) {
let left = 0;
let right = ranges.length - 1;
while (left <= right) {
const mid = Math.floor((left + right) / 2);
const [start, end] = ranges[mid];
if (code >= start && code <= end) return true;
else if (code < start) right = mid - 1;
else left = mid + 1;
}
return false;
}
function isZeroWidth(code) {
return ZERO_WIDTH_SINGLES.has(code) || isInRanges(code, ZERO_WIDTH_RANGES);
}
function isWideCharacter(code) {
return code >= 4352 && code <= 4447 || code >= 8986 && code <= 8987 || code >= 9001 && code <= 9002 || code >= 9193 && code <= 9196 || code === 9200 || code === 9203 || code >= 9725 && code <= 9726 || code >= 9748 && code <= 9749 || code >= 9800 && code <= 9811 || code === 9855 || code === 9875 || code === 9888 || code === 9889 || code === 9898 || code === 9899 || code >= 9917 && code <= 9918 || code >= 9924 && code <= 9925 || code === 9934 || code === 9940 || code >= 9962 && code <= 9962 || code >= 9970 && code <= 9971 || code === 9973 || code === 9978 || code === 9981 || code >= 9989 && code <= 9989 || code >= 9994 && code <= 9995 || code === 10024 || code === 10060 || code === 10062 || code >= 10067 && code <= 10069 || code === 10071 || code >= 10133 && code <= 10135 || code === 10160 || code === 10175 || code >= 11035 && code <= 11036 || code === 11088 || code === 11093 || code >= 11904 && code <= 11929 || code >= 11931 && code <= 12019 || code >= 12032 && code <= 12245 || code >= 12272 && code <= 12283 || code >= 12288 && code <= 12350 || code >= 12353 && code <= 12438 || code >= 12441 && code <= 12543 || code >= 12549 && code <= 12591 || code >= 12593 && code <= 12686 || code >= 12688 && code <= 12771 || code >= 12784 && code <= 12830 || code >= 12832 && code <= 12871 || code >= 12880 && code <= 19903 || code >= 19968 && code <= 40959 || code >= 43360 && code <= 43391 || code >= 44032 && code <= 55203 || code >= 55216 && code <= 55238 || code >= 63744 && code <= 64255 || code >= 65040 && code <= 65049 || code >= 65072 && code <= 65135 || code >= 65280 && code <= 65376 || code >= 65504 && code <= 65510 || code >= 94176 && code <= 94180 || code >= 94192 && code <= 94193 || code >= 94208 && code <= 100343 || code >= 100352 && code <= 101589 || code >= 101632 && code <= 101640 || code >= 110576 && code <= 110579 || code >= 110581 && code <= 110587 || code >= 110589 && code <= 110590 || code >= 110592 && code <= 110882 || code >= 110928 && code <= 110930 || code >= 110948 && code <= 110951 || code >= 110960 && code <= 111355 || code === 126980 || code === 127183 || code >= 127374 && code <= 127374 || code >= 127377 && code <= 127386 || code >= 127462 && code <= 127487 || code >= 127488 && code <= 127490 || code >= 127504 && code <= 127547 || code >= 127552 && code <= 127560 || code >= 127568 && code <= 127569 || code >= 127584 && code <= 127589 || code >= 127744 && code <= 128727 || code >= 128736 && code <= 128748 || code >= 128752 && code <= 128764 || code >= 128768 && code <= 128883 || code >= 128896 && code <= 128984 || code >= 128992 && code <= 129003 || code >= 129008 && code <= 129008 || code >= 129024 && code <= 129035 || code >= 129040 && code <= 129095 || code >= 129104 && code <= 129113 || code >= 129120 && code <= 129159 || code >= 129168 && code <= 129197 || code >= 129200 && code <= 129201 || code >= 129280 && code <= 129619 || code >= 129632 && code <= 129645 || code >= 129648 && code <= 129660 || code >= 129664 && code <= 129672 || code >= 129680 && code <= 129725 || code >= 129727 && code <= 129733 || code >= 129742 && code <= 129755 || code >= 129760 && code <= 129768 || code >= 129776 && code <= 129784 || code >= 131072 && code <= 196605 || code >= 196608 && code <= 262141;
}
// node_modules/@logtape/pretty/dist/wordwrap.js
function wrapText(text, maxWidth, messageContent) {
if (maxWidth <= 0) return text;
const displayWidth = getDisplayWidth(text);
if (displayWidth <= maxWidth && !text.includes("\n")) return text;
const firstLineWords = messageContent.split(" ");
const firstWord = firstLineWords[0];
const plainText = stripAnsi(text);
const messageStartIndex = plainText.indexOf(firstWord);
let indentWidth = 0;
if (messageStartIndex >= 0) {
const prefixText = plainText.slice(0, messageStartIndex);
indentWidth = getDisplayWidth(prefixText);
}
const indent = " ".repeat(Math.max(0, indentWidth));
if (text.includes("\n")) {
const lines = text.split("\n");
const wrappedLines = [];
for (let i = 0; i < lines.length; i++) {
const line = lines[i];
const lineDisplayWidth = getDisplayWidth(line);
if (lineDisplayWidth <= maxWidth) if (i === 0) wrappedLines.push(line);
else wrappedLines.push(indent + line);
else {
const wrappedLine = wrapSingleLine(line, maxWidth, indent);
if (i === 0) wrappedLines.push(wrappedLine);
else {
const subLines = wrappedLine.split("\n");
for (let j = 0; j < subLines.length; j++) if (j === 0) wrappedLines.push(indent + subLines[j]);
else wrappedLines.push(subLines[j]);
}
}
}
return wrappedLines.join("\n");
}
return wrapSingleLine(text, maxWidth, indent);
}
function wrapSingleLine(text, maxWidth, indent) {
const lines = [];
let currentLine = "";
let currentDisplayWidth = 0;
let i = 0;
while (i < text.length) {
if (text[i] === "\x1B" && text[i + 1] === "[") {
let j = i + 2;
while (j < text.length && text[j] !== "m") j++;
if (j < text.length) {
j++;
currentLine += text.slice(i, j);
i = j;
continue;
}
}
const char = text[i];
if (currentDisplayWidth >= maxWidth && char !== " ") {
const breakPoint = currentLine.lastIndexOf(" ");
if (breakPoint > 0) {
lines.push(currentLine.slice(0, breakPoint));
currentLine = indent + currentLine.slice(breakPoint + 1) + char;
currentDisplayWidth = getDisplayWidth(currentLine);
} else {
lines.push(currentLine);
currentLine = indent + char;
currentDisplayWidth = getDisplayWidth(currentLine);
}
} else {
currentLine += char;
currentDisplayWidth = getDisplayWidth(currentLine);
}
i++;
}
if (currentLine.trim()) lines.push(currentLine);
const filteredLines = lines.filter((line) => line.trim().length > 0);
return filteredLines.join("\n");
}
// node_modules/@logtape/pretty/dist/util.node.js
import util2 from "node:util";
function inspect3(obj, options) {
return util2.inspect(obj, options);
}
// node_modules/@logtape/pretty/dist/formatter.js
var RESET2 = "\x1B[0m";
var DIM = "\x1B[2m";
var defaultColors = {
trace: "rgb(167,139,250)",
debug: "rgb(96,165,250)",
info: "rgb(52,211,153)",
warning: "rgb(251,191,36)",
error: "rgb(248,113,113)",
fatal: "rgb(220,38,38)",
category: "rgb(100,116,139)",
message: "rgb(148,163,184)",
timestamp: "rgb(100,116,139)"
};
var styles = {
reset: RESET2,
bold: "\x1B[1m",
dim: DIM,
italic: "\x1B[3m",
underline: "\x1B[4m",
strikethrough: "\x1B[9m"
};
var ansiColors2 = {
black: "\x1B[30m",
red: "\x1B[31m",
green: "\x1B[32m",
yellow: "\x1B[33m",
blue: "\x1B[34m",
magenta: "\x1B[35m",
cyan: "\x1B[36m",
white: "\x1B[37m"
};
var RGB_PATTERN = /^rgb\((\d+),(\d+),(\d+)\)$/;
var HEX_PATTERN = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
function colorToAnsi(color