feat(cli): add about command with build info display
- commit
- c1882116413af395d6b325a952cf89e698bf770f
- author
- bnema · · 2025-12-18 20:50 UTC
- parent
- 151b026
- signature
- unsigned
7 files · +156 -6
M cmd/dumber/main.go +9 -0
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | 10 | "github.com/bnema/dumber/assets" | |
| 11 | 11 | "github.com/bnema/dumber/internal/application/usecase" | |
| 12 | 12 | "github.com/bnema/dumber/internal/cli/cmd" | |
| 13 | + | "github.com/bnema/dumber/internal/domain/build" | |
| 13 | 14 | "github.com/bnema/dumber/internal/infrastructure/clipboard" | |
| 14 | 15 | "github.com/bnema/dumber/internal/infrastructure/config" | |
| 15 | 16 | "github.com/bnema/dumber/internal/infrastructure/media" | |
| @@ -43,6 +44,14 @@ func main() { | |||
| 43 | 44 | return | |
| 44 | 45 | } | |
| 45 | 46 | ||
| 47 | + | // Pass build info to CLI | |
| 48 | + | cmd.SetBuildInfo(build.Info{ | |
| 49 | + | Version: version, | |
| 50 | + | Commit: commit, | |
| 51 | + | BuildDate: buildDate, | |
| 52 | + | GoVersion: runtime.Version(), | |
| 53 | + | }) | |
| 54 | + | ||
| 46 | 55 | // Default: run CLI (shows help if no subcommand) | |
| 47 | 56 | cmd.Execute() | |
| 48 | 57 | } | |
| @@ -10,6 +10,7 @@ import ( | |||||
| 10 | "github.com/bnema/dumber/assets" | 10 | "github.com/bnema/dumber/assets" | ||
| 11 | "github.com/bnema/dumber/internal/application/usecase" | 11 | "github.com/bnema/dumber/internal/application/usecase" | ||
| 12 | "github.com/bnema/dumber/internal/cli/cmd" | 12 | "github.com/bnema/dumber/internal/cli/cmd" | ||
| 13 | + | "github.com/bnema/dumber/internal/domain/build" | |||
| 13 | "github.com/bnema/dumber/internal/infrastructure/clipboard" | 14 | "github.com/bnema/dumber/internal/infrastructure/clipboard" | ||
| 14 | "github.com/bnema/dumber/internal/infrastructure/config" | 15 | "github.com/bnema/dumber/internal/infrastructure/config" | ||
| 15 | "github.com/bnema/dumber/internal/infrastructure/media" | 16 | "github.com/bnema/dumber/internal/infrastructure/media" | ||
| @@ -43,6 +44,14 @@ func main() { | |||||
| 43 | return | 44 | return | ||
| 44 | } | 45 | } | ||
| 45 | 46 | ||||
| 47 | + | // Pass build info to CLI | |||
| 48 | + | cmd.SetBuildInfo(build.Info{ | |||
| 49 | + | Version: version, | |||
| 50 | + | Commit: commit, | |||
| 51 | + | BuildDate: buildDate, | |||
| 52 | + | GoVersion: runtime.Version(), | |||
| 53 | + | }) | |||
| 54 | + | ||||
| 46 | // Default: run CLI (shows help if no subcommand) | 55 | // Default: run CLI (shows help if no subcommand) | ||
| 47 | cmd.Execute() | 56 | cmd.Execute() | ||
| 48 | } | 57 | } | ||
M internal/cli/app.go +6 -4
| @@ -10,6 +10,7 @@ import ( | |||
| 10 | 10 | ||
| 11 | 11 | "github.com/bnema/dumber/internal/application/usecase" | |
| 12 | 12 | "github.com/bnema/dumber/internal/cli/styles" | |
| 13 | + | "github.com/bnema/dumber/internal/domain/build" | |
| 13 | 14 | "github.com/bnema/dumber/internal/domain/repository" | |
| 14 | 15 | "github.com/bnema/dumber/internal/infrastructure/config" | |
| 15 | 16 | "github.com/bnema/dumber/internal/infrastructure/persistence/sqlite" | |
| @@ -18,10 +19,11 @@ import ( | |||
| 18 | 19 | ||
| 19 | 20 | // App holds CLI dependencies. | |
| 20 | 21 | type App struct { | |
| 21 | - | Config *config.Config | |
| 22 | - | Theme *styles.Theme | |
| 23 | - | db *sql.DB | |
| 24 | - | History repository.HistoryRepository | |
| 22 | + | Config *config.Config | |
| 23 | + | Theme *styles.Theme | |
| 24 | + | BuildInfo build.Info | |
| 25 | + | db *sql.DB | |
| 26 | + | History repository.HistoryRepository | |
| 25 | 27 | ||
| 26 | 28 | // Use cases | |
| 27 | 29 | SearchHistoryUC *usecase.SearchHistoryUseCase | |
| @@ -10,6 +10,7 @@ import ( | |||||
| 10 | 10 | ||||
| 11 | "github.com/bnema/dumber/internal/application/usecase" | 11 | "github.com/bnema/dumber/internal/application/usecase" | ||
| 12 | "github.com/bnema/dumber/internal/cli/styles" | 12 | "github.com/bnema/dumber/internal/cli/styles" | ||
| 13 | + | "github.com/bnema/dumber/internal/domain/build" | |||
| 13 | "github.com/bnema/dumber/internal/domain/repository" | 14 | "github.com/bnema/dumber/internal/domain/repository" | ||
| 14 | "github.com/bnema/dumber/internal/infrastructure/config" | 15 | "github.com/bnema/dumber/internal/infrastructure/config" | ||
| 15 | "github.com/bnema/dumber/internal/infrastructure/persistence/sqlite" | 16 | "github.com/bnema/dumber/internal/infrastructure/persistence/sqlite" | ||
| @@ -18,10 +19,11 @@ import ( | |||||
| 18 | 19 | ||||
| 19 | // App holds CLI dependencies. | 20 | // App holds CLI dependencies. | ||
| 20 | type App struct { | 21 | type App struct { | ||
| 21 | - | Config *config.Config | 22 | + | Config *config.Config |
| 22 | - | Theme *styles.Theme | 23 | + | Theme *styles.Theme |
| 23 | - | db *sql.DB | 24 | + | BuildInfo build.Info |
| 24 | - | History repository.HistoryRepository | 25 | + | db *sql.DB |
| 26 | + | History repository.HistoryRepository | |||
| 25 | 27 | ||||
| 26 | // Use cases | 28 | // Use cases | ||
| 27 | SearchHistoryUC *usecase.SearchHistoryUseCase | 29 | SearchHistoryUC *usecase.SearchHistoryUseCase | ||
A internal/cli/cmd/about.go +33 -0
| @@ -0,0 +1,33 @@ | |||
| 1 | + | package cmd | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "fmt" | |
| 5 | + | ||
| 6 | + | "github.com/spf13/cobra" | |
| 7 | + | ||
| 8 | + | "github.com/bnema/dumber/internal/cli/styles" | |
| 9 | + | ) | |
| 10 | + | ||
| 11 | + | var aboutCmd = &cobra.Command{ | |
| 12 | + | Use: "about", | |
| 13 | + | Short: "Show version and build information", | |
| 14 | + | Long: `Display version, build info, repository URL, and contributors.`, | |
| 15 | + | RunE: runAbout, | |
| 16 | + | } | |
| 17 | + | ||
| 18 | + | func init() { | |
| 19 | + | rootCmd.AddCommand(aboutCmd) | |
| 20 | + | } | |
| 21 | + | ||
| 22 | + | func runAbout(cmd *cobra.Command, args []string) error { | |
| 23 | + | app := GetApp() | |
| 24 | + | if app == nil { | |
| 25 | + | return fmt.Errorf("app not initialized") | |
| 26 | + | } | |
| 27 | + | ||
| 28 | + | renderer := styles.NewAboutRenderer(app.Theme) | |
| 29 | + | output := renderer.Render(app.BuildInfo) | |
| 30 | + | ||
| 31 | + | fmt.Println(output) | |
| 32 | + | return nil | |
| 33 | + | } | |
| @@ -0,0 +1,33 @@ | |||||
| 1 | + | package cmd | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "fmt" | |||
| 5 | + | ||||
| 6 | + | "github.com/spf13/cobra" | |||
| 7 | + | ||||
| 8 | + | "github.com/bnema/dumber/internal/cli/styles" | |||
| 9 | + | ) | |||
| 10 | + | ||||
| 11 | + | var aboutCmd = &cobra.Command{ | |||
| 12 | + | Use: "about", | |||
| 13 | + | Short: "Show version and build information", | |||
| 14 | + | Long: `Display version, build info, repository URL, and contributors.`, | |||
| 15 | + | RunE: runAbout, | |||
| 16 | + | } | |||
| 17 | + | ||||
| 18 | + | func init() { | |||
| 19 | + | rootCmd.AddCommand(aboutCmd) | |||
| 20 | + | } | |||
| 21 | + | ||||
| 22 | + | func runAbout(cmd *cobra.Command, args []string) error { | |||
| 23 | + | app := GetApp() | |||
| 24 | + | if app == nil { | |||
| 25 | + | return fmt.Errorf("app not initialized") | |||
| 26 | + | } | |||
| 27 | + | ||||
| 28 | + | renderer := styles.NewAboutRenderer(app.Theme) | |||
| 29 | + | output := renderer.Render(app.BuildInfo) | |||
| 30 | + | ||||
| 31 | + | fmt.Println(output) | |||
| 32 | + | return nil | |||
| 33 | + | } | |||
M internal/cli/cmd/root.go +11 -2
| @@ -8,11 +8,13 @@ import ( | |||
| 8 | 8 | "github.com/spf13/cobra" | |
| 9 | 9 | ||
| 10 | 10 | "github.com/bnema/dumber/internal/cli" | |
| 11 | + | "github.com/bnema/dumber/internal/domain/build" | |
| 11 | 12 | ) | |
| 12 | 13 | ||
| 13 | 14 | var ( | |
| 14 | - | app *cli.App | |
| 15 | - | rootCmd = &cobra.Command{ | |
| 15 | + | app *cli.App | |
| 16 | + | buildInfo build.Info | |
| 17 | + | rootCmd = &cobra.Command{ | |
| 16 | 18 | Use: "dumber", | |
| 17 | 19 | Short: "A minimal web browser", | |
| 18 | 20 | Long: `Dumber is a minimal, keyboard-driven web browser built with GTK4 and WebKitGTK.`, | |
| @@ -27,6 +29,8 @@ var ( | |||
| 27 | 29 | if err != nil { | |
| 28 | 30 | return fmt.Errorf("initialize app: %w", err) | |
| 29 | 31 | } | |
| 32 | + | // Set build info from main.go | |
| 33 | + | app.BuildInfo = buildInfo | |
| 30 | 34 | return nil | |
| 31 | 35 | }, | |
| 32 | 36 | PersistentPostRun: func(cmd *cobra.Command, args []string) { | |
| @@ -69,3 +73,8 @@ Examples: | |||
| 69 | 73 | func init() { | |
| 70 | 74 | rootCmd.AddCommand(browseCmd) | |
| 71 | 75 | } | |
| 76 | + | ||
| 77 | + | // SetBuildInfo sets the build information (called from main.go before Execute). | |
| 78 | + | func SetBuildInfo(info build.Info) { | |
| 79 | + | buildInfo = info | |
| 80 | + | } | |
| @@ -8,11 +8,13 @@ import ( | |||||
| 8 | "github.com/spf13/cobra" | 8 | "github.com/spf13/cobra" | ||
| 9 | 9 | ||||
| 10 | "github.com/bnema/dumber/internal/cli" | 10 | "github.com/bnema/dumber/internal/cli" | ||
| 11 | + | "github.com/bnema/dumber/internal/domain/build" | |||
| 11 | ) | 12 | ) | ||
| 12 | 13 | ||||
| 13 | var ( | 14 | var ( | ||
| 14 | - | app *cli.App | 15 | + | app *cli.App |
| 15 | - | rootCmd = &cobra.Command{ | 16 | + | buildInfo build.Info |
| 17 | + | rootCmd = &cobra.Command{ | |||
| 16 | Use: "dumber", | 18 | Use: "dumber", | ||
| 17 | Short: "A minimal web browser", | 19 | Short: "A minimal web browser", | ||
| 18 | Long: `Dumber is a minimal, keyboard-driven web browser built with GTK4 and WebKitGTK.`, | 20 | Long: `Dumber is a minimal, keyboard-driven web browser built with GTK4 and WebKitGTK.`, | ||
| @@ -27,6 +29,8 @@ var ( | |||||
| 27 | if err != nil { | 29 | if err != nil { | ||
| 28 | return fmt.Errorf("initialize app: %w", err) | 30 | return fmt.Errorf("initialize app: %w", err) | ||
| 29 | } | 31 | } | ||
| 32 | + | // Set build info from main.go | |||
| 33 | + | app.BuildInfo = buildInfo | |||
| 30 | return nil | 34 | return nil | ||
| 31 | }, | 35 | }, | ||
| 32 | PersistentPostRun: func(cmd *cobra.Command, args []string) { | 36 | PersistentPostRun: func(cmd *cobra.Command, args []string) { | ||
| @@ -69,3 +73,8 @@ Examples: | |||||
| 69 | func init() { | 73 | func init() { | ||
| 70 | rootCmd.AddCommand(browseCmd) | 74 | rootCmd.AddCommand(browseCmd) | ||
| 71 | } | 75 | } | ||
| 76 | + | ||||
| 77 | + | // SetBuildInfo sets the build information (called from main.go before Execute). | |||
| 78 | + | func SetBuildInfo(info build.Info) { | |||
| 79 | + | buildInfo = info | |||
| 80 | + | } | |||
A internal/cli/styles/about.go +62 -0
| @@ -0,0 +1,62 @@ | |||
| 1 | + | package styles | |
| 2 | + | ||
| 3 | + | import ( | |
| 4 | + | "fmt" | |
| 5 | + | "strings" | |
| 6 | + | ||
| 7 | + | "github.com/charmbracelet/lipgloss" | |
| 8 | + | ||
| 9 | + | "github.com/bnema/dumber/internal/domain/build" | |
| 10 | + | ) | |
| 11 | + | ||
| 12 | + | // AboutRenderer renders build info in fastfetch style. | |
| 13 | + | type AboutRenderer struct { | |
| 14 | + | theme *Theme | |
| 15 | + | } | |
| 16 | + | ||
| 17 | + | // NewAboutRenderer creates a new about renderer with the given theme. | |
| 18 | + | func NewAboutRenderer(theme *Theme) *AboutRenderer { | |
| 19 | + | return &AboutRenderer{theme: theme} | |
| 20 | + | } | |
| 21 | + | ||
| 22 | + | // Render renders build info with ASCII logo and styled info lines. | |
| 23 | + | func (r *AboutRenderer) Render(info build.Info) string { | |
| 24 | + | logo := r.renderLogo() | |
| 25 | + | lines := r.renderInfoLines(info) | |
| 26 | + | ||
| 27 | + | // Combine horizontally: logo | info | |
| 28 | + | return lipgloss.JoinHorizontal(lipgloss.Top, logo, " ", lines) | |
| 29 | + | } | |
| 30 | + | ||
| 31 | + | func (r *AboutRenderer) renderLogo() string { | |
| 32 | + | // ASCII art: Lightning bolt + D (matches pixel logo) | |
| 33 | + | // All in accent color (green) | |
| 34 | + | logoStyle := lipgloss.NewStyle().Foreground(r.theme.Accent).Bold(true) | |
| 35 | + | ||
| 36 | + | // Simple bold D | |
| 37 | + | logo := `██████▄ | |
| 38 | + | ██ ██ | |
| 39 | + | ██ ██ | |
| 40 | + | ██ ██ | |
| 41 | + | ██████▀` | |
| 42 | + | ||
| 43 | + | return logoStyle.MarginTop(1).MarginLeft(2).Render(logo) | |
| 44 | + | } | |
| 45 | + | ||
| 46 | + | func (r *AboutRenderer) renderInfoLines(info build.Info) string { | |
| 47 | + | keyStyle := r.theme.Subtle | |
| 48 | + | valStyle := r.theme.Highlight | |
| 49 | + | iconStyle := lipgloss.NewStyle().Foreground(r.theme.Accent) | |
| 50 | + | ||
| 51 | + | lines := []string{ | |
| 52 | + | fmt.Sprintf("%s %s %s", iconStyle.Render(IconVersion), keyStyle.Render("Version"), valStyle.Render(info.Version)), | |
| 53 | + | fmt.Sprintf("%s %s %s", iconStyle.Render(IconGitBranch), keyStyle.Render("Commit"), valStyle.Render(info.Commit)), | |
| 54 | + | fmt.Sprintf("%s %s %s", iconStyle.Render(IconCalendar), keyStyle.Render("Built"), valStyle.Render(info.BuildDate)), | |
| 55 | + | fmt.Sprintf("%s %s %s", iconStyle.Render(IconGo), keyStyle.Render("Go"), valStyle.Render(info.GoVersion)), | |
| 56 | + | "", | |
| 57 | + | fmt.Sprintf("%s %s", iconStyle.Render(IconGithub), keyStyle.Render(build.RepoURL())), | |
| 58 | + | fmt.Sprintf("%s %s %s", iconStyle.Render(IconHeart), keyStyle.Render("Made with love by"), valStyle.Render(strings.Join(build.Contributors(), ", "))), | |
| 59 | + | } | |
| 60 | + | ||
| 61 | + | return strings.Join(lines, "\n") | |
| 62 | + | } | |
| @@ -0,0 +1,62 @@ | |||||
| 1 | + | package styles | |||
| 2 | + | ||||
| 3 | + | import ( | |||
| 4 | + | "fmt" | |||
| 5 | + | "strings" | |||
| 6 | + | ||||
| 7 | + | "github.com/charmbracelet/lipgloss" | |||
| 8 | + | ||||
| 9 | + | "github.com/bnema/dumber/internal/domain/build" | |||
| 10 | + | ) | |||
| 11 | + | ||||
| 12 | + | // AboutRenderer renders build info in fastfetch style. | |||
| 13 | + | type AboutRenderer struct { | |||
| 14 | + | theme *Theme | |||
| 15 | + | } | |||
| 16 | + | ||||
| 17 | + | // NewAboutRenderer creates a new about renderer with the given theme. | |||
| 18 | + | func NewAboutRenderer(theme *Theme) *AboutRenderer { | |||
| 19 | + | return &AboutRenderer{theme: theme} | |||
| 20 | + | } | |||
| 21 | + | ||||
| 22 | + | // Render renders build info with ASCII logo and styled info lines. | |||
| 23 | + | func (r *AboutRenderer) Render(info build.Info) string { | |||
| 24 | + | logo := r.renderLogo() | |||
| 25 | + | lines := r.renderInfoLines(info) | |||
| 26 | + | ||||
| 27 | + | // Combine horizontally: logo | info | |||
| 28 | + | return lipgloss.JoinHorizontal(lipgloss.Top, logo, " ", lines) | |||
| 29 | + | } | |||
| 30 | + | ||||
| 31 | + | func (r *AboutRenderer) renderLogo() string { | |||
| 32 | + | // ASCII art: Lightning bolt + D (matches pixel logo) | |||
| 33 | + | // All in accent color (green) | |||
| 34 | + | logoStyle := lipgloss.NewStyle().Foreground(r.theme.Accent).Bold(true) | |||
| 35 | + | ||||
| 36 | + | // Simple bold D | |||
| 37 | + | logo := `██████▄ | |||
| 38 | + | ██ ██ | |||
| 39 | + | ██ ██ | |||
| 40 | + | ██ ██ | |||
| 41 | + | ██████▀` | |||
| 42 | + | ||||
| 43 | + | return logoStyle.MarginTop(1).MarginLeft(2).Render(logo) | |||
| 44 | + | } | |||
| 45 | + | ||||
| 46 | + | func (r *AboutRenderer) renderInfoLines(info build.Info) string { | |||
| 47 | + | keyStyle := r.theme.Subtle | |||
| 48 | + | valStyle := r.theme.Highlight | |||
| 49 | + | iconStyle := lipgloss.NewStyle().Foreground(r.theme.Accent) | |||
| 50 | + | ||||
| 51 | + | lines := []string{ | |||
| 52 | + | fmt.Sprintf("%s %s %s", iconStyle.Render(IconVersion), keyStyle.Render("Version"), valStyle.Render(info.Version)), | |||
| 53 | + | fmt.Sprintf("%s %s %s", iconStyle.Render(IconGitBranch), keyStyle.Render("Commit"), valStyle.Render(info.Commit)), | |||
| 54 | + | fmt.Sprintf("%s %s %s", iconStyle.Render(IconCalendar), keyStyle.Render("Built"), valStyle.Render(info.BuildDate)), | |||
| 55 | + | fmt.Sprintf("%s %s %s", iconStyle.Render(IconGo), keyStyle.Render("Go"), valStyle.Render(info.GoVersion)), | |||
| 56 | + | "", | |||
| 57 | + | fmt.Sprintf("%s %s", iconStyle.Render(IconGithub), keyStyle.Render(build.RepoURL())), | |||
| 58 | + | fmt.Sprintf("%s %s %s", iconStyle.Render(IconHeart), keyStyle.Render("Made with love by"), valStyle.Render(strings.Join(build.Contributors(), ", "))), | |||
| 59 | + | } | |||
| 60 | + | ||||
| 61 | + | return strings.Join(lines, "\n") | |||
| 62 | + | } | |||
A internal/cli/styles/icons.go +15 -0
| @@ -0,0 +1,15 @@ | |||
| 1 | + | // Package styles provides reusable lipgloss-based TUI components. | |
| 2 | + | package styles | |
| 3 | + | ||
| 4 | + | // Nerd Font icons (requires a Nerd Font to display correctly) | |
| 5 | + | const ( | |
| 6 | + | IconGlobe = "\uf0ac" // browser/web | |
| 7 | + | IconVersion = "\uf02b" // tag | |
| 8 | + | IconGitBranch = "\ue725" // git branch | |
| 9 | + | IconCalendar = "\uf073" // calendar | |
| 10 | + | IconCode = "\uf121" // code | |
| 11 | + | IconGithub = "\uf09b" // github | |
| 12 | + | IconHeart = "\uf004" // heart | |
| 13 | + | IconGo = "\ue627" // go gopher | |
| 14 | + | IconArrow = "\uf061" // arrow right | |
| 15 | + | ) | |
| @@ -0,0 +1,15 @@ | |||||
| 1 | + | // Package styles provides reusable lipgloss-based TUI components. | |||
| 2 | + | package styles | |||
| 3 | + | ||||
| 4 | + | // Nerd Font icons (requires a Nerd Font to display correctly) | |||
| 5 | + | const ( | |||
| 6 | + | IconGlobe = "\uf0ac" // browser/web | |||
| 7 | + | IconVersion = "\uf02b" // tag | |||
| 8 | + | IconGitBranch = "\ue725" // git branch | |||
| 9 | + | IconCalendar = "\uf073" // calendar | |||
| 10 | + | IconCode = "\uf121" // code | |||
| 11 | + | IconGithub = "\uf09b" // github | |||
| 12 | + | IconHeart = "\uf004" // heart | |||
| 13 | + | IconGo = "\ue627" // go gopher | |||
| 14 | + | IconArrow = "\uf061" // arrow right | |||
| 15 | + | ) | |||
A internal/domain/build/info.go +20 -0
| @@ -0,0 +1,20 @@ | |||
| 1 | + | // Package build provides domain entities for build information. | |
| 2 | + | package build | |
| 3 | + | ||
| 4 | + | // Info holds build-time information injected via ldflags. | |
| 5 | + | type Info struct { | |
| 6 | + | Version string | |
| 7 | + | Commit string | |
| 8 | + | BuildDate string | |
| 9 | + | GoVersion string | |
| 10 | + | } | |
| 11 | + | ||
| 12 | + | // Contributors returns the list of project contributors. | |
| 13 | + | func Contributors() []string { | |
| 14 | + | return []string{"bnema"} | |
| 15 | + | } | |
| 16 | + | ||
| 17 | + | // RepoURL returns the GitHub repository URL. | |
| 18 | + | func RepoURL() string { | |
| 19 | + | return "https://github.com/bnema/dumber" | |
| 20 | + | } | |
| @@ -0,0 +1,20 @@ | |||||
| 1 | + | // Package build provides domain entities for build information. | |||
| 2 | + | package build | |||
| 3 | + | ||||
| 4 | + | // Info holds build-time information injected via ldflags. | |||
| 5 | + | type Info struct { | |||
| 6 | + | Version string | |||
| 7 | + | Commit string | |||
| 8 | + | BuildDate string | |||
| 9 | + | GoVersion string | |||
| 10 | + | } | |||
| 11 | + | ||||
| 12 | + | // Contributors returns the list of project contributors. | |||
| 13 | + | func Contributors() []string { | |||
| 14 | + | return []string{"bnema"} | |||
| 15 | + | } | |||
| 16 | + | ||||
| 17 | + | // RepoURL returns the GitHub repository URL. | |||
| 18 | + | func RepoURL() string { | |||
| 19 | + | return "https://github.com/bnema/dumber" | |||
| 20 | + | } | |||