From a65dfcd0ba8d027a6d554b0c9f47ce3feaf880a0 Mon Sep 17 00:00:00 2001 From: Markus Graf Date: Thu, 26 Mar 2026 12:08:13 +0100 Subject: [PATCH] feat(02-03): wire -o output flag and snapshot accumulator stub into CLI - Add outputPath var and -o/--output Cobra flag (OUT-01) - Default output path resolves to netsynth-.mp3 when -o not provided (D-15) - Snapshot accumulator collects all WindowSnapshots for Phase 3 synthesis wiring - TODO(phase-3) marker for encode.RunSynthesis integration --- cmd/netsynth/main.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/cmd/netsynth/main.go b/cmd/netsynth/main.go index 77022d6..f727191 100644 --- a/cmd/netsynth/main.go +++ b/cmd/netsynth/main.go @@ -8,6 +8,7 @@ import ( "strings" "sync/atomic" "syscall" + "time" "github.com/spf13/cobra" @@ -20,6 +21,7 @@ var ( ifaceName string listIfaces bool verbose bool + outputPath string ) func main() { @@ -33,6 +35,7 @@ func main() { rootCmd.Flags().StringVarP(&ifaceName, "interface", "i", "", "Network interface to capture on (required unless --list-interfaces)") rootCmd.Flags().BoolVar(&listIfaces, "list-interfaces", false, "List available network interfaces and exit") rootCmd.Flags().BoolVar(&verbose, "verbose", false, "Print per-window protocol activity to stderr") + rootCmd.Flags().StringVarP(&outputPath, "output", "o", "", "Output MP3 file path (default: netsynth-.mp3)") if err := rootCmd.Execute(); err != nil { os.Exit(1) @@ -45,6 +48,11 @@ func run(cmd *cobra.Command, args []string) error { return runListInterfaces() } + // Resolve default output path (D-15 / OUT-01) + if outputPath == "" { + outputPath = fmt.Sprintf("netsynth-%s.mp3", time.Now().Format("20060102-150405")) + } + // Require -i flag if ifaceName == "" { return fmt.Errorf("interface required: use -i or --list-interfaces to see available interfaces") @@ -80,12 +88,17 @@ func run(cmd *cobra.Command, args []string) error { } snapshots := aggregate.Aggregate(ctx.Done(), classified, aggregate.DefaultWindowMs, onSnapshot) - // Consume snapshots and accumulate totals + // Accumulate snapshots for synthesis (Phase 3 will pass to encode.RunSynthesis) totals := make(map[classify.TrafficClass]int64) + var collectedSnapshots []classify.WindowSnapshot for snap := range snapshots { + collectedSnapshots = append(collectedSnapshots, snap) aggregate.AccumulateTotals(totals, snap) } + // TODO(phase-3): Pass collectedSnapshots to encode.RunSynthesis(collectedSnapshots, outputPath) + _ = collectedSnapshots + // Print exit summary (CLAS-03) dropped := atomic.LoadInt64(droppedPtr) if dropped > 0 {