@@ -3,6 +3,7 @@ import { promisify } from "node:util"
33import { log } from "./logger.ts"
44
55const execFileAsync = promisify ( execFile )
6+ let bmCallCounter = 0
67
78/**
89 * Strip YAML frontmatter from note content.
@@ -106,6 +107,17 @@ export function parseJsonOutput(raw: string): unknown {
106107 throw new Error ( `Could not parse JSON from bm output: ${ raw . slice ( 0 , 200 ) } ` )
107108}
108109
110+ function quoteArgForLog ( arg : string ) : string {
111+ if ( / ^ [ A - Z a - z 0 - 9 _ . / : @ % + = , - ] + $ / . test ( arg ) ) return arg
112+ return `"${ arg . replace ( / \\ / g, "\\\\" ) . replace ( / " / g, '\\"' ) } "`
113+ }
114+
115+ export function formatCommandForLog ( cmd : string , args : string [ ] ) : string {
116+ return [ quoteArgForLog ( cmd ) , ...args . map ( ( arg ) => quoteArgForLog ( arg ) ) ] . join (
117+ " " ,
118+ )
119+ }
120+
109121function getErrorMessage ( err : unknown ) : string {
110122 return err instanceof Error ? err . message : String ( err )
111123}
@@ -161,20 +173,52 @@ export class BmClient {
161173 * Run a raw bm command with no automatic flags.
162174 */
163175 private async execRaw ( args : string [ ] ) : Promise < string > {
164- log . debug ( `exec: ${ this . bmPath } ${ args . join ( " " ) } ` )
176+ const callId = ++ bmCallCounter
177+ const startedAt = Date . now ( )
178+ const renderedCommand = formatCommandForLog ( this . bmPath , args )
179+ log . debug ( `[bm:${ callId } ] exec start: ${ renderedCommand } ` )
180+ log . debug ( `[bm:${ callId } ] exec args` , args )
165181
166182 try {
167- const { stdout } = await execFileAsync ( this . bmPath , args , {
183+ const { stdout, stderr } = await execFileAsync ( this . bmPath , args , {
168184 timeout : 30_000 ,
169185 maxBuffer : 10 * 1024 * 1024 ,
170186 } )
171- return stdout . trim ( )
187+ const durationMs = Date . now ( ) - startedAt
188+ const trimmedStdout = stdout . trim ( )
189+
190+ log . debug (
191+ `[bm:${ callId } ] exec success (${ durationMs } ms): ${ renderedCommand } ` ,
192+ )
193+ log . debug ( `[bm:${ callId } ] stdout` , stdout )
194+ log . debug ( `[bm:${ callId } ] stdout (trimmed)` , trimmedStdout )
195+ if ( stderr . trim ( ) . length > 0 ) {
196+ log . debug ( `[bm:${ callId } ] stderr` , stderr )
197+ }
198+
199+ return trimmedStdout
172200 } catch ( err ) {
201+ const durationMs = Date . now ( ) - startedAt
173202 const msg = err instanceof Error ? err . message : String ( err )
174- log . debug ( `bm command failed: ${ this . bmPath } ${ args . join ( " " ) } — ${ msg } ` )
175- throw new Error (
176- `bm command failed: ${ this . bmPath } ${ args . join ( " " ) } — ${ msg } ` ,
203+ const failedStdout =
204+ typeof ( err as { stdout ?: unknown } ) . stdout === "string"
205+ ? ( err as { stdout : string } ) . stdout
206+ : ""
207+ const failedStderr =
208+ typeof ( err as { stderr ?: unknown } ) . stderr === "string"
209+ ? ( err as { stderr : string } ) . stderr
210+ : ""
211+
212+ log . debug (
213+ `[bm:${ callId } ] exec failure (${ durationMs } ms): ${ renderedCommand } — ${ msg } ` ,
177214 )
215+ if ( failedStdout . trim ( ) . length > 0 ) {
216+ log . debug ( `[bm:${ callId } ] stdout (error path)` , failedStdout )
217+ }
218+ if ( failedStderr . trim ( ) . length > 0 ) {
219+ log . debug ( `[bm:${ callId } ] stderr (error path)` , failedStderr )
220+ }
221+ throw new Error ( `bm command failed: ${ renderedCommand } — ${ msg } ` )
178222 }
179223 }
180224
0 commit comments