Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 84 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@
python promptpack.py
```


## Project Structure

The source code is organized in the `promptpack` package:

- `gui.py` contains the graphical interface.
- `settings.py` manages the application settings.
- `utils.py` includes supporting functions.
Expand All @@ -55,7 +55,7 @@ The file `promptpack.py` simply launches the application.

## How to Use

1. **Start Folder**: Click *Browse* to select the folder containing the files you want to include.
1. **Start Folder**: Click _Browse_ to select the folder containing the files you want to include.
2. **Select Files**: Opens an expandable tree of all folders and files. You can include/exclude each item via checkboxes.
- Default selections are based on the current settings.
3. **Settings**: Define default allowed extensions, excluded folders and files. Also choose:
Expand All @@ -76,10 +76,10 @@ User preferences are saved in a file named `promptpack_settings.json` in the sam
{
"allowed_exts": [".php", ".js", ".ts", ".html", ".css", ".py"],
"excluded_dirs": ["vendor", ".git", "node_modules"],
"excluded_files": [".env", "README.md"],
"export_format": "md",
"tree_only": false,
"include_heading": true,
"excluded_files": [".env", "README.md"],
"export_format": "md",
"tree_only": false,
"include_heading": true,
"use_code_block": true,
"max_tokens": 200000,
"last_start_folder": "",
Expand Down Expand Up @@ -109,6 +109,84 @@ body {
```
````

````markdown
## Command Line Usage (CLI)

In addition to the graphical interface, **PromptPack** can be used from the command line to automate file exports. The CLI module is separate from the GUI and is executed using:

```bash
python -m promptpack.cli <source_folder> <destination_folder> [options]
```
````

### Examples

```bash
# Export source files to Markdown with progress display
python -m promptpack.cli ./src ./out --format md --progress

# Export only the folder structure as JSON
python -m promptpack.cli ./project ./out --tree-only --format json

# Exclude headings and code blocks from the output
python -m promptpack.cli ./input ./out --no-heading --no-code-block
```

### Available Options

| Option | Description |
| ----------------- | ------------------------------------------------------------------- |
| `source` | Source folder to analyze |
| `dest` | Destination folder for the generated output |
| `--format` | Export format: `txt`, `md`, `json` |
| `--tree-only` | Export only the folder structure, without file contents |
| `--no-heading` | Do not include headings for each file |
| `--no-code-block` | Do not wrap contents in code blocks (Markdown only) |
| `--max-tokens N` | Maximum number of tokens allowed (default: 200000 or from settings) |
| `--progress` | Show a progress bar during file processing |

### Notes

- Absolute paths are supported (including on Windows).
- The destination folder is automatically created if it does not exist.
- Outputs are split into multiple parts if the token limit is exceeded.
- CLI settings override the defaults from `promptpack_settings.json`.
- Useful for scripting, automation, and batch workflows.

### Integration Tip

If you use PromptPack frequently, you can add an alias for convenience:

**PowerShell (Windows):**

```powershell
Set-Alias promptpackcli "python -m promptpack.cli"
```

**Bash (Linux/macOS):**

```bash
alias promptpackcli='python -m promptpack.cli'
```

You can then run:

```bash
promptpackcli ./src ./out --format md --progress
```

Alternatively, use `pyinstaller` to generate a portable `.exe`:

```bash
pyinstaller --onefile promptpackcli.py
```

This creates `promptpackcli.exe` in the `dist/` folder, usable from any terminal without needing Python installed.

```

```

## Notes

- Only files with allowed extensions are included by default.
Expand Down
4 changes: 2 additions & 2 deletions promptpack/__init__.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
from .gui import PromptPackApp
from .settings import load_settings, save_settings
from .utils import generate_output
from .cli import main as cli_main

__all__ = [
"PromptPackApp",
"load_settings",
"save_settings",
"generate_output",
"cli_main",
]

2 changes: 1 addition & 1 deletion promptpack/__main__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import tkinter as tk

from promptpack import PromptPackApp
from .gui import PromptPackApp


def main():
Expand Down
76 changes: 76 additions & 0 deletions promptpack/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import argparse
from pathlib import Path
from .settings import load_settings
from .utils import generate_output
from pathspec import PathSpec


def collect_files(start_folder: str, settings) -> list[Path]:
folder = Path(start_folder)
gitignore = folder / ".gitignore"
spec = None
if gitignore.exists():
with gitignore.open("r", encoding="utf-8") as f:
spec = PathSpec.from_lines("gitwildmatch", f)
files = [
p
for p in folder.rglob("*")
if p.is_file()
and p.suffix in settings["allowed_exts"]
and p.name not in settings["excluded_files"]
and not any(excl in p.parts for excl in settings["excluded_dirs"])
and not (spec and spec.match_file(str(p.relative_to(folder))))
]
return files


def main():
parser = argparse.ArgumentParser(description="PromptPack CLI")
parser.add_argument("source", help="cartella sorgente")
parser.add_argument("dest", help="cartella di destinazione")
parser.add_argument("--format", choices=["txt", "md", "json"], dest="format")
parser.add_argument("--tree-only", action="store_true")
parser.add_argument("--no-heading", action="store_true")
parser.add_argument("--no-code-block", action="store_true")
parser.add_argument("--max-tokens", type=int)
parser.add_argument("--progress", action="store_true")
args = parser.parse_args()

settings = load_settings()
export_format = args.format or settings.get("export_format", "md")
tree_only = args.tree_only or settings.get("tree_only", False)
include_heading = settings.get("include_heading", True)
if args.no_heading:
include_heading = False
use_code_block = settings.get("use_code_block", True)
if args.no_code_block:
use_code_block = False
max_tokens = args.max_tokens or settings.get("max_tokens", 200000)

files = collect_files(args.source, settings)
total = len(files)

def cb(current, maximum):
if args.progress:
percent = int(current / maximum * 100)
print(f"\r{percent}% ({current}/{maximum})", end="", flush=True)

output_paths = generate_output(
args.source,
args.dest,
files,
export_format,
tree_only,
include_heading,
use_code_block,
max_tokens,
progress_callback=cb if args.progress else None,
)
if args.progress:
print()
for p in output_paths:
print(p)


if __name__ == "__main__":
main()
Loading