diff options
| author | Paul Buetow <paul@buetow.org> | 2025-10-31 20:13:32 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2025-10-31 20:13:32 +0200 |
| commit | 11eea6a82cbfdde40ec1457c6ea080da4da6b7dc (patch) | |
| tree | 8026068f6a3beb3ee02c45f06f4487f4b89caaf1 /internal/cmd | |
| parent | 5c3e0b5cf99d028c4f06be7a825388b296e37a22 (diff) | |
feat: implement amp AI tool support and replace Taskfile with Magev0.10.0
- Add amp as default AI tool for release notes and showcase generation
- Fallback chain: amp → hexai → claude → aichat
- Replace Taskfile.yaml with magefile.go for build automation
- Update all documentation (README.md, AGENTS.md, doc/development.md)
- Update version to 0.10.0
Amp-Thread-ID: https://ampcode.com/threads/T-735ba1e2-0255-4b43-8ed1-6c0d2f78301b
Co-authored-by: Amp <amp@ampcode.com>
Diffstat (limited to 'internal/cmd')
| -rw-r--r-- | internal/cmd/list.go | 4 | ||||
| -rw-r--r-- | internal/cmd/manage.go | 30 | ||||
| -rw-r--r-- | internal/cmd/release.go | 26 | ||||
| -rw-r--r-- | internal/cmd/root.go | 21 | ||||
| -rw-r--r-- | internal/cmd/showcase.go | 65 | ||||
| -rw-r--r-- | internal/cmd/sync.go | 58 | ||||
| -rw-r--r-- | internal/cmd/test.go | 12 |
7 files changed, 107 insertions, 109 deletions
diff --git a/internal/cmd/list.go b/internal/cmd/list.go index 90d0eb8..31a39f5 100644 --- a/internal/cmd/list.go +++ b/internal/cmd/list.go @@ -3,8 +3,8 @@ package cmd import ( "os" - "github.com/spf13/cobra" "codeberg.org/snonux/gitsyncer/internal/cli" + "github.com/spf13/cobra" ) var listCmd = &cobra.Command{ @@ -37,4 +37,4 @@ func init() { rootCmd.AddCommand(listCmd) listCmd.AddCommand(listOrgsCmd) listCmd.AddCommand(listReposCmd) -}
\ No newline at end of file +} diff --git a/internal/cmd/manage.go b/internal/cmd/manage.go index 437bd96..6e2ffee 100644 --- a/internal/cmd/manage.go +++ b/internal/cmd/manage.go @@ -5,9 +5,9 @@ import ( "os" "path/filepath" - "github.com/spf13/cobra" "codeberg.org/snonux/gitsyncer/internal/cli" "codeberg.org/snonux/gitsyncer/internal/state" + "github.com/spf13/cobra" ) var force bool @@ -43,7 +43,7 @@ var cleanCmd = &cobra.Command{ flags := buildFlags() flags.Clean = true flags.Force = force - + // TODO: Implement clean handler fmt.Println("Clean command not yet implemented") os.Exit(1) @@ -64,7 +64,7 @@ This is designed for automated weekly synchronization from cron jobs or shell sc flags := buildFlags() flags.BatchRun = true flags.Force = force - + // Check state unless forced if !force { stateManager := state.NewManager(workDir) @@ -72,23 +72,23 @@ This is designed for automated weekly synchronization from cron jobs or shell sc if err != nil { fmt.Fprintf(os.Stderr, "Warning: Failed to load state: %v\n", err) } - + if s.HasRunWithinWeek() { - fmt.Printf("Batch run was already executed within the past week (last run: %s).\n", + fmt.Printf("Batch run was already executed within the past week (last run: %s).\n", s.LastBatchRun.Format("2006-01-02 15:04:05")) stateFile := filepath.Join(workDir, ".gitsyncer-state.json") fmt.Printf("State file location: %s\n", stateFile) fmt.Println("Skipping batch run. Use --force to override.") os.Exit(0) } - + // Store state manager for later flags.BatchRunStateManager = stateManager flags.BatchRunState = s } - + fmt.Println("Starting weekly batch run (full sync + showcase)...") - + // Enable full sync and showcase flags.FullSync = true flags.Showcase = true @@ -96,24 +96,24 @@ This is designed for automated weekly synchronization from cron jobs or shell sc flags.SyncGitHubPublic = true flags.CreateGitHubRepos = true flags.CreateCodebergRepos = true - + // Run sync operations exitCode := cli.HandleSyncCodebergPublic(cfg, flags) if exitCode != 0 { os.Exit(exitCode) } - + exitCode = cli.HandleSyncGitHubPublic(cfg, flags) if exitCode != 0 { os.Exit(exitCode) } - + // Run showcase showcaseCode := cli.HandleShowcase(cfg, flags) if showcaseCode != 0 { os.Exit(showcaseCode) } - + // Save batch run state if flags.BatchRunStateManager != nil && flags.BatchRunState != nil { flags.BatchRunState.UpdateBatchRunTime() @@ -125,7 +125,7 @@ This is designed for automated weekly synchronization from cron jobs or shell sc fmt.Println("Next batch run allowed after one week.") } } - + os.Exit(0) }, } @@ -135,8 +135,8 @@ func init() { manageCmd.AddCommand(deleteRepoCmd) manageCmd.AddCommand(cleanCmd) manageCmd.AddCommand(batchRunCmd) - + // Manage-specific flags cleanCmd.Flags().BoolVarP(&force, "force", "f", false, "force operation without confirmation") batchRunCmd.Flags().BoolVarP(&force, "force", "f", false, "force run even if already run this week") -}
\ No newline at end of file +} diff --git a/internal/cmd/release.go b/internal/cmd/release.go index 9f4e713..656f4a6 100644 --- a/internal/cmd/release.go +++ b/internal/cmd/release.go @@ -3,8 +3,8 @@ package cmd import ( "os" - "github.com/spf13/cobra" "codeberg.org/snonux/gitsyncer/internal/cli" + "github.com/spf13/cobra" ) var ( @@ -16,11 +16,11 @@ var ( ) var releaseCmd = &cobra.Command{ - Use: "release", - Short: "Manage releases across platforms", - Long: `Check for version tags without releases and create them across -GitHub and Codeberg. Supports AI-generated release notes via hexai (stdin pipeline), -with fallback to Claude or aichat.`, + Use: "release", + Short: "Manage releases across platforms", + Long: `Check for version tags without releases and create them across +GitHub and Codeberg. Supports AI-generated release notes via amp (stdin pipeline), +with fallback to hexai, Claude, or aichat.`, } var releaseCheckCmd = &cobra.Command{ @@ -40,7 +40,7 @@ If no repository is specified, checks all configured repositories.`, Run: func(cmd *cobra.Command, args []string) { flags := buildFlags() flags.CheckReleases = true - + if len(args) > 0 { // Check specific repo exitCode := cli.HandleCheckReleasesForRepo(cfg, flags, args[0]) @@ -74,8 +74,8 @@ If no repository is specified, processes all configured repositories.`, # Create for specific repository without AI gitsyncer release create myproject --no-ai-notes - # Use aichat instead of claude for AI release notes - gitsyncer release create --ai-tool aichat`, + # Use amp for AI release notes +gitsyncer release create --ai-tool amp`, Run: func(cmd *cobra.Command, args []string) { flags := buildFlags() flags.CheckReleases = true @@ -83,7 +83,7 @@ If no repository is specified, processes all configured repositories.`, flags.AIReleaseNotes = !noAINotes flags.UpdateReleases = updateExisting flags.AITool = aiTool - + if len(args) > 0 { // Create releases for specific repo exitCode := cli.HandleCheckReleasesForRepo(cfg, flags, args[0]) @@ -100,14 +100,14 @@ func init() { rootCmd.AddCommand(releaseCmd) releaseCmd.AddCommand(releaseCheckCmd) releaseCmd.AddCommand(releaseCreateCmd) - + // Release flags releaseCmd.PersistentFlags().BoolVar(&dryRun, "dry-run", false, "preview what releases would be created") - + // Create-specific flags releaseCreateCmd.Flags().BoolVar(&autoRelease, "auto", false, "skip confirmation prompts") releaseCreateCmd.Flags().BoolVar(&noAINotes, "no-ai-notes", false, "disable AI-generated release notes (AI notes are enabled by default)") releaseCreateCmd.Flags().BoolVar(&updateExisting, "update-existing", false, "update existing releases with new AI-generated notes") releaseCreateCmd.Flags().StringVar(&templatePath, "template", "", "custom template for release notes") - releaseCreateCmd.Flags().StringVar(&aiTool, "ai-tool", "claude", "AI tool to use for release notes (claude or aichat; hexai is tried first if available)") + releaseCreateCmd.Flags().StringVar(&aiTool, "ai-tool", "amp", "AI tool to use for release notes (amp, claude, aichat, or hexai; amp is tried first if available)") } diff --git a/internal/cmd/root.go b/internal/cmd/root.go index bf4f64a..caf89f1 100644 --- a/internal/cmd/root.go +++ b/internal/cmd/root.go @@ -5,15 +5,15 @@ import ( "os" "path/filepath" - "github.com/spf13/cobra" "codeberg.org/snonux/gitsyncer/internal/config" "codeberg.org/snonux/gitsyncer/internal/version" + "github.com/spf13/cobra" ) var ( - cfgFile string - workDir string - cfg *config.Config + cfgFile string + workDir string + cfg *config.Config rootCmd = &cobra.Command{ Use: "gitsyncer", Short: "Synchronize git repositories across multiple platforms", @@ -25,7 +25,7 @@ keeps all branches in sync across different git hosting platforms.`, if cmd.Use == "version" { return } - + // Load configuration var err error cfg, err = config.Load(cfgFile) @@ -35,7 +35,7 @@ keeps all branches in sync across different git hosting platforms.`, fmt.Fprintf(os.Stderr, "See 'gitsyncer help' for more information.\n") os.Exit(1) } - + // Use config WorkDir if no flag was explicitly provided if !cmd.Flags().Changed("work-dir") && cfg.WorkDir != "" { workDir = cfg.WorkDir @@ -54,16 +54,16 @@ func Execute() { func init() { // Global flags rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "configuration file (default: ~/.config/gitsyncer/config.json)") - + // Set default work directory home, err := os.UserHomeDir() defaultWorkDir := ".gitsyncer-work" if err == nil { defaultWorkDir = filepath.Join(home, "git", "gitsyncer-workdir") } - + rootCmd.PersistentFlags().StringVarP(&workDir, "work-dir", "w", defaultWorkDir, "working directory for operations") - + // Version command rootCmd.AddCommand(&cobra.Command{ Use: "version", @@ -72,6 +72,5 @@ func init() { fmt.Println(version.GetVersion()) }, }) - -} +} diff --git a/internal/cmd/showcase.go b/internal/cmd/showcase.go index 6f9f984..a590756 100644 --- a/internal/cmd/showcase.go +++ b/internal/cmd/showcase.go @@ -4,26 +4,25 @@ import ( "fmt" "os" - "github.com/spf13/cobra" "codeberg.org/snonux/gitsyncer/internal/cli" + "github.com/spf13/cobra" ) var ( - forceRegenerate bool - outputPath string - outputFormat string - excludePattern string - showcaseAITool string - showcaseRepo string + forceRegenerate bool + outputPath string + outputFormat string + excludePattern string + showcaseAITool string + showcaseRepo string ) var showcaseCmd = &cobra.Command{ Use: "showcase", Short: "Generate AI-powered project showcase", - Long: `Generate a comprehensive showcase of all your projects using AI. + Long: `Generate a comprehensive showcase of all your projects using AI. This feature creates a formatted document with project summaries, statistics, -and code snippets. By default uses Claude, but will try hexai first if available, -and can also use aichat.`, +and code snippets. By default uses amp, with fallback to hexai, claude, and aichat.`, Example: ` # Generate showcase with cached summaries gitsyncer showcase @@ -40,30 +39,30 @@ and can also use aichat.`, gitsyncer showcase --exclude "test-.*" # Use a specific AI tool - gitsyncer showcase --ai-tool hexai`, - Run: func(cmd *cobra.Command, args []string) { - flags := buildFlags() - flags.Showcase = true - flags.Force = forceRegenerate - flags.AITool = showcaseAITool - if showcaseRepo != "" { - flags.SyncRepo = showcaseRepo - } - - fmt.Println("Running showcase generation for all repositories...") - exitCode := cli.HandleShowcaseOnly(cfg, flags) - os.Exit(exitCode) - }, + gitsyncer showcase --ai-tool amp`, + Run: func(cmd *cobra.Command, args []string) { + flags := buildFlags() + flags.Showcase = true + flags.Force = forceRegenerate + flags.AITool = showcaseAITool + if showcaseRepo != "" { + flags.SyncRepo = showcaseRepo + } + + fmt.Println("Running showcase generation for all repositories...") + exitCode := cli.HandleShowcaseOnly(cfg, flags) + os.Exit(exitCode) + }, } func init() { - rootCmd.AddCommand(showcaseCmd) - - // Showcase flags - showcaseCmd.Flags().BoolVarP(&forceRegenerate, "force", "f", false, "force regeneration of cached summaries") - showcaseCmd.Flags().StringVarP(&outputPath, "output", "o", "", "custom output path (default: ~/git/foo.zone-content/gemtext/about/showcase.gmi.tpl)") - showcaseCmd.Flags().StringVar(&outputFormat, "format", "gemtext", "output format: gemtext, markdown, html") - showcaseCmd.Flags().StringVar(&excludePattern, "exclude", "", "exclude repos matching pattern") - showcaseCmd.Flags().StringVar(&showcaseAITool, "ai-tool", "claude", "AI tool for summaries: hexai, claude, claude-code, or aichat (default tries hexai→claude→aichat)") - showcaseCmd.Flags().StringVar(&showcaseRepo, "repo", "", "only generate showcase for a single repository") + rootCmd.AddCommand(showcaseCmd) + + // Showcase flags + showcaseCmd.Flags().BoolVarP(&forceRegenerate, "force", "f", false, "force regeneration of cached summaries") + showcaseCmd.Flags().StringVarP(&outputPath, "output", "o", "", "custom output path (default: ~/git/foo.zone-content/gemtext/about/showcase.gmi.tpl)") + showcaseCmd.Flags().StringVar(&outputFormat, "format", "gemtext", "output format: gemtext, markdown, html") + showcaseCmd.Flags().StringVar(&excludePattern, "exclude", "", "exclude repos matching pattern") + showcaseCmd.Flags().StringVar(&showcaseAITool, "ai-tool", "amp", "AI tool for summaries: amp, hexai, claude, claude-code, or aichat (default tries amp→hexai→claude→aichat)") + showcaseCmd.Flags().StringVar(&showcaseRepo, "repo", "", "only generate showcase for a single repository") } diff --git a/internal/cmd/sync.go b/internal/cmd/sync.go index 86505d5..a28f50d 100644 --- a/internal/cmd/sync.go +++ b/internal/cmd/sync.go @@ -3,18 +3,18 @@ package cmd import ( "os" - "github.com/spf13/cobra" "codeberg.org/snonux/gitsyncer/internal/cli" + "github.com/spf13/cobra" ) var ( - dryRun bool - backup bool - createRepos bool - noReleases bool - autoCreate bool + dryRun bool + backup bool + createRepos bool + noReleases bool + autoCreate bool noAIReleaseNotes bool - syncAITool string + syncAITool string ) var syncCmd = &cobra.Command{ @@ -42,12 +42,12 @@ var syncRepoCmd = &cobra.Command{ # Sync without AI-generated release notes gitsyncer sync repo myproject --no-ai-release-notes - # Auto-create releases using aichat for AI notes - gitsyncer sync repo myproject --auto-create-releases --ai-tool aichat`, + # Auto-create releases using amp for AI notes +gitsyncer sync repo myproject --auto-create-releases --ai-tool amp`, Run: func(cmd *cobra.Command, args []string) { flags := buildFlags() flags.SyncRepo = args[0] - + exitCode := cli.HandleSync(cfg, flags) if exitCode == 0 && !noReleases { cli.HandleCheckReleasesForRepo(cfg, flags, args[0]) @@ -71,7 +71,7 @@ var syncAllCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { flags := buildFlags() flags.SyncAll = true - + exitCode := cli.HandleSyncAll(cfg, flags) if exitCode == 0 && !noReleases { cli.HandleCheckReleases(cfg, flags) @@ -95,11 +95,11 @@ var syncCodebergToGitHubCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { flags := buildFlags() flags.SyncCodebergPublic = true - + if createRepos || autoCreate { flags.CreateGitHubRepos = true } - + exitCode := cli.HandleSyncCodebergPublic(cfg, flags) if exitCode == 0 && !noReleases { cli.HandleCheckReleases(cfg, flags) @@ -123,11 +123,11 @@ var syncGitHubToCodebergCmd = &cobra.Command{ Run: func(cmd *cobra.Command, args []string) { flags := buildFlags() flags.SyncGitHubPublic = true - + if createRepos || autoCreate { flags.CreateCodebergRepos = true } - + exitCode := cli.HandleSyncGitHubPublic(cfg, flags) if exitCode == 0 && !noReleases { cli.HandleCheckReleases(cfg, flags) @@ -156,13 +156,13 @@ repositories between GitHub and Codeberg. This is equivalent to the old --full f flags.SyncGitHubPublic = true flags.CreateGitHubRepos = true flags.CreateCodebergRepos = true - + // First sync Codeberg to GitHub exitCode := cli.HandleSyncCodebergPublic(cfg, flags) if exitCode != 0 { os.Exit(exitCode) } - + // Then sync GitHub to Codeberg exitCode = cli.HandleSyncGitHubPublic(cfg, flags) if exitCode == 0 && !noReleases { @@ -174,14 +174,14 @@ repositories between GitHub and Codeberg. This is equivalent to the old --full f func init() { rootCmd.AddCommand(syncCmd) - + // Add subcommands syncCmd.AddCommand(syncRepoCmd) syncCmd.AddCommand(syncAllCmd) syncCmd.AddCommand(syncCodebergToGitHubCmd) syncCmd.AddCommand(syncGitHubToCodebergCmd) syncCmd.AddCommand(syncBidirectionalCmd) - + // Sync flags (available for all sync subcommands) syncCmd.PersistentFlags().BoolVar(&dryRun, "dry-run", false, "preview what would be synced") syncCmd.PersistentFlags().BoolVar(&backup, "backup", false, "include backup locations") @@ -189,20 +189,20 @@ func init() { syncCmd.PersistentFlags().BoolVar(&noReleases, "no-releases", false, "skip release checking after sync") syncCmd.PersistentFlags().BoolVar(&autoCreate, "auto-create-releases", false, "automatically create releases without confirmation") syncCmd.PersistentFlags().BoolVar(&noAIReleaseNotes, "no-ai-release-notes", false, "disable AI-generated release notes (AI notes are enabled by default)") - syncCmd.PersistentFlags().StringVar(&syncAITool, "ai-tool", "claude", "AI tool to use for release notes when auto-creating (claude or aichat; hexai is tried first if available)") + syncCmd.PersistentFlags().StringVar(&syncAITool, "ai-tool", "amp", "AI tool to use for release notes when auto-creating (amp, claude, aichat, or hexai; amp is tried first if available)") } func buildFlags() *cli.Flags { return &cli.Flags{ - ConfigPath: cfgFile, - WorkDir: workDir, - DryRun: dryRun, - Backup: backup, - NoCheckReleases: noReleases, - AutoCreateReleases: autoCreate, - AIReleaseNotes: !noAIReleaseNotes, - AITool: syncAITool, - CreateGitHubRepos: createRepos, + ConfigPath: cfgFile, + WorkDir: workDir, + DryRun: dryRun, + Backup: backup, + NoCheckReleases: noReleases, + AutoCreateReleases: autoCreate, + AIReleaseNotes: !noAIReleaseNotes, + AITool: syncAITool, + CreateGitHubRepos: createRepos, CreateCodebergRepos: createRepos, } } diff --git a/internal/cmd/test.go b/internal/cmd/test.go index 2c50112..ebee3db 100644 --- a/internal/cmd/test.go +++ b/internal/cmd/test.go @@ -4,9 +4,9 @@ import ( "fmt" "os" - "github.com/spf13/cobra" "codeberg.org/snonux/gitsyncer/internal/cli" "codeberg.org/snonux/gitsyncer/internal/config" + "github.com/spf13/cobra" ) var testCmd = &cobra.Command{ @@ -52,11 +52,11 @@ var testConfigCmd = &cobra.Command{ fmt.Fprintf(os.Stderr, "Configuration validation failed: %v\n", err) os.Exit(1) } - + fmt.Println("Configuration validation successful!") fmt.Printf(" Organizations: %d\n", len(cfg.Organizations)) fmt.Printf(" Repositories: %d\n", len(cfg.Repositories)) - + // Check for common issues hasGitHub := false hasCodeberg := false @@ -74,11 +74,11 @@ var testConfigCmd = &cobra.Command{ } } } - + if !hasGitHub && !hasCodeberg { fmt.Println(" ⚠️ Warning: No GitHub or Codeberg organizations configured") } - + os.Exit(0) }, } @@ -88,4 +88,4 @@ func init() { testCmd.AddCommand(testGitHubCmd) testCmd.AddCommand(testCodebergCmd) testCmd.AddCommand(testConfigCmd) -}
\ No newline at end of file +} |
