From 9074149778d9e78a01c2bdfba5b740ff2cbe4a2c Mon Sep 17 00:00:00 2001 From: ajmallesh Date: Mon, 16 Feb 2026 17:21:12 -0800 Subject: [PATCH] feat: add resume header to workflow.log showing previous workflow ID and checkpoint --- src/audit/audit-session.ts | 14 ++++++++++++++ src/audit/workflow-logger.ts | 28 ++++++++++++++++++++++++++++ src/temporal/activities.ts | 16 ++++++++++++++-- src/temporal/workflows.ts | 6 ++++-- 4 files changed, 60 insertions(+), 4 deletions(-) diff --git a/src/audit/audit-session.ts b/src/audit/audit-session.ts index 26cade4..266fb67 100644 --- a/src/audit/audit-session.ts +++ b/src/audit/audit-session.ts @@ -288,4 +288,18 @@ export class AuditSession { unlock(); } } + + /** + * Log resume header to workflow.log + * Call this when a workflow is resuming to add a visual separator + */ + async logResumeHeader(resumeInfo: { + previousWorkflowId: string; + newWorkflowId: string; + checkpointHash: string; + completedAgents: string[]; + }): Promise { + await this.ensureInitialized(); + await this.workflowLogger.logResumeHeader(resumeInfo); + } } diff --git a/src/audit/workflow-logger.ts b/src/audit/workflow-logger.ts index 5276bb0..afd6b78 100644 --- a/src/audit/workflow-logger.ts +++ b/src/audit/workflow-logger.ts @@ -87,6 +87,34 @@ export class WorkflowLogger { return this.logStream.write(header); } + /** + * Write resume header to log file when workflow is resumed + */ + async logResumeHeader(resumeInfo: { + previousWorkflowId: string; + newWorkflowId: string; + checkpointHash: string; + completedAgents: string[]; + }): Promise { + await this.ensureInitialized(); + + const header = [ + ``, + `================================================================================`, + `RESUMED`, + `================================================================================`, + `Previous Workflow ID: ${resumeInfo.previousWorkflowId}`, + `New Workflow ID: ${resumeInfo.newWorkflowId}`, + `Resumed At: ${formatTimestamp()}`, + `Checkpoint: ${resumeInfo.checkpointHash}`, + `Completed: ${resumeInfo.completedAgents.length} agents (${resumeInfo.completedAgents.join(', ')})`, + `================================================================================`, + ``, + ].join('\n'); + + return this.logStream.write(header); + } + /** * Format timestamp for log line (local time, human readable) */ diff --git a/src/temporal/activities.ts b/src/temporal/activities.ts index e1138dc..bcf8b1c 100644 --- a/src/temporal/activities.ts +++ b/src/temporal/activities.ts @@ -485,17 +485,29 @@ export async function restoreGitCheckpoint( } /** - * Record a resume attempt in session.json. + * Record a resume attempt in session.json and write resume header to workflow.log. */ export async function recordResumeAttempt( input: ActivityInput, terminatedWorkflows: string[], - checkpointHash: string + checkpointHash: string, + previousWorkflowId: string, + completedAgents: string[] ): Promise { const sessionMetadata = buildSessionMetadata(input); const auditSession = new AuditSession(sessionMetadata); await auditSession.initialize(); + + // Update session.json with resume attempt await auditSession.addResumeAttempt(input.workflowId, terminatedWorkflows, checkpointHash); + + // Write resume header to workflow.log + await auditSession.logResumeHeader({ + previousWorkflowId, + newWorkflowId: input.workflowId, + checkpointHash, + completedAgents, + }); } // === Phase Transition Activities === diff --git a/src/temporal/workflows.ts b/src/temporal/workflows.ts index a51bd0a..e5d1b6a 100644 --- a/src/temporal/workflows.ts +++ b/src/temporal/workflows.ts @@ -178,11 +178,13 @@ export async function pentestPipelineWorkflow( return state; } - // Record resume attempt in session.json + // Record resume attempt in session.json and write resume header to workflow.log await a.recordResumeAttempt( activityInput, input.terminatedWorkflows || [], - resumeState.checkpointHash + resumeState.checkpointHash, + resumeState.originalWorkflowId, + resumeState.completedAgents ); log.info('Resume state loaded and workspace restored');