up
Some checks failed
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Docs CI / lint-and-preview (push) Has been cancelled

This commit is contained in:
StellaOps Bot
2025-11-24 09:07:40 +02:00
parent 150b3730ef
commit e6119cbe91
59 changed files with 1827 additions and 204 deletions

View File

@@ -1304,10 +1304,60 @@ internal static class CommandFactory
cancellationToken);
});
var batchOptions = CreateAdvisoryOptions();
var batchKeys = new Argument<string[]>("advisory-keys")
{
Description = "One or more advisory identifiers.",
Arity = ArgumentArity.OneOrMore
};
var batch = new Command("batch", "Run Advisory AI over multiple advisories with a single invocation.");
batch.Add(batchKeys);
batch.Add(batchOptions.Output);
batch.Add(batchOptions.AdvisoryKey);
batch.Add(batchOptions.ArtifactId);
batch.Add(batchOptions.ArtifactPurl);
batch.Add(batchOptions.PolicyVersion);
batch.Add(batchOptions.Profile);
batch.Add(batchOptions.Sections);
batch.Add(batchOptions.ForceRefresh);
batch.Add(batchOptions.TimeoutSeconds);
batch.Add(batchOptions.Format);
batch.SetAction((parseResult, _) =>
{
var advisoryKeys = parseResult.GetValue(batchKeys) ?? Array.Empty<string>();
var artifactId = parseResult.GetValue(batchOptions.ArtifactId);
var artifactPurl = parseResult.GetValue(batchOptions.ArtifactPurl);
var policyVersion = parseResult.GetValue(batchOptions.PolicyVersion);
var profile = parseResult.GetValue(batchOptions.Profile) ?? "default";
var sections = parseResult.GetValue(batchOptions.Sections) ?? Array.Empty<string>();
var forceRefresh = parseResult.GetValue(batchOptions.ForceRefresh);
var timeoutSeconds = parseResult.GetValue(batchOptions.TimeoutSeconds) ?? 120;
var outputFormat = ParseAdvisoryOutputFormat(parseResult.GetValue(batchOptions.Format));
var outputDirectory = parseResult.GetValue(batchOptions.Output);
var verbose = parseResult.GetValue(verboseOption);
return CommandHandlers.HandleAdviseBatchAsync(
services,
AdvisoryAiTaskType.Summary,
advisoryKeys,
artifactId,
artifactPurl,
policyVersion,
profile,
sections,
forceRefresh,
timeoutSeconds,
outputFormat,
outputDirectory,
verbose,
cancellationToken);
});
advise.Add(run);
advise.Add(summarize);
advise.Add(explain);
advise.Add(remediate);
advise.Add(batch);
return advise;
}

View File

@@ -593,6 +593,92 @@ internal static class CommandHandlers
}
}
public static async Task HandleAdviseBatchAsync(
IServiceProvider services,
AdvisoryAiTaskType taskType,
IReadOnlyList<string> advisoryKeys,
string? artifactId,
string? artifactPurl,
string? policyVersion,
string profile,
IReadOnlyList<string> preferredSections,
bool forceRefresh,
int timeoutSeconds,
AdvisoryOutputFormat outputFormat,
string? outputDirectory,
bool verbose,
CancellationToken cancellationToken)
{
if (advisoryKeys.Count == 0)
{
throw new ArgumentException("At least one advisory key is required.", nameof(advisoryKeys));
}
var outputDir = string.IsNullOrWhiteSpace(outputDirectory) ? null : Path.GetFullPath(outputDirectory!);
if (outputDir is not null)
{
Directory.CreateDirectory(outputDir);
}
var results = new List<(string Advisory, int ExitCode)>();
var overallExit = 0;
foreach (var key in advisoryKeys)
{
var sanitized = string.IsNullOrWhiteSpace(key) ? "unknown" : key.Trim();
var ext = outputFormat switch
{
AdvisoryOutputFormat.Json => ".json",
AdvisoryOutputFormat.Markdown => ".md",
_ => ".txt"
};
var outputPath = outputDir is null ? null : Path.Combine(outputDir, $"{SanitizeFileName(sanitized)}-{taskType.ToString().ToLowerInvariant()}{ext}");
Environment.ExitCode = 0; // reset per advisory to capture individual result
await HandleAdviseRunAsync(
services,
taskType,
sanitized,
artifactId,
artifactPurl,
policyVersion,
profile,
preferredSections,
forceRefresh,
timeoutSeconds,
outputFormat,
outputPath,
verbose,
cancellationToken);
var code = Environment.ExitCode;
results.Add((sanitized, code));
overallExit = overallExit == 0 ? code : overallExit; // retain first non-zero if any
}
if (results.Count > 1)
{
var table = new Table()
.Border(TableBorder.Rounded)
.Title("[bold]Advisory Batch[/]");
table.AddColumn("Advisory");
table.AddColumn("Task");
table.AddColumn("Exit Code");
foreach (var result in results)
{
var exitText = result.ExitCode == 0 ? "[green]0[/]" : $"[red]{result.ExitCode}[/]";
table.AddRow(Markup.Escape(result.Advisory), taskType.ToString(), exitText);
}
AnsiConsole.Console.Write(table);
}
Environment.ExitCode = overallExit;
}
public static async Task HandleSourcesIngestAsync(
IServiceProvider services,
bool dryRun,