@@ -251,15 +251,22 @@ export async function run(options: RunOptions = {}): Promise<RunOutput> {
251251
252252 const updateStatus = ( index : number , status : JobStatus , durationMs ?: number ) => {
253253 const patch : Partial < JobState > = { status, durationMs } ;
254- // Stamp the start time on the first transition into "running" so the
255- // live UI can tick an elapsed-duration counter.
256- if ( status === "running" && jobStates [ index ] . runStartedAt === undefined ) {
254+ // Stamp the start time on the first transition into "starting"/"running"
255+ // so the live UI can tick an elapsed-duration counter that includes the
256+ // adapter's own startup (CLI cold start, ACP handshake, etc.).
257+ if ( ( status === "starting" || status === "running" ) && jobStates [ index ] . runStartedAt === undefined ) {
257258 patch . runStartedAt = Date . now ( ) ;
258259 }
259260 jobStates [ index ] = { ...jobStates [ index ] , ...patch } ;
260261 logger . onJobUpdate ?.( jobStates , jobMeta ) ;
261262 } ;
262263
264+ const promoteToRunning = ( index : number ) => {
265+ if ( jobStates [ index ] . status === "starting" ) {
266+ updateStatus ( index , "running" ) ;
267+ }
268+ } ;
269+
263270 const setTeardown = ( index : number , inTeardown : boolean ) => {
264271 if ( Boolean ( jobStates [ index ] . inTeardown ) === inTeardown ) return ;
265272 jobStates [ index ] = { ...jobStates [ index ] , inTeardown } ;
@@ -443,6 +450,7 @@ export async function run(options: RunOptions = {}): Promise<RunOutput> {
443450 logger ,
444451 updateStatus ,
445452 updateTokens ,
453+ promoteToRunning ,
446454 resolvedSkillMap ,
447455 options . registerCleanup ,
448456 options . debug ?? false ,
@@ -492,6 +500,7 @@ async function executeJob(
492500 logger : Logger ,
493501 updateStatus : ( index : number , status : JobStatus , durationMs ?: number ) => void ,
494502 updateTokens : ( index : number , tokens : number , final ?: boolean ) => void ,
503+ promoteToRunning : ( index : number ) => void ,
495504 resolvedSkillMap : Map < string , ResolvedSkill > ,
496505 registerCleanup ?: ( fn : ( ) => void ) => void ,
497506 debug ?: boolean ,
@@ -618,7 +627,7 @@ async function executeJob(
618627 }
619628
620629 try {
621- updateStatus ( index , "running " ) ;
630+ updateStatus ( index , "starting " ) ;
622631 logger . verbose ?.( `[${ label } ] Executing agent...` ) ;
623632
624633 // Merge top-level + per-agent + per-scenario skills, deduplicate by source
@@ -648,6 +657,8 @@ async function executeJob(
648657 : axisConfig . mcp_servers ,
649658 resolvedSkills : agentSkills . length > 0 ? agentSkills : undefined ,
650659 onTokenProgress : ( tokens ) => {
660+ // First token from the agent → it's past startup, into real work.
661+ promoteToRunning ( index ) ;
651662 updateTokens ( index , tokens ) ;
652663 // Per-scenario token limit
653664 if ( jobLimits ?. tokenLimit && tokens >= jobLimits . tokenLimit ) {
@@ -656,6 +667,7 @@ async function executeJob(
656667 // Overall token limit (checks cumulative across all jobs)
657668 checkOverallTokenLimit ?.( ) ;
658669 } ,
670+ onAgentReady : ( ) => promoteToRunning ( index ) ,
659671 ...( jobLimits ?. timeoutMs ? { timeoutMs : jobLimits . timeoutMs } : { } ) ,
660672 ...( jobAbortController ? { signal : jobAbortController . signal } : { } ) ,
661673 debug,
0 commit comments