package cli import ( "context" "flag" "fmt" "io" "gitea.maximumdirect.net/eric/ReleaseKit/buildinfo" "gitea.maximumdirect.net/eric/audita/internal/core/schema" "gitea.maximumdirect.net/eric/audita/internal/framework/llm" ) func sourceToCanonicalTranscript(source *schema.SourceTranscript) *schema.Transcript { segments := make([]schema.Segment, len(source.Segments)) for i, s := range source.Segments { id := i + 1 if s.ID != nil { id = *s.ID } segments[i] = schema.Segment{ ID: id, Speaker: s.Speaker, Start: s.Start, End: s.End, Text: s.Text, Categories: s.Categories, } } return &schema.Transcript{Segments: segments} } // Run executes the Audita CLI with the provided arguments and streams. func Run(ctx context.Context, args []string, stdout, stderr io.Writer) int { if len(args) == 0 { writeRootUsage(stdout) return 0 } if len(args) == 2 && args[0] == "help" { switch args[1] { case "process": writeProcessUsage(stdout) return 0 case "config": writeConfigUsage(stdout) return 0 case "version": writeVersionUsage(stdout) return 0 } } if isHelpCommand(args) { writeRootUsage(stdout) return 0 } if args[0] == "process" { return runProcess(ctx, args[1:], stdout, stderr) } if args[0] == "config" { return runConfig(ctx, args[1:], stdout, stderr) } if args[0] == "version" { return runVersion(args[1:], stdout, stderr) } fmt.Fprintf(stderr, "audita: unknown command %q\n\n", args[0]) writeRootUsage(stderr) return 2 } func runVersion(args []string, stdout, stderr io.Writer) int { flags := flag.NewFlagSet("version", flag.ContinueOnError) flags.SetOutput(stderr) flags.Usage = func() {} // Route usage after parsing so help stays on stdout. if err := flags.Parse(args); err != nil { if err == flag.ErrHelp { writeVersionUsage(stdout) return 0 } writeVersionUsage(stderr) return 2 } if positional := flags.Args(); len(positional) > 0 { fmt.Fprintf(stderr, "audita version: unexpected argument %q\n\n", positional[0]) writeVersionUsage(stderr) return 2 } fmt.Fprintf(stdout, "audita %s\n", buildinfo.Version()) return 0 } func runConfig(ctx context.Context, args []string, stdout, stderr io.Writer) int { if len(args) == 0 || isHelpCommand(args) || args[0] == "--help" || args[0] == "-h" { writeConfigUsage(stdout) return 0 } switch args[0] { case "validate": return runConfigValidate(ctx, args[1:], stdout, stderr) case "print-effective": return runConfigPrintEffective(ctx, args[1:], stdout, stderr) default: fmt.Fprintf(stderr, "audita config: unknown command %q\n\n", args[0]) writeConfigUsage(stderr) return 2 } } func runConfigValidate(ctx context.Context, args []string, stdout, stderr io.Writer) int { input, help, err := parseConfigInput("validate", args, stderr) if err != nil { fmt.Fprintf(stderr, "audita config validate: %s\n", configInputError(err)) return 2 } if help { writeConfigValidateUsage(stdout) return 0 } selected, err := loadConfigInput(input, "validate") if err != nil { fmt.Fprintf(stderr, "audita config validate: %s\n", configInputError(err)) return 2 } if _, err := llm.NewRuntime(ctx, selected.Result.Config, selected.Path, nil); err != nil { fmt.Fprintf(stderr, "audita config validate: %s\n", llm.RedactError(err, selected.Result.Config)) if ctx.Err() != nil || llm.IsAssetError(err) { return 1 } return 2 } fmt.Fprintln(stdout, "config is valid") return 0 } func runConfigPrintEffective(ctx context.Context, args []string, stdout, stderr io.Writer) int { input, help, err := parseConfigInput("print-effective", args, stderr) if err != nil { fmt.Fprintf(stderr, "audita config print-effective: %s\n", configInputError(err)) return 2 } if help { writeConfigPrintEffectiveUsage(stdout) return 0 } selected, err := loadConfigInput(input, "print-effective") if err != nil { fmt.Fprintf(stderr, "audita config print-effective: %s\n", configInputError(err)) return 2 } llmRuntime, err := llm.NewRuntime(ctx, selected.Result.Config, selected.Path, nil) if err != nil { fmt.Fprintf(stderr, "audita config print-effective: %s\n", llm.RedactError(err, selected.Result.Config)) if ctx.Err() != nil || llm.IsAssetError(err) { return 1 } return 2 } if input.View == "settings" { err = selected.Result.WriteEffective(stdout) } else { var output []byte if input.View == "profiles" { output, err = llmRuntime.SelectedProfilesYAML() } else { output, err = llm.ExplanationYAML(selected.Result) } if err == nil { _, err = stdout.Write(output) } } if err != nil { fmt.Fprintf(stderr, "audita config print-effective: %v\n", err) return 1 } return 0 } func isHelpCommand(args []string) bool { if len(args) == 0 { return false } if len(args) == 1 { switch args[0] { case "help", "-h", "--help": return true } } if len(args) == 2 && args[0] == "help" { switch args[1] { case "process": return true } } return false } func writeRootUsage(w io.Writer) { fmt.Fprintln(w, "Audita is a transcript processing CLI.") fmt.Fprintln(w) fmt.Fprintln(w, "Usage:") fmt.Fprintln(w, " audita [options]") fmt.Fprintln(w) fmt.Fprintln(w, "Commands:") fmt.Fprintln(w, " process Process a transcript JSON file") fmt.Fprintln(w, " config Validate and inspect config") fmt.Fprintln(w, " version Print the Audita version") fmt.Fprintln(w) fmt.Fprintln(w, "Example:") fmt.Fprintln(w, " audita process transcript.json --glossary glossary.yaml --output corrected.json") } func writeVersionUsage(w io.Writer) { fmt.Fprintln(w, "Print the Audita version.") fmt.Fprintln(w) fmt.Fprintln(w, "Usage:") fmt.Fprintln(w, " audita version") } func writeConfigUsage(w io.Writer) { fmt.Fprintln(w, "Validate and inspect Audita config.") fmt.Fprintln(w) fmt.Fprintln(w, "Usage:") fmt.Fprintln(w, " audita config [flags]") fmt.Fprintln(w) fmt.Fprintln(w, "Commands:") fmt.Fprintln(w, " validate Validate a versioned YAML config file") fmt.Fprintln(w, " print-effective Print redacted effective settings YAML") } func writeConfigValidateUsage(w io.Writer) { fmt.Fprintln(w, "Validate a versioned YAML config file.") fmt.Fprintln(w) fmt.Fprintln(w, "Usage:") fmt.Fprintln(w, " audita config validate --config [--overlay ] [setting flags]") } func writeConfigPrintEffectiveUsage(w io.Writer) { fmt.Fprintln(w, "Print redacted effective settings YAML.") fmt.Fprintln(w) fmt.Fprintln(w, "Usage:") fmt.Fprintln(w, " audita config print-effective [--config ] [--overlay ] [setting flags]") } func writeProcessUsage(w io.Writer) { fmt.Fprintln(w, "Process a transcript JSON file.") fmt.Fprintln(w) fmt.Fprintln(w, "Usage:") fmt.Fprintln(w, " audita process [flags]") fmt.Fprintln(w) fmt.Fprintln(w, "Flags:") for _, name := range []string{ "config", "overlay", "glossary", "output", "proposal-profile", "validation-profile", "modules", "output-schema", "validation-max-prompt-tokens", "target-sections", "max-section-tokens", "min-section-tokens", "normalize-max-segment-gap", "normalize-ellipsis-gap", "normalize-max-segment-duration", "normalize-max-segment-tokens", "glossary-confidence-threshold", "homophones-confidence-threshold", "spoken-word-confidence-threshold", "grammar-confidence-threshold", "transcript-description", "work-dir", } { fmt.Fprintf(w, " --%s\n", name) } fmt.Fprintln(w, " --reporting[=true|false] Write the three-file report bundle (default true)") fmt.Fprintln(w, " --report-dir DIR Select the report directory (stdout setting for stdout; output parent by default for files)") fmt.Fprintln(w, " --debug[=true|false] Persist detailed diagnostics (default false)") fmt.Fprintln(w) fmt.Fprintln(w, "Example:") fmt.Fprintln(w, " audita process transcript.json --glossary glossary.yaml --output corrected.json") }