Compare commits
4 Commits
5e5727f021
..
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 0b7b8802d1 | |||
| b4be492dec | |||
| d25540d727 | |||
| 242e3fde38 |
@@ -0,0 +1,93 @@
|
|||||||
|
# cliprepo
|
||||||
|
|
||||||
|
`cliprepo` is a lightweight, efficient CLI tool written in Go that helps you package your repository's file tree and source code content into a formatted Markdown block. It is designed to quickly build comprehensive context for Large Language Models (LLMs) like GPT, Claude, or DeepSeek.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **File Tree Generation**: Automatically generates a clean ASCII directory tree, honoring your `.gitignore` rules.
|
||||||
|
- **Flexible File Filtering**: Match files using flexible presets (`*`, `cmd/*`, or specific file paths).
|
||||||
|
- **Gitignore Smart Filtering**: Automatically skips files and directories specified in your `.gitignore` (e.g., `.git`, `node_modules`, `.DS_Store`).
|
||||||
|
- **Clipboard Integration**: Directly copies the generated prompt to your clipboard—no manual file saving required.
|
||||||
|
- **Customizable Templates**: Define how your code blocks are presented to the LLM via a YAML configuration file.
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
Ensure you have [Go](https://go.dev/) installed (version 1.26 or higher), then clone the repository and run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x install.sh
|
||||||
|
./install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
This will compile and install the `cliprepo` binary into your `$GOPATH/bin` directory.
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
Create a `.cliprepo.yaml` file in the root of your project to manage path modes, custom prompt templates, and file group presets:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
config:
|
||||||
|
path_mode: relative # Options: 'relative' or 'absolute'
|
||||||
|
|
||||||
|
prompts:
|
||||||
|
preset: "The following code is from file {{path}}:\n---\n{{content}}"
|
||||||
|
|
||||||
|
preset:
|
||||||
|
all:
|
||||||
|
- "*" # Scans and includes all tracked files in the repo
|
||||||
|
|
||||||
|
internal:
|
||||||
|
- "internal/tree/*"
|
||||||
|
- "internal/resolver/resolver.go"
|
||||||
|
|
||||||
|
cmd:
|
||||||
|
- "cmd/*"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Run the tool using the `run` command by specifying a preset key defined in your `.cliprepo.yaml`.
|
||||||
|
|
||||||
|
### Print to Terminal
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cliprepo run --delineate cmd
|
||||||
|
```
|
||||||
|
|
||||||
|
### Copy Directly to Clipboard
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cliprepo run --delineate all --clipboard
|
||||||
|
```
|
||||||
|
|
||||||
|
### Flags
|
||||||
|
|
||||||
|
* `--delineate` (string): The preset key to use from `.cliprepo.yaml` (Required).
|
||||||
|
* `--clipboard` (bool): Copy the output directly to your system clipboard instead of printing it to stdout.
|
||||||
|
|
||||||
|
## Output Example
|
||||||
|
|
||||||
|
When running `cliprepo run --delineate cmd`, the output format will look like this:
|
||||||
|
|
||||||
|
```text
|
||||||
|
.
|
||||||
|
├── cmd
|
||||||
|
│ ├── root.go
|
||||||
|
│ └── run.go
|
||||||
|
└── main.go
|
||||||
|
|
||||||
|
The following code is from file cmd/root.go:
|
||||||
|
---
|
||||||
|
package cmd
|
||||||
|
...
|
||||||
|
|
||||||
|
The following code is from file cmd/run.go:
|
||||||
|
---
|
||||||
|
package cmd
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT License](https://www.google.com/search?q=LICENSE)
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,92 @@
|
|||||||
|
# cliprepo
|
||||||
|
|
||||||
|
`cliprepo` 是一个用 Go 语言编写的轻量、高效的命令行工具(CLI)。它可以将你代码库的目录结构和指定的文件内容一键打包成格式化的 Markdown 文本,专门用于快速为大语言模型(如 GPT、Claude、DeepSeek)构建完整的上下文。
|
||||||
|
|
||||||
|
## 功能特性
|
||||||
|
|
||||||
|
- **目录树生成**:自动生成清晰的 ASCII 目录树,并且会自动遵循 `.gitignore` 的过滤规则。
|
||||||
|
- **灵活的文件过滤**:支持通过预设组合(Preset)匹配文件(如 `*`、`cmd/*` 或具体文件路径)。
|
||||||
|
- **智能 Gitignore 过滤**:自动跳过 `.gitignore` 中指定的文件和文件夹(例如 `.git`、`node_modules`、`.DS_Store`)。
|
||||||
|
- **剪贴板集成**:一键将生成的 Prompt 复制到系统剪贴板,省去手动复制或保存文件的烦恼。
|
||||||
|
- **自定义模板**:支持通过 YAML 配置文件自定义代码块向 LLM 展示的模板。
|
||||||
|
|
||||||
|
## 安装指南
|
||||||
|
|
||||||
|
请确保你已经安装了 [Go](https://go.dev/)(版本 1.26 或更高),然后克隆本仓库并执行:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
chmod +x install.sh
|
||||||
|
./install.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
这将会把编译好的 `cliprepo` 二进制文件安装到你的 `$GOPATH/bin` 目录下。
|
||||||
|
|
||||||
|
## 配置文件
|
||||||
|
|
||||||
|
在项目根目录下创建一个 `.cliprepo.yaml` 文件,用于管理路径模式、自定义提示词模板和文件组预设:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
config:
|
||||||
|
path_mode: relative # 可选值: 'relative' (相对路径) 或 'absolute' (绝对路径)
|
||||||
|
|
||||||
|
prompts:
|
||||||
|
preset: "下面的代码来自文件 {{path}}:\n---\n{{content}}"
|
||||||
|
|
||||||
|
preset:
|
||||||
|
all:
|
||||||
|
- "*" # 扫描并包含库中所有未被 ignore 的文件
|
||||||
|
|
||||||
|
internal:
|
||||||
|
- "internal/tree/*"
|
||||||
|
- "internal/resolver/resolver.go"
|
||||||
|
|
||||||
|
cmd:
|
||||||
|
- "cmd/*"
|
||||||
|
```
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
通过 `run` 命令并指定 `.cliprepo.yaml` 中配置的预设(preset)键名来运行该工具。
|
||||||
|
|
||||||
|
### 输出到终端屏幕
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cliprepo run --delineate cmd
|
||||||
|
```
|
||||||
|
|
||||||
|
### 直接复制到剪贴板
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cliprepo run --delineate all --clipboard
|
||||||
|
```
|
||||||
|
|
||||||
|
### 命令行参数(Flags)
|
||||||
|
|
||||||
|
* `--delineate` (string): 指定要使用的 `.cliprepo.yaml` 中的预设键名(必填)。
|
||||||
|
* `--clipboard` (bool): 将生成的结果直接复制到系统剪贴板,不再在终端打印。
|
||||||
|
|
||||||
|
## 输出示例
|
||||||
|
|
||||||
|
当你运行 `cliprepo run --delineate cmd` 时,输出的内容格式如下:
|
||||||
|
|
||||||
|
```text
|
||||||
|
.
|
||||||
|
├── cmd
|
||||||
|
│ ├── root.go
|
||||||
|
│ └── run.go
|
||||||
|
└── main.go
|
||||||
|
|
||||||
|
下面的代码来自文件 cmd/root.go:
|
||||||
|
---
|
||||||
|
package cmd
|
||||||
|
...
|
||||||
|
|
||||||
|
下面的代码来自文件 cmd/run.go:
|
||||||
|
---
|
||||||
|
package cmd
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
## 开源协议
|
||||||
|
|
||||||
|
[MIT License](https://www.google.com/search?q=LICENSE)
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/atotto/clipboard"
|
|
||||||
)
|
|
||||||
|
|
||||||
func copyToClipboard(content string) error {
|
|
||||||
return clipboard.WriteAll(content)
|
|
||||||
}
|
|
||||||
-11
@@ -29,7 +29,6 @@ var runCmd = &cobra.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1. tree
|
|
||||||
treeStr, err := tree.Generate(".")
|
treeStr, err := tree.Generate(".")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -39,7 +38,6 @@ var runCmd = &cobra.Command{
|
|||||||
builder.WriteString(treeStr)
|
builder.WriteString(treeStr)
|
||||||
builder.WriteString("\n\n")
|
builder.WriteString("\n\n")
|
||||||
|
|
||||||
// 2. resolver (GLOBAL FILE REGISTRY)
|
|
||||||
r := resolver.New(".")
|
r := resolver.New(".")
|
||||||
|
|
||||||
raw, ok := cfg.Preset[delineate]
|
raw, ok := cfg.Preset[delineate]
|
||||||
@@ -51,7 +49,6 @@ var runCmd = &cobra.Command{
|
|||||||
var files []string
|
var files []string
|
||||||
|
|
||||||
for _, pattern := range patterns {
|
for _, pattern := range patterns {
|
||||||
// 统一交给 resolver 处理,无论是 "*", "cmd/*" 还是 "**/*.go"
|
|
||||||
matches, err := r.ResolvePattern(pattern)
|
matches, err := r.ResolvePattern(pattern)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -59,17 +56,9 @@ var runCmd = &cobra.Command{
|
|||||||
files = append(files, matches...)
|
files = append(files, matches...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 3. dedup + stable order
|
|
||||||
files = r.Unique(files)
|
files = r.Unique(files)
|
||||||
sort.Strings(files)
|
sort.Strings(files)
|
||||||
|
|
||||||
// 4. template
|
|
||||||
template := cfg.Prompts.Preset
|
|
||||||
if template == "" {
|
|
||||||
template = "The following code is from file {{path}}:\n---\n{{content}}"
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. render
|
|
||||||
for _, file := range files {
|
for _, file := range files {
|
||||||
content, err := os.ReadFile(file)
|
content, err := os.ReadFile(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -1,27 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ExpandPaths(patterns []string) ([]string, error) {
|
|
||||||
var result []string
|
|
||||||
|
|
||||||
for _, pattern := range patterns {
|
|
||||||
matches, err := filepath.Glob(pattern)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, m := range matches {
|
|
||||||
info, err := os.Stat(m)
|
|
||||||
if err != nil || info.IsDir() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
result = append(result, m)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
// "strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ExpandGlob(patterns []string) ([]string, error) {
|
|
||||||
var result []string
|
|
||||||
|
|
||||||
for _, pattern := range patterns {
|
|
||||||
|
|
||||||
if pattern == "*" {
|
|
||||||
files, err := filepath.Glob("**") // fallback
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
result = append(result, files...)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
matches, err := filepath.Glob(pattern)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, m := range matches {
|
|
||||||
info, err := os.Stat(m)
|
|
||||||
if err != nil || info.IsDir() {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
result = append(result, m)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func add(path string, seen map[string]struct{}, result *[]string) {
|
|
||||||
if _, ok := seen[path]; ok {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
seen[path] = struct{}{}
|
|
||||||
*result = append(*result, path)
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user