From 539bd873cc8f62cf43caa83f7cafa2f21f511071 Mon Sep 17 00:00:00 2001 From: ajmallesh Date: Mon, 16 Feb 2026 09:26:12 -0800 Subject: [PATCH] fix: improve resume edge cases and shell quoting - Early exit when all agents already completed instead of running empty workflow - Descriptive error when deliverables missing from disk despite session.json success - Quote $WORKSPACE in shannon CLI to prevent word splitting --- src/temporal/activities.ts | 11 ++++++++++- src/temporal/workflows.ts | 9 +++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/temporal/activities.ts b/src/temporal/activities.ts index 454701b..6f76244 100644 --- a/src/temporal/activities.ts +++ b/src/temporal/activities.ts @@ -544,8 +544,17 @@ export async function loadResumeState( .filter((hash): hash is string => hash != null); if (checkpoints.length === 0) { + const successAgents = Object.entries(agents) + .filter(([, data]) => data.status === 'success') + .map(([name]) => name); + throw ApplicationFailure.nonRetryable( - `No successful agent checkpoints found in workspace ${workspaceName}`, + `Cannot resume workspace ${workspaceName}: ` + + (successAgents.length > 0 + ? `${successAgents.length} agent(s) show success in session.json (${successAgents.join(', ')}) ` + + `but their deliverable files are missing from disk. ` + + `Start a fresh run instead.` + : `No agents completed successfully. Start a fresh run instead.`), 'NoCheckpointsError' ); } diff --git a/src/temporal/workflows.ts b/src/temporal/workflows.ts index bed783e..3bc2804 100644 --- a/src/temporal/workflows.ts +++ b/src/temporal/workflows.ts @@ -167,6 +167,15 @@ export async function pentestPipelineWorkflow( incompleteAgents ); + // Check if all agents are already complete + if (resumeState.completedAgents.length === ALL_AGENTS.length) { + console.log(`All ${ALL_AGENTS.length} agents already completed. Nothing to resume.`); + state.status = 'completed'; + state.completedAgents = [...resumeState.completedAgents]; + state.summary = computeSummary(state); + return state; + } + // Record resume attempt in session.json await a.recordResumeAttempt( activityInput,