@@ -152,6 +152,7 @@ const CRON_NEXT_PAD = 10;
152152const CRON_LAST_PAD = 10 ;
153153const CRON_STATUS_PAD = 9 ;
154154const CRON_TARGET_PAD = 9 ;
155+ const CRON_DELIVERY_PAD = 42 ;
155156const CRON_AGENT_PAD = 10 ;
156157const CRON_MODEL_PAD = 20 ;
157158
@@ -224,7 +225,101 @@ const formatStatus = (job: CronJob) => {
224225 return job . state . lastStatus ?? "idle" ;
225226} ;
226227
227- export function printCronList ( jobs : CronJob [ ] , runtime : RuntimeEnv = defaultRuntime ) {
228+ export type CronDeliveryPreview = {
229+ label : string ;
230+ detail : string ;
231+ } ;
232+
233+ function formatTarget ( channel ?: string , to ?: string | null ) : string {
234+ if ( ! channel ) {
235+ return "last" ;
236+ }
237+ if ( to ) {
238+ return `${ channel } :${ to } ` ;
239+ }
240+ return channel ;
241+ }
242+
243+ function formatDeliveryDetail ( params : {
244+ requestedChannel ?: string ;
245+ resolved : boolean ;
246+ sessionKey ?: string ;
247+ error ?: string ;
248+ } ) : string {
249+ if ( params . requestedChannel === "last" || ! params . requestedChannel ) {
250+ if ( ! params . resolved ) {
251+ return params . error
252+ ? `last -> no route, will fail-closed: ${ params . error } `
253+ : "last -> no route, will fail-closed" ;
254+ }
255+ return params . sessionKey
256+ ? `resolved from last, session ${ params . sessionKey } `
257+ : "resolved from last, main session" ;
258+ }
259+ return params . resolved ? "explicit" : ( params . error ?? "unresolved" ) ;
260+ }
261+
262+ export async function resolveCronDeliveryPreview ( job : CronJob ) : Promise < CronDeliveryPreview > {
263+ const { resolveCronDeliveryPlan } = await import ( "../../cron/delivery-plan.js" ) ;
264+ const plan = resolveCronDeliveryPlan ( job ) ;
265+ if ( ! plan . requested && plan . mode === "none" && ! job . delivery ) {
266+ return { label : "not requested" , detail : "not requested" } ;
267+ }
268+ if ( plan . mode === "webhook" ) {
269+ const target = plan . to ? `webhook:${ plan . to } ` : "webhook" ;
270+ return { label : target , detail : plan . to ? "webhook" : "webhook target missing" } ;
271+ }
272+
273+ const requestedChannel = plan . channel ?? "last" ;
274+ const [ { loadConfig } , { resolveDefaultAgentId } , { resolveDeliveryTarget } ] = await Promise . all ( [
275+ import ( "../../config/config.js" ) ,
276+ import ( "../../agents/agent-scope-config.js" ) ,
277+ import ( "../../cron/isolated-agent/delivery-target.js" ) ,
278+ ] ) ;
279+ const cfg = loadConfig ( ) ;
280+ const agentId = job . agentId ?. trim ( ) || resolveDefaultAgentId ( cfg ) ;
281+ const resolved = await resolveDeliveryTarget ( cfg , agentId , {
282+ channel : requestedChannel ,
283+ to : plan . to ,
284+ threadId : plan . threadId ,
285+ accountId : plan . accountId ,
286+ sessionKey : job . sessionKey ,
287+ } ) ;
288+ if ( ! resolved . ok ) {
289+ return {
290+ label : `${ plan . mode } -> ${ formatTarget ( requestedChannel , plan . to ?? null ) } ` ,
291+ detail : formatDeliveryDetail ( {
292+ requestedChannel,
293+ resolved : false ,
294+ sessionKey : job . sessionKey ,
295+ error : resolved . error . message ,
296+ } ) ,
297+ } ;
298+ }
299+ return {
300+ label : `${ plan . mode } -> ${ formatTarget ( resolved . channel , resolved . to ) } ` ,
301+ detail : formatDeliveryDetail ( {
302+ requestedChannel,
303+ resolved : true ,
304+ sessionKey : job . sessionKey ,
305+ } ) ,
306+ } ;
307+ }
308+
309+ export async function resolveCronDeliveryPreviews (
310+ jobs : CronJob [ ] ,
311+ ) : Promise < Map < string , CronDeliveryPreview > > {
312+ const entries = await Promise . all (
313+ jobs . map ( async ( job ) => [ job . id , await resolveCronDeliveryPreview ( job ) ] as const ) ,
314+ ) ;
315+ return new Map ( entries ) ;
316+ }
317+
318+ export function printCronList (
319+ jobs : CronJob [ ] ,
320+ runtime : RuntimeEnv = defaultRuntime ,
321+ opts ?: { deliveryPreviews ?: Map < string , CronDeliveryPreview > } ,
322+ ) {
228323 if ( jobs . length === 0 ) {
229324 runtime . log ( "No cron jobs." ) ;
230325 return ;
@@ -239,6 +334,7 @@ export function printCronList(jobs: CronJob[], runtime: RuntimeEnv = defaultRunt
239334 pad ( "Last" , CRON_LAST_PAD ) ,
240335 pad ( "Status" , CRON_STATUS_PAD ) ,
241336 pad ( "Target" , CRON_TARGET_PAD ) ,
337+ pad ( "Delivery" , CRON_DELIVERY_PAD ) ,
242338 pad ( "Agent ID" , CRON_AGENT_PAD ) ,
243339 pad ( "Model" , CRON_MODEL_PAD ) ,
244340 ] . join ( " " ) ;
@@ -261,6 +357,11 @@ export function printCronList(jobs: CronJob[], runtime: RuntimeEnv = defaultRunt
261357 const statusRaw = formatStatus ( job ) ;
262358 const statusLabel = pad ( statusRaw , CRON_STATUS_PAD ) ;
263359 const targetLabel = pad ( job . sessionTarget ?? "-" , CRON_TARGET_PAD ) ;
360+ const deliveryPreview = opts ?. deliveryPreviews ?. get ( job . id ) ;
361+ const deliveryLabel = pad (
362+ truncate ( deliveryPreview ?. label ?? "-" , CRON_DELIVERY_PAD ) ,
363+ CRON_DELIVERY_PAD ,
364+ ) ;
264365 const agentLabel = pad ( truncate ( job . agentId ?? "-" , CRON_AGENT_PAD ) , CRON_AGENT_PAD ) ;
265366 const modelLabel = pad (
266367 truncate (
@@ -302,6 +403,9 @@ export function printCronList(jobs: CronJob[], runtime: RuntimeEnv = defaultRunt
302403 colorize ( rich , theme . muted , lastLabel ) ,
303404 coloredStatus ,
304405 coloredTarget ,
406+ deliveryPreview
407+ ? colorize ( rich , theme . info , deliveryLabel )
408+ : colorize ( rich , theme . muted , deliveryLabel ) ,
305409 coloredAgent ,
306410 job . payload . kind === "agentTurn" && job . payload . model
307411 ? colorize ( rich , theme . info , modelLabel )
@@ -311,3 +415,18 @@ export function printCronList(jobs: CronJob[], runtime: RuntimeEnv = defaultRunt
311415 runtime . log ( line . trimEnd ( ) ) ;
312416 }
313417}
418+
419+ export async function printCronShow ( job : CronJob , runtime : RuntimeEnv = defaultRuntime ) {
420+ const preview = await resolveCronDeliveryPreview ( job ) ;
421+ runtime . log ( `id: ${ job . id } ` ) ;
422+ runtime . log ( `name: ${ job . name } ` ) ;
423+ runtime . log ( `enabled: ${ job . enabled ? "yes" : "no" } ` ) ;
424+ runtime . log ( `schedule: ${ formatSchedule ( job . schedule ) } ` ) ;
425+ runtime . log ( `session: ${ job . sessionTarget ?? "-" } ` ) ;
426+ runtime . log ( `agent: ${ job . agentId ?? "-" } ` ) ;
427+ runtime . log ( `model: ${ job . payload . kind === "agentTurn" ? ( job . payload . model ?? "-" ) : "-" } ` ) ;
428+ runtime . log ( `delivery: ${ preview . label } (${ preview . detail } )` ) ;
429+ runtime . log ( `next: ${ formatRelative ( job . state . nextRunAtMs , Date . now ( ) ) } ` ) ;
430+ runtime . log ( `last: ${ formatRelative ( job . state . lastRunAtMs , Date . now ( ) ) } ` ) ;
431+ runtime . log ( `status: ${ formatStatus ( job ) } ` ) ;
432+ }
0 commit comments