first commit
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"cliprepo/internal/bundle"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var bundleClipboard bool
|
||||
|
||||
var bundleCmd = &cobra.Command{
|
||||
Use: "bundle [key]",
|
||||
Short: "Bundle files by key from config",
|
||||
Args: cobra.ExactArgs(1),
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
key := args[0]
|
||||
|
||||
result, err := bundle.Build(key)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if bundleClipboard {
|
||||
return bundle.Copy(result)
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(bundleCmd)
|
||||
bundleCmd.Flags().BoolVar(&bundleClipboard, "clipboard", false, "Copy to clipboard")
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "cliprepo",
|
||||
Short: "Extract repo structure and bundle code for LLMs",
|
||||
}
|
||||
|
||||
func Execute() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"cliprepo/internal/tree"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var treeOutput string
|
||||
var treeClipboard bool
|
||||
|
||||
var treeCmd = &cobra.Command{
|
||||
Use: "tree",
|
||||
Short: "Print repo tree respecting .gitignore",
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
result, err := tree.Generate(".")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if treeClipboard {
|
||||
return tree.Copy(result)
|
||||
}
|
||||
|
||||
if treeOutput != "" {
|
||||
return tree.Write(treeOutput, result)
|
||||
}
|
||||
|
||||
fmt.Println(result)
|
||||
return nil
|
||||
},
|
||||
}
|
||||
|
||||
func init() {
|
||||
rootCmd.AddCommand(treeCmd)
|
||||
|
||||
treeCmd.Flags().StringVarP(&treeOutput, "output", "o", "", "Output file")
|
||||
treeCmd.Flags().BoolVar(&treeClipboard, "clipboard", false, "Copy to clipboard")
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
module cliprepo
|
||||
|
||||
go 1.26.3
|
||||
|
||||
require (
|
||||
github.com/atotto/clipboard v0.1.4
|
||||
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06
|
||||
github.com/spf13/cobra v1.10.2
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/spf13/pflag v1.0.9 // indirect
|
||||
)
|
||||
@@ -0,0 +1,25 @@
|
||||
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
|
||||
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 h1:OkMGxebDjyw0ULyrTYWeN0UNCCkmCWfjPnIA2W6oviI=
|
||||
github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06/go.mod h1:+ePHsJ1keEjQtpvf9HHw0f4ZeJ0TLRsxhunSI2hYJSs=
|
||||
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
|
||||
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
|
||||
github.com/spf13/pflag v1.0.9 h1:9exaQaMOCwffKiiiYk6/BndUBv+iRViNW+4lEMi0PvY=
|
||||
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
@@ -0,0 +1,52 @@
|
||||
package bundle
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"cliprepo/internal/config"
|
||||
"github.com/atotto/clipboard"
|
||||
)
|
||||
|
||||
const maxFileSize = 1 * 1024 * 1024 // 1MB
|
||||
|
||||
func Build(key string) (string, error) {
|
||||
cfg, err := config.Load()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
files, ok := cfg.Bundles[key]
|
||||
if !ok {
|
||||
return "", fmt.Errorf("bundle not found: %s", key)
|
||||
}
|
||||
|
||||
var builder strings.Builder
|
||||
|
||||
for _, file := range files {
|
||||
info, err := os.Stat(file)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
if info.Size() > maxFileSize {
|
||||
continue
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(file)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
|
||||
builder.WriteString(fmt.Sprintf("===== %s =====\n", file))
|
||||
builder.Write(data)
|
||||
builder.WriteString("\n\n")
|
||||
}
|
||||
|
||||
return builder.String(), nil
|
||||
}
|
||||
|
||||
func Copy(content string) error {
|
||||
return clipboard.WriteAll(content)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
Bundles map[string][]string `yaml:"bundles"`
|
||||
}
|
||||
|
||||
func Load() (*Config, error) {
|
||||
data, err := os.ReadFile("cliprepo.yaml")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var cfg Config
|
||||
err = yaml.Unmarshal(data, &cfg)
|
||||
return &cfg, err
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package gitignore
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
ignore "github.com/sabhiram/go-gitignore"
|
||||
)
|
||||
|
||||
func Load(root string) (*ignore.GitIgnore, error) {
|
||||
path := filepath.Join(root, ".gitignore")
|
||||
|
||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||
return ignore.CompileIgnoreLines(), nil
|
||||
}
|
||||
|
||||
return ignore.CompileIgnoreFile(path)
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
package tree
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"cliprepo/internal/gitignore"
|
||||
"github.com/atotto/clipboard"
|
||||
)
|
||||
|
||||
func Generate(root string) (string, error) {
|
||||
ig, _ := gitignore.Load(root)
|
||||
|
||||
var builder strings.Builder
|
||||
|
||||
err := filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if path == root {
|
||||
builder.WriteString(".\n")
|
||||
return nil
|
||||
}
|
||||
|
||||
rel, _ := filepath.Rel(root, path)
|
||||
|
||||
if ig.MatchesPath(rel) {
|
||||
if info.IsDir() {
|
||||
return filepath.SkipDir
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
level := strings.Count(rel, string(os.PathSeparator))
|
||||
prefix := strings.Repeat("│ ", level)
|
||||
|
||||
builder.WriteString(fmt.Sprintf("%s├── %s\n", prefix, info.Name()))
|
||||
return nil
|
||||
})
|
||||
|
||||
return builder.String(), err
|
||||
}
|
||||
|
||||
func Copy(content string) error {
|
||||
return clipboard.WriteAll(content)
|
||||
}
|
||||
|
||||
func Write(path, content string) error {
|
||||
return os.WriteFile(path, []byte(content), 0644)
|
||||
}
|
||||
Reference in New Issue
Block a user