11#!/usr/bin/env node
22import { spawn } from 'node:child_process' ;
3- import { mkdtemp , rm } from 'node:fs/promises' ;
3+ import { mkdtemp , realpath , rm } from 'node:fs/promises' ;
44import { tmpdir } from 'node:os' ;
55import path from 'node:path' ;
66import { fileURLToPath } from 'node:url' ;
@@ -36,13 +36,14 @@ try {
3636 pricingCacheFile ,
3737 ] ;
3838 const rows = [ ] ;
39+ const upstream = await resolveUpstreamBinary ( ) ;
3940 rows . push ( await measure ( 'cdxusage cold' , process . execPath , [ ...commonCdxArgs , '--clear-cache' ] , cdxusageTimeoutSeconds ) ) ;
4041 rows . push ( await measure ( 'cdxusage warm' , process . execPath , commonCdxArgs , cdxusageTimeoutSeconds ) ) ;
4142 rows . push (
4243 await measure (
43- ' upstream latest' ,
44- 'npx' ,
45- [ '-y' , '@ccusage/codex@latest' , ' monthly', '--since' , since , '--json' ] ,
44+ `@ccusage/codex@ ${ upstream . version } ` ,
45+ upstream . binPath ,
46+ [ 'monthly' , '--since' , since , '--json' ] ,
4647 upstreamTimeoutSeconds ,
4748 ) ,
4849 ) ;
@@ -95,9 +96,39 @@ async function measure(label, command, commandArgs, timeoutSeconds) {
9596 } ;
9697}
9798
98- function run ( command , args , timeoutSeconds ) {
99+ async function resolveUpstreamBinary ( ) {
100+ const versionResult = await run ( 'npm' , [ 'view' , '@ccusage/codex@latest' , 'version' ] , 60 , { captureStdout : true } ) ;
101+ if ( versionResult . status !== 0 || ! versionResult . stdout . trim ( ) ) {
102+ throw new Error ( `failed to resolve @ccusage/codex@latest version: ${ versionResult . stderr . trim ( ) || `exit ${ versionResult . status } ` } ` ) ;
103+ }
104+ const pathResult = await run (
105+ 'npm' ,
106+ process . platform === 'win32'
107+ ? [ 'exec' , '--yes' , '--package' , '@ccusage/codex@latest' , '--' , 'cmd' , '/d' , '/s' , '/c' , 'where ccusage-codex' ]
108+ : [ 'exec' , '--yes' , '--package' , '@ccusage/codex@latest' , '--' , 'sh' , '-c' , 'command -v ccusage-codex' ] ,
109+ 60 ,
110+ { captureStdout : true } ,
111+ ) ;
112+ if ( pathResult . status !== 0 || ! pathResult . stdout . trim ( ) ) {
113+ throw new Error ( `failed to resolve @ccusage/codex@latest binary: ${ pathResult . stderr . trim ( ) || `exit ${ pathResult . status } ` } ` ) ;
114+ }
115+ const binPath = pathResult . stdout
116+ . trim ( )
117+ . split ( / \r ? \n / )
118+ . find ( ( line ) => line . trim ( ) ) ;
119+ if ( ! binPath ) {
120+ throw new Error ( `failed to parse @ccusage/codex binary path: ${ pathResult . stdout . trim ( ) } ` ) ;
121+ }
122+ return {
123+ version : versionResult . stdout . trim ( ) . split ( / \r ? \n / ) . at ( - 1 ) ,
124+ binPath : process . platform === 'win32' ? binPath : await realpath ( binPath ) ,
125+ } ;
126+ }
127+
128+ function run ( command , args , timeoutSeconds , options = { } ) {
99129 return new Promise ( ( resolve ) => {
100- const child = spawn ( command , args , { cwd : repoRoot , stdio : [ 'ignore' , 'ignore' , 'pipe' ] } ) ;
130+ const child = spawn ( command , args , { cwd : repoRoot , stdio : [ 'ignore' , options . captureStdout ? 'pipe' : 'ignore' , 'pipe' ] } ) ;
131+ let stdout = '' ;
101132 let stderr = '' ;
102133 let timedOut = false ;
103134 const timer = setTimeout ( ( ) => {
@@ -106,13 +137,21 @@ function run(command, args, timeoutSeconds) {
106137 setTimeout ( ( ) => child . kill ( 'SIGKILL' ) , 1_000 ) . unref ( ) ;
107138 } , Math . ceil ( timeoutSeconds * 1000 ) + 500 ) ;
108139 timer . unref ( ) ;
140+ child . stdout ?. setEncoding ( 'utf8' ) ;
141+ child . stdout ?. on ( 'data' , ( chunk ) => {
142+ stdout += chunk ;
143+ } ) ;
109144 child . stderr . setEncoding ( 'utf8' ) ;
110145 child . stderr . on ( 'data' , ( chunk ) => {
111146 stderr += chunk ;
112147 } ) ;
148+ child . on ( 'error' , ( error ) => {
149+ clearTimeout ( timer ) ;
150+ resolve ( { status : 127 , signal : null , stdout, stderr : `${ stderr } ${ error . message } ` , timedOut } ) ;
151+ } ) ;
113152 child . on ( 'close' , ( status , signal ) => {
114153 clearTimeout ( timer ) ;
115- resolve ( { status, signal, stderr, timedOut } ) ;
154+ resolve ( { status, signal, stdout , stderr, timedOut } ) ;
116155 } ) ;
117156 } ) ;
118157}
0 commit comments