Files
audita/internal/cli/process.go

93 lines
3.4 KiB
Go
Raw Normal View History

package cli
import (
"errors"
"fmt"
"sync"
2026-10-11 01:40:38 +00:00
"gitea.maximumdirect.net/eric/audita/v3/internal/core/normalization"
"gitea.maximumdirect.net/eric/audita/v3/internal/core/outputschema"
"gitea.maximumdirect.net/eric/audita/v3/internal/core/reporting"
"gitea.maximumdirect.net/eric/audita/v3/internal/core/schema"
"gitea.maximumdirect.net/eric/audita/v3/internal/framework/llm"
"go.maximumdirect.net/ckconfig"
commandkit "go.maximumdirect.net/commandkit"
ck "go.maximumdirect.net/configkit"
)
// processResult carries the runner's transcript and ordinary report facts.
type processResult struct {
Transcript *schema.Transcript
Snapshot reporting.Snapshot
}
func runProcess(inv commandkit.Invocation, input processInput) commandkit.Outcome {
loaded, err := loadProcessInputs(inv.Context, input, inv.ReportingMode())
if err != nil {
if inv.Context.Err() != nil || llm.IsAssetError(err) {
return commandkit.Failure("Could not prepare processing.").WithCause(err)
}
var loadErr *ck.LoadError
if errors.As(err, &loadErr) {
_, explanation := ckconfig.AdaptDiagnostics("Application configuration:\n", loadErr.Sources(), loadErr.Diagnostics())
return commandkit.Usage(loadErr.Error(), explanation.Details...).WithCause(err)
}
return commandkit.Usage(err.Error()).WithCause(err)
}
prepared, err := prepareProcess(inv.Context, input, loaded, inv.Reporter().Output())
if err != nil {
return commandkit.Failure(loaded.Runtime.RedactError(inv.Context, err)).WithCause(err)
}
defer prepared.Prepared.Output.Close()
var warningsMu sync.Mutex
warn := func(err error) {
if err == nil {
return
}
warningsMu.Lock()
prepared.Prepared.Warnings = append(prepared.Prepared.Warnings, err)
warningsMu.Unlock()
}
debug := prepared.Prepared.Debug
if debug != nil {
warn(debug.WriteSourceTranscript(loaded.Source, loaded.RawTranscript))
}
cfg := &loaded.Configuration.Config
normalizer := normalization.NewNormalizer(normalization.NormalizationConfig{
MaxSegmentGap: cfg.Normalization.MaxSegmentGap, EllipsisGap: cfg.Normalization.EllipsisGap,
MaxSegmentDuration: cfg.Normalization.MaxSegmentDuration, MaxSegmentTokens: cfg.Normalization.MaxSegmentTokens,
})
normalized, summary := normalizer.Normalize(sourceToCanonicalTranscript(loaded.Source))
if debug != nil {
warn(debug.WriteNormalizedTranscript(normalized))
warn(debug.WriteNormalizationSummary(summary))
}
if err := inv.Context.Err(); err != nil {
return finishProcess(inv, input, loaded, prepared, reporting.Snapshot{}, nil, err)
}
result, runErr := executePipeline(inv.Context, loaded, prepared, normalized, warn)
if runErr != nil {
return finishProcess(inv, input, loaded, prepared, result.Snapshot, nil, runErr)
}
encoder, err := outputschema.Resolve(cfg.Output.Schema)
if err != nil {
return finishProcess(inv, input, loaded, prepared, result.Snapshot, nil, err)
}
if result.Transcript == nil {
return finishProcess(inv, input, loaded, prepared, result.Snapshot, nil, fmt.Errorf("processing returned no transcript"))
}
payload, err := encoder.Encoder(result.Transcript)
if err != nil {
return finishProcess(inv, input, loaded, prepared, result.Snapshot, nil, err)
}
return finishProcess(inv, input, loaded, prepared, result.Snapshot, payload, nil)
}
// DebugPath returns the retained artifact directory, if its preparation succeeded.
func (p *preparedProcess) DebugPath() string {
if p == nil || p.Prepared == nil || p.Prepared.Debug == nil {
return ""
}
return p.Prepared.Debug.Path()
}