core: ensure export command output can be piped without UI interference

This commit is contained in:
Dax Raad
2025-11-05 18:35:59 -05:00
parent c9ae89a38b
commit 2a9b6a85de
2 changed files with 28 additions and 11 deletions

View File

@@ -18,10 +18,13 @@ export const ExportCommand = cmd({
handler: async (args) => { handler: async (args) => {
await bootstrap(process.cwd(), async () => { await bootstrap(process.cwd(), async () => {
let sessionID = args.sessionID let sessionID = args.sessionID
process.stderr.write(`Exporting session: ${sessionID ?? "latest"}`)
if (!sessionID) { if (!sessionID) {
UI.empty() UI.empty()
prompts.intro("Export session") prompts.intro("Export session", {
output: process.stderr,
})
const sessions = [] const sessions = []
for await (const session of Session.list()) { for await (const session of Session.list()) {
@@ -29,8 +32,12 @@ export const ExportCommand = cmd({
} }
if (sessions.length === 0) { if (sessions.length === 0) {
prompts.log.error("No sessions found") prompts.log.error("No sessions found", {
prompts.outro("Done") output: process.stderr,
})
prompts.outro("Done", {
output: process.stderr,
})
return return
} }
@@ -44,6 +51,7 @@ export const ExportCommand = cmd({
value: session.id, value: session.id,
hint: `${new Date(session.time.updated).toLocaleString()}${session.id.slice(-8)}`, hint: `${new Date(session.time.updated).toLocaleString()}${session.id.slice(-8)}`,
})), })),
output: process.stderr,
}) })
if (prompts.isCancel(selectedSession)) { if (prompts.isCancel(selectedSession)) {
@@ -52,7 +60,9 @@ export const ExportCommand = cmd({
sessionID = selectedSession as string sessionID = selectedSession as string
prompts.outro("Exporting session...") prompts.outro("Exporting session...", {
output: process.stderr,
})
} }
try { try {

View File

@@ -4,7 +4,9 @@ import { Global } from "../global"
import z from "zod" import z from "zod"
export namespace Log { export namespace Log {
export const Level = z.enum(["DEBUG", "INFO", "WARN", "ERROR"]).meta({ ref: "LogLevel", description: "Log level" }) export const Level = z
.enum(["DEBUG", "INFO", "WARN", "ERROR"])
.meta({ ref: "LogLevel", description: "Log level" })
export type Level = z.infer<typeof Level> export type Level = z.infer<typeof Level>
const levelPriority: Record<Level, number> = { const levelPriority: Record<Level, number> = {
@@ -50,6 +52,7 @@ export namespace Log {
export function file() { export function file() {
return logpath return logpath
} }
let write: (msg: string) => void
export async function init(options: Options) { export async function init(options: Options) {
if (options.level) level = options.level if (options.level) level = options.level
@@ -62,7 +65,7 @@ export namespace Log {
const logfile = Bun.file(logpath) const logfile = Bun.file(logpath)
await fs.truncate(logpath).catch(() => {}) await fs.truncate(logpath).catch(() => {})
const writer = logfile.writer() const writer = logfile.writer()
process.stderr.write = (msg) => { write = (msg) => {
writer.write(msg) writer.write(msg)
writer.flush() writer.flush()
return true return true
@@ -118,27 +121,31 @@ export namespace Log {
const next = new Date() const next = new Date()
const diff = next.getTime() - last const diff = next.getTime() - last
last = next.getTime() last = next.getTime()
return [next.toISOString().split(".")[0], "+" + diff + "ms", prefix, message].filter(Boolean).join(" ") + "\n" return (
[next.toISOString().split(".")[0], "+" + diff + "ms", prefix, message]
.filter(Boolean)
.join(" ") + "\n"
)
} }
const result: Logger = { const result: Logger = {
debug(message?: any, extra?: Record<string, any>) { debug(message?: any, extra?: Record<string, any>) {
if (shouldLog("DEBUG")) { if (shouldLog("DEBUG")) {
process.stderr.write("DEBUG " + build(message, extra)) write("DEBUG " + build(message, extra))
} }
}, },
info(message?: any, extra?: Record<string, any>) { info(message?: any, extra?: Record<string, any>) {
if (shouldLog("INFO")) { if (shouldLog("INFO")) {
process.stderr.write("INFO " + build(message, extra)) write("INFO " + build(message, extra))
} }
}, },
error(message?: any, extra?: Record<string, any>) { error(message?: any, extra?: Record<string, any>) {
if (shouldLog("ERROR")) { if (shouldLog("ERROR")) {
process.stderr.write("ERROR " + build(message, extra)) write("ERROR " + build(message, extra))
} }
}, },
warn(message?: any, extra?: Record<string, any>) { warn(message?: any, extra?: Record<string, any>) {
if (shouldLog("WARN")) { if (shouldLog("WARN")) {
process.stderr.write("WARN " + build(message, extra)) write("WARN " + build(message, extra))
} }
}, },
tag(key: string, value: string) { tag(key: string, value: string) {