edit in tui/classify.go at line 714
[3.243975]→[3.243975:243997](∅→∅) replacement in tui/classify.go at line 723
[3.244222]→[3.244222:244259](∅→∅) − // Bindings help (wrap at 80 chars)
+ m.renderHeader(&b)
+ m.renderProgressBar(&b, current, total)
+ m.renderSegmentInfo(&b, df, seg)
+ m.renderLabels(&b, seg)
+
+ // Clip dialog (when active)
+ if m.clipMode {
+ m.renderClipDialog(&b)
+ return tea.NewView(b.String())
+ }
+
+ // Comment dialog (when active)
+ if m.commentMode {
+ m.renderCommentDialog(&b)
+ return tea.NewView(b.String())
+ }
+
+ // Error
+ if m.err != "" {
+ b.WriteString(errorStyle.Render(m.err))
+ }
+
+ v := tea.NewView(b.String())
+ v.AltScreen = true
+ return v
+ }
+
+ // renderHeader renders the keybindings help text
+ func (m Model) renderHeader(b *strings.Builder) {
edit in tui/classify.go at line 757
replacement in tui/classify.go at line 759
[3.244604]→[3.244604:244621](∅→∅) + // renderProgressBar renders the progress bar and file title
+ func (m Model) renderProgressBar(b *strings.Builder, current, total int) {
replacement in tui/classify.go at line 766
[3.244809]→[3.244809:244824](∅→∅) + df := m.state.CurrentFile()
edit in tui/classify.go at line 771
replacement in tui/classify.go at line 773
[3.245061]→[3.245061:245078](∅→∅) + // renderSegmentInfo renders segment timing and playback status
+ func (m Model) renderSegmentInfo(b *strings.Builder, df *utils.DataFile, seg *utils.Segment) {
edit in tui/classify.go at line 791
replacement in tui/classify.go at line 793
[3.245548]→[3.245548:245559](∅→∅) + // renderLabels renders the filter labels for the current segment
+ func (m Model) renderLabels(b *strings.Builder, seg *utils.Segment) {
replacement in tui/classify.go at line 800
[3.245750]→[3.245750:245845](∅→∅) − fmt.Fprintf(&b, " • %s\n", tools.FormatLabels([]*utils.Label{l}, m.state.Config.Filter))
+ fmt.Fprintf(b, " • %s\n", tools.FormatLabels([]*utils.Label{l}, m.state.Config.Filter))
edit in tui/classify.go at line 804
[3.245873]→[3.245873:246235](∅→∅) −
− // Clip dialog (when active)
− if m.clipMode {
− m.renderClipDialog(&b)
− return tea.NewView(b.String())
− }
−
− // Comment dialog (when active)
− if m.commentMode {
− m.renderCommentDialog(&b)
− return tea.NewView(b.String())
− }
−
− // Error
− if m.err != "" {
− b.WriteString(errorStyle.Render(m.err))
− }
−
− v := tea.NewView(b.String())
− v.AltScreen = true
− return v
edit in main.go at line 10
+ // commandDispatch maps command names to their handler functions.
+ var commandDispatch = map[string]func([]string) error{
+ "import": cmd.RunImport,
+ "sql": cmd.RunSQL,
+ "create": cmd.RunCreate,
+ "update": cmd.RunUpdate,
+ "export": cmd.RunExport,
+ "replay": cmd.RunReplay,
+ "calls": cmd.RunCalls,
+ "xxhash": cmd.RunXXHash,
+ "metadata": cmd.RunMetadata,
+ "time": cmd.RunTime,
+ "isnight": cmd.RunIsNight,
+ "prepend": cmd.RunPrepend,
+ }
+
replacement in main.go at line 32
[3.772942]→[3.772942:773137](∅→∅),
[3.773407]→[3.773407:773779](∅→∅) − switch os.Args[1] {
− case "import":
− cmd.RunImport(os.Args[2:])
− case "sql":
− cmd.RunSQL(os.Args[2:])
− case "create":
− cmd.RunCreate(os.Args[2:])
− case "update":
− cmd.RunUpdate(os.Args[2:])
− case "export":
− cmd.RunExport(os.Args[2:])
− case "replay":
− cmd.RunReplay(os.Args[2:])
− case "calls":
− cmd.RunCalls(os.Args[2:])
− case "xxhash":
− cmd.RunXXHash(os.Args[2:])
− case "metadata":
− cmd.RunMetadata(os.Args[2:])
− case "time":
− cmd.RunTime(os.Args[2:])
− case "isnight":
− cmd.RunIsNight(os.Args[2:])
− case "prepend":
− cmd.RunPrepend(os.Args[2:])
− default:
+ handler, ok := commandDispatch[os.Args[1]]
+ if !ok {
edit in main.go at line 36
+ os.Exit(1)
+ }
+
+ if err := handler(os.Args[2:]); err != nil {
+ fmt.Fprintf(os.Stderr, "Error: %v\n", err)
replacement in cmd/xxhash.go at line 20
[3.1037820]→[3.1037820:1037852](∅→∅) − func RunXXHash(args []string) {
+ func RunXXHash(args []string) error {
replacement in cmd/xxhash.go at line 35
[3.1038447]→[3.1038447:1038460](∅→∅) + return fmt.Errorf("parsing flags: %w", err)
edit in cmd/xxhash.go at line 39
[3.1038486]→[3.1038486:1038544](∅→∅) − fmt.Fprintf(os.Stderr, "Error: --file is required\n\n")
replacement in cmd/xxhash.go at line 40
[3.1038557]→[3.1038557:1038570](∅→∅) + return fmt.Errorf("--file is required")
edit in cmd/xxhash.go at line 43
[3.1038574]→[3.1038574:1038591](∅→∅) replacement in cmd/xxhash.go at line 45
[3.1038652]→[3.1038652:1038710](∅→∅) − fmt.Fprintf(os.Stderr, "Error: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("computing hash: %w", err)
edit in cmd/xxhash.go at line 48
[3.1038714]→[3.1038714:1038733](∅→∅) replacement in cmd/xxhash.go at line 56
[3.1038908]→[3.1038908:1038982](∅→∅) − fmt.Fprintf(os.Stderr, "Error encoding output: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("encoding output: %w", err)
edit in cmd/xxhash.go at line 58
replacement in cmd/update.go at line 9
[3.1039104]→[3.1039104:1039136](∅→∅) − func RunUpdate(args []string) {
+ func RunUpdate(args []string) error {
replacement in cmd/update.go at line 12
[3.1039177]→[3.1039177:1039190](∅→∅) + return fmt.Errorf("update subcommand required")
replacement in cmd/update.go at line 17
[3.1039229]→[3.1039229:1039258](∅→∅) − RunDatasetUpdate(args[1:])
+ return RunDatasetUpdate(args[1:])
replacement in cmd/update.go at line 19
[3.1039276]→[3.1039276:1039306](∅→∅) − RunLocationUpdate(args[1:])
+ return RunLocationUpdate(args[1:])
replacement in cmd/update.go at line 21
[3.1039323]→[3.1039323:1039352](∅→∅) − RunClusterUpdate(args[1:])
+ return RunClusterUpdate(args[1:])
replacement in cmd/update.go at line 23
[3.1039369]→[3.1039369:1039398](∅→∅) − RunPatternUpdate(args[1:])
+ return RunPatternUpdate(args[1:])
edit in cmd/update.go at line 25
[3.1039408]→[3.1039408:1039478](∅→∅) − fmt.Fprintf(os.Stderr, "Unknown resource to update: %s\n", args[0])
replacement in cmd/update.go at line 26
[3.1039499]→[3.1039499:1039512](∅→∅) + return fmt.Errorf("unknown resource to update: %s", args[0])
replacement in cmd/time.go at line 22
[3.1040879]→[3.1040879:1040909](∅→∅) − func RunTime(args []string) {
+ func RunTime(args []string) error {
replacement in cmd/time.go at line 34
[3.1041302]→[3.1041302:1041315](∅→∅) + return fmt.Errorf("parsing flags: %w", err)
edit in cmd/time.go at line 37
[3.1041319]→[3.1041319:1041340](∅→∅) replacement in cmd/time.go at line 39
[3.1041445]→[3.1041445:1041503](∅→∅) − fmt.Fprintf(os.Stderr, "Error: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("getting time: %w", err)
replacement in cmd/time.go at line 46
[3.1041630]→[3.1041630:1041704](∅→∅) − fmt.Fprintf(os.Stderr, "Error encoding output: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("encoding output: %w", err)
edit in cmd/time.go at line 48
edit in cmd/sql.go at line 15
[3.1041885]→[3.1041885:1041955](∅→∅) − // RunSQL handles CLI SQL query execution with direct database access
replacement in cmd/sql.go at line 27
[3.1042467]→[3.1042467:1042496](∅→∅) − func RunSQL(args []string) {
+ func RunSQL(args []string) error {
replacement in cmd/sql.go at line 43
[3.1043244]→[3.1043244:1043257](∅→∅) + return fmt.Errorf("parsing flags: %w", err)
edit in cmd/sql.go at line 47
[3.1043281]→[3.1043281:1043337](∅→∅) − fmt.Fprintf(os.Stderr, "Error: --db is required\n\n")
replacement in cmd/sql.go at line 48
[3.1043350]→[3.1043350:1043363](∅→∅) + return fmt.Errorf("--db is required")
edit in cmd/sql.go at line 51
[3.1043367]→[3.1043367:1043400](∅→∅) − // Remaining args are the query
edit in cmd/sql.go at line 53
[3.1043450]→[3.1043450:1043507](∅→∅) − fmt.Fprintf(os.Stderr, "Error: query is required\n\n")
replacement in cmd/sql.go at line 54
[3.1043520]→[3.1043520:1043533](∅→∅) + return fmt.Errorf("query is required")
replacement in cmd/sql.go at line 70
[3.1043777]→[3.1043777:1043835](∅→∅) − fmt.Fprintf(os.Stderr, "Error: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("executing query: %w", err)
replacement in cmd/sql.go at line 76
[3.1043943]→[3.1043943:1044017](∅→∅) − fmt.Fprintf(os.Stderr, "Error encoding output: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("encoding output: %w", err)
edit in cmd/sql.go at line 78
replacement in cmd/replay.go at line 17
[3.1044225]→[3.1044225:1044257](∅→∅) − func RunReplay(args []string) {
+ func RunReplay(args []string) error {
replacement in cmd/replay.go at line 20
[3.1044298]→[3.1044298:1044311](∅→∅) + return fmt.Errorf("replay subcommand required")
replacement in cmd/replay.go at line 25
[3.1044349]→[3.1044349:1044377](∅→∅) − runReplayEvents(args[1:])
+ return runReplayEvents(args[1:])
edit in cmd/replay.go at line 27
[3.1044387]→[3.1044387:1044458](∅→∅) − fmt.Fprintf(os.Stderr, "Unknown replay subcommand: %s\n\n", args[0])
replacement in cmd/replay.go at line 28
[3.1044479]→[3.1044479:1044492](∅→∅) + return fmt.Errorf("unknown replay subcommand: %s", args[0])
replacement in cmd/replay.go at line 42
[3.1045073]→[3.1045073:1045111](∅→∅) − func runReplayEvents(args []string) {
+ func runReplayEvents(args []string) error {
replacement in cmd/replay.go at line 64
[3.1046248]→[3.1046248:1046261](∅→∅) + return fmt.Errorf("parsing flags: %w", err)
replacement in cmd/replay.go at line 67
[3.1046265]→[3.1046265:1046372](∅→∅) − // Validate required flags
− missing := []string{}
− if *dbPath == "" {
− missing = append(missing, "--db")
+ if err := checkFlags(fs, "--db", *dbPath, "--log", *logPath); err != nil {
+ return err
edit in cmd/replay.go at line 70
[3.1046375]→[3.1046375:1046563](∅→∅) − if *logPath == "" {
− missing = append(missing, "--log")
− }
− if len(missing) > 0 {
− fmt.Fprintf(os.Stderr, "Error: missing required flags: %v\n\n", missing)
− fs.Usage()
− os.Exit(1)
− }
edit in cmd/replay.go at line 71
[3.1046564]→[3.1046564:1046580](∅→∅) replacement in cmd/replay.go at line 73
[3.1046634]→[3.1046634:1046707](∅→∅) − fmt.Fprintf(os.Stderr, "Error reading events: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("reading events: %w", err)
edit in cmd/replay.go at line 76
[3.1046711]→[3.1046711:1046729](∅→∅) replacement in cmd/replay.go at line 88
[3.1047131]→[3.1047131:1047140](∅→∅) edit in cmd/replay.go at line 91
[3.1047144]→[3.1047144:1047162](∅→∅) replacement in cmd/replay.go at line 93
[3.1047225]→[3.1047225:1047300](∅→∅) − fmt.Fprintf(os.Stderr, "Error opening database: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("opening database: %w", err)
edit in cmd/replay.go at line 97
[3.1047328]→[3.1047328:1047365](∅→∅) − // Disable event logging for replay
edit in cmd/replay.go at line 99
[3.1047423]→[3.1047423:1047445](∅→∅) replacement in cmd/replay.go at line 110
[3.1047766]→[3.1047766:1047867](∅→∅) − fmt.Fprintf(os.Stderr, "Stopping due to error. Use --continue to skip errors.\n")
− os.Exit(1)
+ return fmt.Errorf("replay failed at event %s: %w (use --continue to skip errors)", event.ID, err)
edit in cmd/replay.go at line 119
edit in cmd/replay.go at line 176
[3.1049611]→[3.1049611:1049632](∅→∅) edit in cmd/replay.go at line 187
[3.1049788]→[3.1049788:1049807](∅→∅) edit in cmd/replay.go at line 198
[3.1049967]→[3.1049967:1049987](∅→∅) edit in cmd/replay.go at line 202
[3.1050068]→[3.1050068:1050102](∅→∅) − // Only replay successful events
edit in cmd/replay.go at line 221
[3.1050543]→[3.1050543:1050593](∅→∅) − // Convert parameters to []interface{} for Exec
replacement in cmd/replay.go at line 237
[3.1050989]→[3.1050989:1051059](∅→∅) − sql = strings.Join(strings.Fields(sql), " ") // Normalize whitespace
+ sql = strings.Join(strings.Fields(sql), " ")
replacement in cmd/prepend.go at line 31
[3.1051884]→[3.1051884:1051917](∅→∅) − func RunPrepend(args []string) {
+ func RunPrepend(args []string) error {
replacement in cmd/prepend.go at line 54
[3.1053201]→[3.1053201:1053214](∅→∅) + return fmt.Errorf("parsing flags: %w", err)
edit in cmd/prepend.go at line 58
[3.1053238]→[3.1053238:1053298](∅→∅) − fmt.Fprintf(os.Stderr, "Error: --folder is required\n\n")
replacement in cmd/prepend.go at line 59
[3.1053311]→[3.1053311:1053324](∅→∅) + return fmt.Errorf("--folder is required")
edit in cmd/prepend.go at line 61
[3.1053327]→[3.1053327:1053328](∅→∅) edit in cmd/prepend.go at line 62
[3.1053348]→[3.1053348:1053408](∅→∅) − fmt.Fprintf(os.Stderr, "Error: --prefix is required\n\n")
replacement in cmd/prepend.go at line 63
[3.1053421]→[3.1053421:1053434](∅→∅) + return fmt.Errorf("--prefix is required")
edit in cmd/prepend.go at line 66
[3.1053438]→[3.1053438:1053468](∅→∅) − // Run the prepend operation
replacement in cmd/prepend.go at line 73
[3.1053630]→[3.1053630:1053688](∅→∅) − fmt.Fprintf(os.Stderr, "Error: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("prepend operation: %w", err)
edit in cmd/prepend.go at line 76
[3.1053692]→[3.1053692:1053711](∅→∅) replacement in cmd/prepend.go at line 79
[3.1053815]→[3.1053815:1053889](∅→∅) − fmt.Fprintf(os.Stderr, "Error encoding output: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("encoding output: %w", err)
edit in cmd/prepend.go at line 81
replacement in cmd/pattern.go at line 28
[3.1054577]→[3.1054577:1054616](∅→∅) − func RunPatternCreate(args []string) {
+ func RunPatternCreate(args []string) error {
replacement in cmd/pattern.go at line 45
[3.1055416]→[3.1055416:1055429](∅→∅) + return fmt.Errorf("parsing flags: %w", err)
replacement in cmd/pattern.go at line 49
[3.1055461]→[2.2951:3011](∅→∅) − requireFlags(fs, "--db", *dbPath)
− requireNonZeroFlags(fs,
+ if err := checkFlags(fs, "--db", *dbPath); err != nil {
+ return err
+ }
+ if err := checkNonZeroFlags(fs,
replacement in cmd/pattern.go at line 61
[2.3141]→[2.3141:3144](∅→∅) + ); err != nil {
+ return err
+ }
edit in cmd/pattern.go at line 66
[3.1055819]→[3.1055819:1055820](∅→∅) replacement in cmd/pattern.go at line 76
[3.1056025]→[3.1056025:1056083](∅→∅) − fmt.Fprintf(os.Stderr, "Error: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("creating pattern: %w", err)
edit in cmd/pattern.go at line 80
replacement in cmd/pattern.go at line 86
[3.1056219]→[3.1056219:1056258](∅→∅) − func RunPatternUpdate(args []string) {
+ func RunPatternUpdate(args []string) error {
replacement in cmd/pattern.go at line 103
[3.1057050]→[3.1057050:1057063](∅→∅) + return fmt.Errorf("parsing flags: %w", err)
replacement in cmd/pattern.go at line 106
[3.1057067]→[3.1057067:1057095](∅→∅),
[3.1057095]→[2.3145:3193](∅→∅) − // Validate required flags
− requireFlags(fs, "--db", *dbPath, "--id", *id)
+ if err := checkFlags(fs, "--db", *dbPath, "--id", *id); err != nil {
+ return err
+ }
edit in cmd/pattern.go at line 110
[3.1057360]→[3.1057360:1057388](∅→∅) − // Parse optional integers
replacement in cmd/pattern.go at line 114
[3.1057490]→[3.1057490:1057566](∅→∅) − fmt.Fprintf(os.Stderr, "Error: invalid record: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("invalid record value: %w", err)
replacement in cmd/pattern.go at line 121
[3.1057663]→[3.1057663:1057738](∅→∅) − fmt.Fprintf(os.Stderr, "Error: invalid sleep: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("invalid sleep value: %w", err)
edit in cmd/pattern.go at line 127
[3.1057785]→[3.1057785:1057786](∅→∅) edit in cmd/pattern.go at line 129
[3.1057818]→[3.1057818:1057871](∅→∅) − // Build input - only set fields that were provided
replacement in cmd/pattern.go at line 142
[3.1058110]→[3.1058110:1058168](∅→∅) − fmt.Fprintf(os.Stderr, "Error: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("updating pattern: %w", err)
edit in cmd/pattern.go at line 146
replacement in cmd/metadata.go at line 26
[3.1058912]→[3.1058912:1058946](∅→∅) − func RunMetadata(args []string) {
+ func RunMetadata(args []string) error {
replacement in cmd/metadata.go at line 41
[3.1059543]→[3.1059543:1059556](∅→∅) + return fmt.Errorf("parsing flags: %w", err)
edit in cmd/metadata.go at line 45
[3.1059582]→[3.1059582:1059640](∅→∅) − fmt.Fprintf(os.Stderr, "Error: --file is required\n\n")
replacement in cmd/metadata.go at line 46
[3.1059653]→[3.1059653:1059666](∅→∅) + return fmt.Errorf("--file is required")
edit in cmd/metadata.go at line 49
[3.1059670]→[3.1059670:1059691](∅→∅) replacement in cmd/metadata.go at line 51
[3.1059758]→[3.1059758:1059816](∅→∅) − fmt.Fprintf(os.Stderr, "Error: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("parsing WAV header: %w", err)
edit in cmd/metadata.go at line 54
[3.1059820]→[3.1059820:1059839](∅→∅) edit in cmd/metadata.go at line 62
[3.1060074]→[3.1060074:1060109](∅→∅) − // Add optional fields if present
replacement in cmd/metadata.go at line 75
[3.1060478]→[3.1060478:1060552](∅→∅) − fmt.Fprintf(os.Stderr, "Error encoding output: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("encoding output: %w", err)
edit in cmd/metadata.go at line 77
replacement in cmd/location.go at line 32
[3.1061479]→[3.1061479:1061519](∅→∅) − func RunLocationCreate(args []string) {
+ func RunLocationCreate(args []string) error {
replacement in cmd/location.go at line 52
[3.1062565]→[3.1062565:1062578](∅→∅) + return fmt.Errorf("parsing flags: %w", err)
replacement in cmd/location.go at line 55
[3.1062582]→[3.1062582:1062610](∅→∅),
[3.1062610]→[2.3196:3322](∅→∅) − // Validate required flags
− requireFlags(fs, "--db", *dbPath, "--dataset", *datasetID, "--name", *name, "--lat", *lat, "--lon", *lon, "--timezone", *tz)
+ if err := checkFlags(fs, "--db", *dbPath, "--dataset", *datasetID, "--name", *name, "--lat", *lat, "--lon", *lon, "--timezone", *tz); err != nil {
+ return err
+ }
edit in cmd/location.go at line 59
[3.1063121]→[3.1063121:1063138](∅→∅) replacement in cmd/location.go at line 61
[3.1063202]→[3.1063202:1063278](∅→∅) − fmt.Fprintf(os.Stderr, "Error: invalid latitude: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("invalid latitude: %w", err)
replacement in cmd/location.go at line 65
[3.1063346]→[3.1063346:1063423](∅→∅) − fmt.Fprintf(os.Stderr, "Error: invalid longitude: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("invalid longitude: %w", err)
edit in cmd/location.go at line 69
[3.1063453]→[3.1063453:1063454](∅→∅) replacement in cmd/location.go at line 83
[3.1063759]→[3.1063759:1063817](∅→∅) − fmt.Fprintf(os.Stderr, "Error: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("creating location: %w", err)
edit in cmd/location.go at line 87
replacement in cmd/location.go at line 93
[3.1063946]→[3.1063946:1063986](∅→∅) − func RunLocationUpdate(args []string) {
+ func RunLocationUpdate(args []string) error {
replacement in cmd/location.go at line 113
[3.1064942]→[3.1064942:1064955](∅→∅) + return fmt.Errorf("parsing flags: %w", err)
replacement in cmd/location.go at line 116
[3.1064959]→[3.1064959:1064987](∅→∅),
[3.1064987]→[2.3323:3371](∅→∅) − // Validate required flags
− requireFlags(fs, "--db", *dbPath, "--id", *id)
+ if err := checkFlags(fs, "--db", *dbPath, "--id", *id); err != nil {
+ return err
+ }
edit in cmd/location.go at line 121
[3.19757]→[3.19757:19758](∅→∅) replacement in cmd/location.go at line 123
[3.19790]→[3.19790:19874](∅→∅) − input := parseLocationUpdateInput(fs, dbPath, id, name, lat, lon, tz, description)
+ input, err := parseLocationUpdateInput(dbPath, id, name, lat, lon, tz, description)
+ if err != nil {
+ return err
+ }
replacement in cmd/location.go at line 130
[3.19966]→[3.19966:20024](∅→∅) − fmt.Fprintf(os.Stderr, "Error: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("updating location: %w", err)
edit in cmd/location.go at line 134
replacement in cmd/location.go at line 138
[3.20153]→[3.20153:20276](∅→∅) − func parseLocationUpdateInput(fs *flag.FlagSet, dbPath, id, name, lat, lon, tz, description *string) tools.LocationInput {
+ func parseLocationUpdateInput(dbPath, id, name, lat, lon, tz, description *string) (tools.LocationInput, error) {
replacement in cmd/location.go at line 143
[3.1065393]→[3.1065393:1065471](∅→∅) − fmt.Fprintf(os.Stderr, "Error: invalid latitude: %v\n", err)
− os.Exit(1)
+ return tools.LocationInput{}, fmt.Errorf("invalid latitude: %w", err)
replacement in cmd/location.go at line 150
[3.1065580]→[3.1065580:1065659](∅→∅) − fmt.Fprintf(os.Stderr, "Error: invalid longitude: %v\n", err)
− os.Exit(1)
+ return tools.LocationInput{}, fmt.Errorf("invalid longitude: %w", err)
replacement in cmd/location.go at line 174
[3.1066265]→[3.20277:20291](∅→∅) replacement in cmd/isnight.go at line 38
[3.1067659]→[3.1067659:1067692](∅→∅) − func RunIsNight(args []string) {
+ func RunIsNight(args []string) error {
replacement in cmd/isnight.go at line 60
[3.1069124]→[3.1069124:1069137](∅→∅) + return fmt.Errorf("parsing flags: %w", err)
edit in cmd/isnight.go at line 64
[3.1069163]→[3.1069163:1069221](∅→∅) − fmt.Fprintf(os.Stderr, "Error: --file is required\n\n")
replacement in cmd/isnight.go at line 65
[3.1069234]→[3.1069234:1069247](∅→∅) + return fmt.Errorf("--file is required")
edit in cmd/isnight.go at line 68
[3.1069279]→[3.1069279:1069347](∅→∅) − fmt.Fprintf(os.Stderr, "Error: --lat and --lng are required\n\n")
replacement in cmd/isnight.go at line 69
[3.1069360]→[3.1069360:1069373](∅→∅) + return fmt.Errorf("--lat and --lng are required")
replacement in cmd/isnight.go at line 79
[3.1069530]→[3.1069530:1069588](∅→∅) − fmt.Fprintf(os.Stderr, "Error: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("computing night status: %w", err)
edit in cmd/isnight.go at line 82
[3.1069592]→[3.1069592:1069610](∅→∅) replacement in cmd/isnight.go at line 84
[3.1069659]→[3.1069659:1069697](∅→∅) − encErr = enc.Encode(map[string]any{
+ if err := enc.Encode(map[string]any{
replacement in cmd/isnight.go at line 87
[3.1069769]→[3.1069769:1069774](∅→∅) + }); err != nil {
+ return fmt.Errorf("encoding output: %w", err)
+ }
replacement in cmd/isnight.go at line 93
[3.1069846]→[3.1069846:1069976](∅→∅) − encErr = enc.Encode(output)
− }
− if encErr != nil {
− fmt.Fprintf(os.Stderr, "Error encoding output: %v\n", encErr)
− os.Exit(1)
+ if err := enc.Encode(output); err != nil {
+ return fmt.Errorf("encoding output: %w", err)
+ }
edit in cmd/isnight.go at line 97
replacement in cmd/import.go at line 14
[3.1070155]→[3.1070155:1070187](∅→∅) − func RunImport(args []string) {
+ func RunImport(args []string) error {
replacement in cmd/import.go at line 17
[3.1070228]→[3.1070228:1070241](∅→∅) + return fmt.Errorf("import subcommand required")
edit in cmd/import.go at line 32
[3.1070501]→[3.1070501:1070572](∅→∅) − fmt.Fprintf(os.Stderr, "Unknown import subcommand: %s\n\n", args[0])
replacement in cmd/import.go at line 33
[3.1070593]→[3.1070593:1070606](∅→∅) + return fmt.Errorf("unknown import subcommand: %s", args[0])
edit in cmd/import.go at line 35
replacement in cmd/export.go at line 26
[3.1089626]→[3.1089626:1089658](∅→∅) − func RunExport(args []string) {
+ func RunExport(args []string) error {
replacement in cmd/export.go at line 29
[3.1089699]→[3.1089699:1089712](∅→∅) + return fmt.Errorf("export subcommand required")
replacement in cmd/export.go at line 34
[3.1089751]→[3.1089751:1089780](∅→∅) − runExportDataset(args[1:])
+ return runExportDataset(args[1:])
edit in cmd/export.go at line 36
[3.1089790]→[3.1089790:1089861](∅→∅) − fmt.Fprintf(os.Stderr, "Unknown export subcommand: %s\n\n", args[0])
replacement in cmd/export.go at line 37
[3.1089882]→[3.1089882:1089895](∅→∅) + return fmt.Errorf("unknown export subcommand: %s", args[0])
replacement in cmd/export.go at line 50
[3.1090403]→[3.1090403:1090442](∅→∅) − func runExportDataset(args []string) {
+ func runExportDataset(args []string) error {
replacement in cmd/export.go at line 70
[3.1091613]→[3.1091613:1091626](∅→∅) + return fmt.Errorf("parsing flags: %w", err)
replacement in cmd/export.go at line 73
[3.1091630]→[3.1091630:1091658](∅→∅),
[3.1091658]→[2.3997:4073](∅→∅) − // Validate required flags
− requireFlags(fs, "--db", *dbPath, "--id", *datasetID, "--output", *output)
+ if err := checkFlags(fs, "--db", *dbPath, "--id", *datasetID, "--output", *output); err != nil {
+ return err
+ }
replacement in cmd/export.go at line 89
[3.1092238]→[3.1092238:1092296](∅→∅) − fmt.Fprintf(os.Stderr, "Error: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("exporting dataset: %w", err)
replacement in cmd/export.go at line 95
[3.1092410]→[3.1092410:1092484](∅→∅) − fmt.Fprintf(os.Stderr, "Error encoding output: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("encoding output: %w", err)
edit in cmd/export.go at line 97
replacement in cmd/dataset.go at line 28
[3.1093232]→[3.1093232:1093271](∅→∅) − func RunDatasetCreate(args []string) {
+ func RunDatasetCreate(args []string) error {
replacement in cmd/dataset.go at line 46
[3.1094187]→[3.1094187:1094200](∅→∅) + return fmt.Errorf("parsing flags: %w", err)
replacement in cmd/dataset.go at line 49
[3.1094204]→[3.1094204:1094232](∅→∅),
[3.1094232]→[2.4075:4127](∅→∅) − // Validate required flags
− requireFlags(fs, "--db", *dbPath, "--name", *name)
+ if err := checkFlags(fs, "--db", *dbPath, "--name", *name); err != nil {
+ return err
+ }
edit in cmd/dataset.go at line 54
[3.1094527]→[3.1094527:1094528](∅→∅) replacement in cmd/dataset.go at line 65
[3.1094756]→[3.1094756:1094814](∅→∅) − fmt.Fprintf(os.Stderr, "Error: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("creating dataset: %w", err)
edit in cmd/dataset.go at line 69
replacement in cmd/dataset.go at line 75
[3.1094940]→[3.1094940:1094979](∅→∅) − func RunDatasetUpdate(args []string) {
+ func RunDatasetUpdate(args []string) error {
replacement in cmd/dataset.go at line 94
[3.1095924]→[3.1095924:1095937](∅→∅) + return fmt.Errorf("parsing flags: %w", err)
replacement in cmd/dataset.go at line 97
[3.1095941]→[3.1095941:1095969](∅→∅),
[3.1095969]→[2.4128:4176](∅→∅) − // Validate required flags
− requireFlags(fs, "--db", *dbPath, "--id", *id)
+ if err := checkFlags(fs, "--db", *dbPath, "--id", *id); err != nil {
+ return err
+ }
edit in cmd/dataset.go at line 102
[3.1096260]→[3.1096260:1096261](∅→∅) edit in cmd/dataset.go at line 104
[3.1096293]→[3.1096293:1096358](∅→∅) − // Build input - only set fields that were provided (non-empty)
replacement in cmd/dataset.go at line 120
[3.1096640]→[3.1096640:1096698](∅→∅) − fmt.Fprintf(os.Stderr, "Error: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("updating dataset: %w", err)
edit in cmd/dataset.go at line 124
replacement in cmd/create.go at line 9
[3.1096841]→[3.1096841:1096873](∅→∅) − func RunCreate(args []string) {
+ func RunCreate(args []string) error {
replacement in cmd/create.go at line 12
[3.1096914]→[3.1096914:1096927](∅→∅) + return fmt.Errorf("create subcommand required")
replacement in cmd/create.go at line 17
[3.1096966]→[3.1096966:1096995](∅→∅) − RunDatasetCreate(args[1:])
+ return RunDatasetCreate(args[1:])
replacement in cmd/create.go at line 19
[3.1097013]→[3.1097013:1097043](∅→∅) − RunLocationCreate(args[1:])
+ return RunLocationCreate(args[1:])
replacement in cmd/create.go at line 21
[3.1097060]→[3.1097060:1097089](∅→∅) − RunClusterCreate(args[1:])
+ return RunClusterCreate(args[1:])
replacement in cmd/create.go at line 23
[3.1097106]→[3.1097106:1097135](∅→∅) − RunPatternCreate(args[1:])
+ return RunPatternCreate(args[1:])
edit in cmd/create.go at line 25
[3.1097145]→[3.1097145:1097215](∅→∅) − fmt.Fprintf(os.Stderr, "Unknown resource to create: %s\n", args[0])
replacement in cmd/create.go at line 26
[3.1097236]→[3.1097236:1097249](∅→∅) + return fmt.Errorf("unknown resource to create: %s", args[0])
replacement in cmd/common.go at line 25
[2.4189]→[2.4189:4470](∅→∅) − // requireFlags checks that the given flag values are non-empty strings.
− // If any are empty, prints an error and exits with usage.
− // Each pair is (flagName, flagValue) — e.g. requireFlags(fs, "--db", *dbPath, "--id", *id)
− func requireFlags(fs *flag.FlagSet, pairs ...string) {
+ // checkFlags checks that the given flag values are non-empty strings.
+ // Returns an error if any are empty (does not call os.Exit).
+ // Each pair is (flagName, flagValue) — e.g. checkFlags(fs, "--db", *dbPath, "--id", *id)
+ func checkFlags(fs *flag.FlagSet, pairs ...string) error {
edit in cmd/common.go at line 36
[2.4623]→[2.4623:4698](∅→∅) − fmt.Fprintf(os.Stderr, "Error: missing required flags: %v\n\n", missing)
replacement in cmd/common.go at line 37
[2.4711]→[2.4711:4724](∅→∅) + return fmt.Errorf("missing required flags: %v", missing)
edit in cmd/common.go at line 39
replacement in cmd/common.go at line 42
[2.4730]→[2.4730:4958](∅→∅) − // requireNonZeroFlags checks that the given int flag values are non-zero.
− // Each pair is (flagName, flagValue) — e.g. requireNonZeroFlags(fs, "--record", *record)
− func requireNonZeroFlags(fs *flag.FlagSet, pairs ...struct {
+ // checkNonZeroFlags checks that the given int flag values are non-zero.
+ // Returns an error if any are zero (does not call os.Exit).
+ func checkNonZeroFlags(fs *flag.FlagSet, pairs ...struct {
replacement in cmd/common.go at line 47
[2.4983]→[2.4983:4988](∅→∅) edit in cmd/common.go at line 52
+ }
+ }
+ if len(missing) > 0 {
+ fs.Usage()
+ return fmt.Errorf("missing required flags: %v", missing)
+ }
+ return nil
+ }
+
+ // requireFlags checks that the given flag values are non-empty strings.
+ // If any are empty, prints usage and exits.
+ // Each pair is (flagName, flagValue) — e.g. requireFlags(fs, "--db", *dbPath, "--id", *id)
+ func requireFlags(fs *flag.FlagSet, pairs ...string) {
+ var missing []string
+ for i := 0; i < len(pairs); i += 2 {
+ if pairs[i+1] == "" {
+ missing = append(missing, pairs[i])
replacement in cmd/cluster.go at line 32
[3.1099875]→[3.1099875:1099914](∅→∅) − func RunClusterCreate(args []string) {
+ func RunClusterCreate(args []string) error {
replacement in cmd/cluster.go at line 51
[3.1100856]→[3.1100856:1100869](∅→∅) + return fmt.Errorf("parsing flags: %w", err)
replacement in cmd/cluster.go at line 54
[3.1100873]→[3.1100873:1100901](∅→∅),
[3.1100901]→[2.5232:5366](∅→∅) − // Validate required flags
− requireFlags(fs, "--db", *dbPath, "--dataset", *datasetID, "--location", *locationID, "--name", *name, "--sample-rate", *sampleRate)
+ if err := checkFlags(fs, "--db", *dbPath, "--dataset", *datasetID, "--location", *locationID, "--name", *name, "--sample-rate", *sampleRate); err != nil {
+ return err
+ }
edit in cmd/cluster.go at line 58
[3.1101378]→[3.1101378:1101400](∅→∅) replacement in cmd/cluster.go at line 60
[3.1101455]→[3.1101455:1101534](∅→∅) − fmt.Fprintf(os.Stderr, "Error: invalid sample rate: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("invalid sample rate: %w", err)
edit in cmd/cluster.go at line 64
[3.1101564]→[3.1101564:1101565](∅→∅) replacement in cmd/cluster.go at line 77
[3.1101843]→[3.1101843:1101901](∅→∅) − fmt.Fprintf(os.Stderr, "Error: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("creating cluster: %w", err)
edit in cmd/cluster.go at line 81
replacement in cmd/cluster.go at line 87
[3.1102027]→[3.1102027:1102066](∅→∅) − func RunClusterUpdate(args []string) {
+ func RunClusterUpdate(args []string) error {
replacement in cmd/cluster.go at line 105
[3.1102916]→[3.1102916:1102929](∅→∅) + return fmt.Errorf("parsing flags: %w", err)
replacement in cmd/cluster.go at line 108
[3.1102933]→[3.1102933:1102961](∅→∅),
[3.1102961]→[2.5367:5415](∅→∅) − // Validate required flags
− requireFlags(fs, "--db", *dbPath, "--id", *id)
+ if err := checkFlags(fs, "--db", *dbPath, "--id", *id); err != nil {
+ return err
+ }
edit in cmd/cluster.go at line 112
[3.1103226]→[3.1103226:1103257](∅→∅) − // Parse optional sample rate
replacement in cmd/cluster.go at line 116
[3.1103354]→[3.1103354:1103435](∅→∅) − fmt.Fprintf(os.Stderr, "Error: invalid sample rate: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("invalid sample rate: %w", err)
edit in cmd/cluster.go at line 122
[3.1103483]→[3.1103483:1103484](∅→∅) edit in cmd/cluster.go at line 124
[3.1103516]→[3.1103516:1103581](∅→∅) − // Build input - only set fields that were provided (non-empty)
replacement in cmd/cluster.go at line 140
[3.1103861]→[3.1103861:1103919](∅→∅) − fmt.Fprintf(os.Stderr, "Error: %v\n", err)
− os.Exit(1)
+ return fmt.Errorf("updating cluster: %w", err)
edit in cmd/cluster.go at line 144
replacement in cmd/calls.go at line 13
[3.1153948]→[3.1153948:1153979](∅→∅) − func RunCalls(args []string) {
+ func RunCalls(args []string) error {
replacement in cmd/calls.go at line 16
[3.1154019]→[3.1154019:1154032](∅→∅) + return fmt.Errorf("calls subcommand required")
edit in cmd/calls.go at line 22
edit in cmd/calls.go at line 25
edit in cmd/calls.go at line 28
edit in cmd/calls.go at line 31
edit in cmd/calls.go at line 34
edit in cmd/calls.go at line 37
edit in cmd/calls.go at line 40
edit in cmd/calls.go at line 43
edit in cmd/calls.go at line 46
edit in cmd/calls.go at line 49
edit in cmd/calls.go at line 52
edit in cmd/calls.go at line 55
edit in cmd/calls.go at line 57
[3.1154665]→[3.1154665:1154735](∅→∅) − fmt.Fprintf(os.Stderr, "Unknown calls subcommand: %s\n\n", args[0])
replacement in cmd/calls.go at line 58
[3.1154755]→[3.1154755:1154768](∅→∅) + return fmt.Errorf("unknown calls subcommand: %s", args[0])
replacement in CHANGELOG.md at line 50
[2.7791]→[2.7791:7834](∅→∅) − ### cmd/ boilerplate reduction (Stream 3b)
+ ### cmd/ boilerplate reduction (Streams 3b + 3c)
replacement in CHANGELOG.md at line 52
[2.7835]→[2.7835:7914](∅→∅) − Added `requireFlags()` and `requireNonZeroFlags()` helpers in `cmd/common.go`.
+ Added `checkFlags()`, `checkNonZeroFlags()`, and `requireFlags()` helpers in `cmd/common.go`.
edit in CHANGELOG.md at line 57
+ Converted core Run* functions to return `error` instead of calling `os.Exit`:
+ - All CRUD commands (create/update dataset/location/cluster/pattern)
+ - sql, export, replay, xxhash, metadata, isnight, prepend, time
+ - Top-level dispatchers: RunImport, RunCalls, RunCreate, RunUpdate, RunExport, RunReplay
+
+ main.go now uses a `commandDispatch` map and has a single error-handling
+ exit point. Reduced main() complexity from 15 to ~4.
+
+ Calls_* subcommand functions and import.go internal functions still use
+ os.Exit internally — to be converted in a follow-up pass.
+