feat: provider extensions and drop claude-code-router mode (#295)

* feat: add ReportOutputProvider for consumer-extended report artifacts

* fix: thread deliverablesSubdir through report assembly

* fix: produce structured report JSON on resume path

* fix: fail loud on structured report output provider errors

* feat: extend checkpoint provider and container DI for consumer-specific backends

* fix: pre-create .shannon overlay mount points on all platforms

* chore: drop claude-code-router mode

* fix: drop 'resets' keyword from spending-cap text patterns
This commit is contained in:
ezl-keygraph
2026-04-20 13:21:54 +05:30
committed by GitHub
parent 01644ff2ed
commit 581c208b84
31 changed files with 240 additions and 416 deletions
+18 -21
View File
@@ -322,30 +322,14 @@ export async function pentestPipeline(input: PipelineInput): Promise<PipelineSta
];
}
// Aggregate results from settled pipeline promises into workflow state
// Aggregate errors from settled pipeline promises.
// Metrics and completedAgents are updated incrementally inside runVulnExploitPipeline
// so that getProgress queries reflect real-time status during execution.
function aggregatePipelineResults(results: PromiseSettledResult<VulnExploitPipelineResult>[]): void {
const failedPipelines: string[] = [];
for (const result of results) {
if (result.status === 'fulfilled') {
const { vulnType, vulnMetrics, exploitMetrics } = result.value;
const vulnAgentName = `${vulnType}-vuln`;
if (vulnMetrics) {
state.agentMetrics[vulnAgentName] = vulnMetrics;
state.completedAgents.push(vulnAgentName);
} else if (shouldSkip(vulnAgentName)) {
state.completedAgents.push(vulnAgentName);
}
const exploitAgentName = `${vulnType}-exploit`;
if (exploitMetrics) {
state.agentMetrics[exploitAgentName] = exploitMetrics;
state.completedAgents.push(exploitAgentName);
} else if (shouldSkip(exploitAgentName)) {
state.completedAgents.push(exploitAgentName);
}
} else {
if (result.status === 'rejected') {
const errorMsg = result.reason instanceof Error ? result.reason.message : String(result.reason);
failedPipelines.push(errorMsg);
}
@@ -432,14 +416,17 @@ export async function pentestPipeline(input: PipelineInput): Promise<PipelineSta
let vulnMetrics: AgentMetrics | null = null;
if (!shouldSkip(vulnAgentName)) {
vulnMetrics = await runVulnAgent();
state.agentMetrics[vulnAgentName] = vulnMetrics;
state.completedAgents.push(vulnAgentName);
if (input.checkpointsEnabled) {
await a.saveCheckpoint(activityInput, vulnAgentName, 'vulnerability-analysis', state);
}
} else {
log.info(`Skipping ${vulnAgentName} (already complete)`);
state.completedAgents.push(vulnAgentName);
}
// 1.5. Merge external findings (SAST, SCA, etc.) into exploitation queue
// 1.5. Merge external findings from consumer provider into exploitation queue
await a.mergeFindingsIntoQueue(activityInput, vulnType);
// 2. Check exploitation queue for actionable findings
@@ -450,11 +437,14 @@ export async function pentestPipeline(input: PipelineInput): Promise<PipelineSta
if (decision.shouldExploit) {
if (!shouldSkip(exploitAgentName)) {
exploitMetrics = await runExploitAgent();
state.agentMetrics[exploitAgentName] = exploitMetrics;
state.completedAgents.push(exploitAgentName);
if (input.checkpointsEnabled) {
await a.saveCheckpoint(activityInput, exploitAgentName, 'exploitation', state);
}
} else {
log.info(`Skipping ${exploitAgentName} (already complete)`);
state.completedAgents.push(exploitAgentName);
}
}
@@ -516,6 +506,13 @@ export async function pentestPipeline(input: PipelineInput): Promise<PipelineSta
state.completedAgents.push('report');
}
// Runs after the skip gate so consumer providers still execute on resume.
await a.generateReportOutputActivity(activityInput);
if (input.checkpointsEnabled) {
await a.saveCheckpoint(activityInput, 'report-output', 'reporting', state);
}
state.status = 'completed';
state.currentPhase = null;
state.currentAgent = null;