promptdiff-cli 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- promptdiff_cli-0.1.0/LICENSE +21 -0
- promptdiff_cli-0.1.0/PKG-INFO +166 -0
- promptdiff_cli-0.1.0/README.md +133 -0
- promptdiff_cli-0.1.0/promptdiff/__init__.py +1 -0
- promptdiff_cli-0.1.0/promptdiff/api/__init__.py +1 -0
- promptdiff_cli-0.1.0/promptdiff/cli/__init__.py +1 -0
- promptdiff_cli-0.1.0/promptdiff/cli/context.py +52 -0
- promptdiff_cli-0.1.0/promptdiff/cli/main.py +338 -0
- promptdiff_cli-0.1.0/promptdiff/core/__init__.py +1 -0
- promptdiff_cli-0.1.0/promptdiff/core/diff.py +126 -0
- promptdiff_cli-0.1.0/promptdiff/core/exceptions.py +23 -0
- promptdiff_cli-0.1.0/promptdiff/core/projects.py +27 -0
- promptdiff_cli-0.1.0/promptdiff/core/prompts.py +45 -0
- promptdiff_cli-0.1.0/promptdiff/core/runner.py +213 -0
- promptdiff_cli-0.1.0/promptdiff/core/versions.py +113 -0
- promptdiff_cli-0.1.0/promptdiff/db/__init__.py +1 -0
- promptdiff_cli-0.1.0/promptdiff/db/base.py +4 -0
- promptdiff_cli-0.1.0/promptdiff/db/models.py +105 -0
- promptdiff_cli-0.1.0/promptdiff/db/session.py +24 -0
- promptdiff_cli-0.1.0/promptdiff_cli.egg-info/PKG-INFO +166 -0
- promptdiff_cli-0.1.0/promptdiff_cli.egg-info/SOURCES.txt +32 -0
- promptdiff_cli-0.1.0/promptdiff_cli.egg-info/dependency_links.txt +1 -0
- promptdiff_cli-0.1.0/promptdiff_cli.egg-info/entry_points.txt +2 -0
- promptdiff_cli-0.1.0/promptdiff_cli.egg-info/requires.txt +12 -0
- promptdiff_cli-0.1.0/promptdiff_cli.egg-info/top_level.txt +1 -0
- promptdiff_cli-0.1.0/pyproject.toml +48 -0
- promptdiff_cli-0.1.0/setup.cfg +4 -0
- promptdiff_cli-0.1.0/tests/test_cli.py +273 -0
- promptdiff_cli-0.1.0/tests/test_core_diff.py +56 -0
- promptdiff_cli-0.1.0/tests/test_core_projects.py +45 -0
- promptdiff_cli-0.1.0/tests/test_core_prompts.py +58 -0
- promptdiff_cli-0.1.0/tests/test_core_runner.py +134 -0
- promptdiff_cli-0.1.0/tests/test_core_versions.py +68 -0
- promptdiff_cli-0.1.0/tests/test_models.py +168 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Raguram R
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: promptdiff-cli
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Git for prompts - version, diff, and test your LLM prompts across any model
|
|
5
|
+
Author: Raguram R
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/Ragu3175/promptdiff
|
|
8
|
+
Project-URL: Repository, https://github.com/Ragu3175/promptdiff
|
|
9
|
+
Project-URL: Issues, https://github.com/Ragu3175/promptdiff/issues
|
|
10
|
+
Keywords: llm,prompt-engineering,prompt-versioning,cli,litellm
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Environment :: Console
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Topic :: Software Development :: Version Control
|
|
17
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
18
|
+
Requires-Python: >=3.11
|
|
19
|
+
Description-Content-Type: text/markdown
|
|
20
|
+
License-File: LICENSE
|
|
21
|
+
Requires-Dist: fastapi>=0.110.0
|
|
22
|
+
Requires-Dist: uvicorn>=0.28.0
|
|
23
|
+
Requires-Dist: sqlalchemy>=2.0.0
|
|
24
|
+
Requires-Dist: alembic>=1.13.0
|
|
25
|
+
Requires-Dist: typer>=0.9.0
|
|
26
|
+
Requires-Dist: rich>=13.7.0
|
|
27
|
+
Requires-Dist: litellm>=1.30.0
|
|
28
|
+
Requires-Dist: python-dotenv>=1.0.0
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: pytest>=8.0.0; extra == "dev"
|
|
31
|
+
Requires-Dist: pytest-mock; extra == "dev"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# PromptDiff
|
|
35
|
+
|
|
36
|
+
**Git for prompts.** Version your LLM prompts, diff them word-by-word, and run any version against Gemini, Groq, or any other LiteLLM-supported model — all from the terminal.
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
promptdiff commit summarizer "Summarize: {text}" -m "v1: baseline"
|
|
40
|
+
promptdiff commit summarizer "Summarize concisely in one sentence: {text}" -m "v2: tighter constraint"
|
|
41
|
+
promptdiff diff summarizer 1 2
|
|
42
|
+
promptdiff run summarizer 2 --model gemini/gemini-2.5-flash
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Why PromptDiff
|
|
46
|
+
|
|
47
|
+
If you've ever overwritten a prompt and lost the version that actually worked, or pasted two prompt drafts into a doc just to eyeball what changed — PromptDiff is the tool for that. It treats prompts as versioned, diffable artifacts the same way Git treats code, and adds one thing Git can't: running any version against a real LLM and recording exactly what it produced, so you can trace output back to the exact prompt and model that generated it.
|
|
48
|
+
|
|
49
|
+
## How it's different from other prompt tools
|
|
50
|
+
|
|
51
|
+
The prompt-tooling space has grown a lot — [Promptfoo](https://github.com/promptfoo/promptfoo) is a mature, YAML-config-based open-source tool with strong CI/eval integration, and platforms like PromptLayer, Langfuse, and Braintrust offer hosted, full-lifecycle prompt management with branching, RBAC, and observability.
|
|
52
|
+
|
|
53
|
+
PromptDiff isn't trying to compete with those. It's deliberately smaller: a local-first CLI for a single developer iterating on prompts, with zero config files, zero hosted accounts, and zero cost beyond free-tier LLM API usage. If you outgrow it — multiple collaborators, non-engineer prompt editors, compliance requirements — those other tools are the right next step. If you're a solo developer who just wants `git commit`-style version control for prompts without standing up infrastructure, PromptDiff is built for exactly that.
|
|
54
|
+
|
|
55
|
+
## Features
|
|
56
|
+
|
|
57
|
+
- **Version control for prompts** — every `commit` is an immutable, numbered version (v1, v2, v3...) scoped per prompt
|
|
58
|
+
- **Word-level diffs** — see exactly which words changed between versions, rendered with color in your terminal (green additions, red strikethrough removals)
|
|
59
|
+
- **Multi-model runs** — execute any prompt version against multiple LLMs in a single command and compare cost, latency, and output side by side
|
|
60
|
+
- **Output comparison** — `diff-output` shows what two versions actually *produced*, not just what their text looks like
|
|
61
|
+
- **Free-tier friendly** — built and tested against Gemini and Groq's free tiers; rate-limit and quota failures are recorded gracefully, never crash the tool
|
|
62
|
+
- **Local-first** — everything lives in a local SQLite database, no account or server required
|
|
63
|
+
|
|
64
|
+
## Installation
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pip install promptdiff-cli
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
(Or, to run from source — see [Development](#development) below.)
|
|
71
|
+
|
|
72
|
+
## Quick start
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# Create a project and switch to it
|
|
76
|
+
promptdiff project create my-app
|
|
77
|
+
promptdiff use my-app
|
|
78
|
+
|
|
79
|
+
# Create a prompt and commit your first version
|
|
80
|
+
promptdiff add summarizer
|
|
81
|
+
promptdiff commit summarizer "Summarize this in one sentence: {text}" -m "v1: baseline"
|
|
82
|
+
|
|
83
|
+
# Edit and commit a new version
|
|
84
|
+
promptdiff commit summarizer "Summarize concisely, max 20 words: {text}" -m "v2: tighter constraint"
|
|
85
|
+
|
|
86
|
+
# See version history
|
|
87
|
+
promptdiff log summarizer
|
|
88
|
+
|
|
89
|
+
# See exactly what changed
|
|
90
|
+
promptdiff diff summarizer 1 2
|
|
91
|
+
|
|
92
|
+
# Run a version against a model (needs an API key — see below)
|
|
93
|
+
promptdiff run summarizer 2 --model gemini/gemini-2.5-flash
|
|
94
|
+
|
|
95
|
+
# Run the same version against multiple models at once
|
|
96
|
+
promptdiff run summarizer 2 --model gemini/gemini-2.5-flash --model groq/llama-3.3-70b-versatile
|
|
97
|
+
|
|
98
|
+
# Compare what two versions actually produced
|
|
99
|
+
promptdiff diff-output summarizer 1 2 --model gemini/gemini-2.5-flash
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## API keys
|
|
103
|
+
|
|
104
|
+
PromptDiff uses [LiteLLM](https://github.com/BerriAI/litellm) under the hood, so it works with any LiteLLM-supported provider. It's built and tested primarily against free tiers:
|
|
105
|
+
|
|
106
|
+
- **Gemini** — get a free key at [aistudio.google.com/apikey](https://aistudio.google.com/apikey)
|
|
107
|
+
- **Groq** — get a free key at [console.groq.com/keys](https://console.groq.com/keys)
|
|
108
|
+
|
|
109
|
+
Copy `.env.example` to `.env` in your project directory and fill in the keys you have:
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
GEMINI_API_KEY=your_key_here
|
|
113
|
+
GROQ_API_KEY=your_key_here
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
## Commands
|
|
117
|
+
|
|
118
|
+
| Command | What it does |
|
|
119
|
+
|---|---|
|
|
120
|
+
| `promptdiff project create <name>` | Create a new project |
|
|
121
|
+
| `promptdiff project list` | List all projects |
|
|
122
|
+
| `promptdiff use <project>` | Set the current project (so you don't need `--project` on every command) |
|
|
123
|
+
| `promptdiff add <prompt>` | Add a new prompt to the current project |
|
|
124
|
+
| `promptdiff commit <prompt> <content_or_file> -m "<message>"` | Commit a new version. Accepts a literal string or a path to a file |
|
|
125
|
+
| `promptdiff log <prompt>` | Show version history |
|
|
126
|
+
| `promptdiff diff <prompt> <v1> <v2>` | Word-level diff between two versions |
|
|
127
|
+
| `promptdiff run <prompt> <version> --model <model>` | Run a version against one or more models (repeat `--model` to run against several at once) |
|
|
128
|
+
| `promptdiff diff-output <prompt> <v1> <v2> [--model <model>]` | Compare what two versions actually produced. If a version was run against multiple models, `--model` is required to avoid an ambiguous comparison |
|
|
129
|
+
|
|
130
|
+
Every command accepts `-p` / `--project` to override the current project for that one call.
|
|
131
|
+
|
|
132
|
+
## Architecture
|
|
133
|
+
|
|
134
|
+
- **Database**: SQLite, 5 tables (`projects`, `prompts`, `versions`, `runs`, `outputs`) via SQLAlchemy + Alembic migrations
|
|
135
|
+
- **Diff engine**: Python's `difflib`, line-level structure with word-level precision inside changed lines
|
|
136
|
+
- **Runner**: [LiteLLM](https://github.com/BerriAI/litellm) for provider-agnostic model calls; failures (rate limits, timeouts, bad keys) are recorded as failed runs rather than crashing the CLI
|
|
137
|
+
- **CLI**: [Typer](https://typer.tiangolo.com/) + [Rich](https://github.com/Textualize/rich)
|
|
138
|
+
|
|
139
|
+
## Development
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
git clone https://github.com/Ragu3175/promptdiff.git
|
|
143
|
+
cd promptdiff
|
|
144
|
+
python -m venv venv
|
|
145
|
+
venv\Scripts\activate # Windows
|
|
146
|
+
# source venv/bin/activate # macOS/Linux
|
|
147
|
+
pip install -r requirements.txt
|
|
148
|
+
pip install -e .
|
|
149
|
+
pytest -v
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Status
|
|
153
|
+
|
|
154
|
+
Core CLI is complete and tested: `commit`, `log`, `diff`, `run`, and `diff-output` all work end-to-end against real Gemini and Groq calls. A REST API layer and web UI are planned but not yet built — the CLI is fully usable on its own today.
|
|
155
|
+
|
|
156
|
+
## Contributing
|
|
157
|
+
|
|
158
|
+
Issues and PRs welcome. This is an early-stage solo project — if you run into something broken or have an idea, please open an issue.
|
|
159
|
+
|
|
160
|
+
## License
|
|
161
|
+
|
|
162
|
+
MIT — see [LICENSE](LICENSE).
|
|
163
|
+
|
|
164
|
+
## Author
|
|
165
|
+
|
|
166
|
+
Built by [Raguram R](https://github.com/Ragu3175).
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# PromptDiff
|
|
2
|
+
|
|
3
|
+
**Git for prompts.** Version your LLM prompts, diff them word-by-word, and run any version against Gemini, Groq, or any other LiteLLM-supported model — all from the terminal.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
promptdiff commit summarizer "Summarize: {text}" -m "v1: baseline"
|
|
7
|
+
promptdiff commit summarizer "Summarize concisely in one sentence: {text}" -m "v2: tighter constraint"
|
|
8
|
+
promptdiff diff summarizer 1 2
|
|
9
|
+
promptdiff run summarizer 2 --model gemini/gemini-2.5-flash
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Why PromptDiff
|
|
13
|
+
|
|
14
|
+
If you've ever overwritten a prompt and lost the version that actually worked, or pasted two prompt drafts into a doc just to eyeball what changed — PromptDiff is the tool for that. It treats prompts as versioned, diffable artifacts the same way Git treats code, and adds one thing Git can't: running any version against a real LLM and recording exactly what it produced, so you can trace output back to the exact prompt and model that generated it.
|
|
15
|
+
|
|
16
|
+
## How it's different from other prompt tools
|
|
17
|
+
|
|
18
|
+
The prompt-tooling space has grown a lot — [Promptfoo](https://github.com/promptfoo/promptfoo) is a mature, YAML-config-based open-source tool with strong CI/eval integration, and platforms like PromptLayer, Langfuse, and Braintrust offer hosted, full-lifecycle prompt management with branching, RBAC, and observability.
|
|
19
|
+
|
|
20
|
+
PromptDiff isn't trying to compete with those. It's deliberately smaller: a local-first CLI for a single developer iterating on prompts, with zero config files, zero hosted accounts, and zero cost beyond free-tier LLM API usage. If you outgrow it — multiple collaborators, non-engineer prompt editors, compliance requirements — those other tools are the right next step. If you're a solo developer who just wants `git commit`-style version control for prompts without standing up infrastructure, PromptDiff is built for exactly that.
|
|
21
|
+
|
|
22
|
+
## Features
|
|
23
|
+
|
|
24
|
+
- **Version control for prompts** — every `commit` is an immutable, numbered version (v1, v2, v3...) scoped per prompt
|
|
25
|
+
- **Word-level diffs** — see exactly which words changed between versions, rendered with color in your terminal (green additions, red strikethrough removals)
|
|
26
|
+
- **Multi-model runs** — execute any prompt version against multiple LLMs in a single command and compare cost, latency, and output side by side
|
|
27
|
+
- **Output comparison** — `diff-output` shows what two versions actually *produced*, not just what their text looks like
|
|
28
|
+
- **Free-tier friendly** — built and tested against Gemini and Groq's free tiers; rate-limit and quota failures are recorded gracefully, never crash the tool
|
|
29
|
+
- **Local-first** — everything lives in a local SQLite database, no account or server required
|
|
30
|
+
|
|
31
|
+
## Installation
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
pip install promptdiff-cli
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
(Or, to run from source — see [Development](#development) below.)
|
|
38
|
+
|
|
39
|
+
## Quick start
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
# Create a project and switch to it
|
|
43
|
+
promptdiff project create my-app
|
|
44
|
+
promptdiff use my-app
|
|
45
|
+
|
|
46
|
+
# Create a prompt and commit your first version
|
|
47
|
+
promptdiff add summarizer
|
|
48
|
+
promptdiff commit summarizer "Summarize this in one sentence: {text}" -m "v1: baseline"
|
|
49
|
+
|
|
50
|
+
# Edit and commit a new version
|
|
51
|
+
promptdiff commit summarizer "Summarize concisely, max 20 words: {text}" -m "v2: tighter constraint"
|
|
52
|
+
|
|
53
|
+
# See version history
|
|
54
|
+
promptdiff log summarizer
|
|
55
|
+
|
|
56
|
+
# See exactly what changed
|
|
57
|
+
promptdiff diff summarizer 1 2
|
|
58
|
+
|
|
59
|
+
# Run a version against a model (needs an API key — see below)
|
|
60
|
+
promptdiff run summarizer 2 --model gemini/gemini-2.5-flash
|
|
61
|
+
|
|
62
|
+
# Run the same version against multiple models at once
|
|
63
|
+
promptdiff run summarizer 2 --model gemini/gemini-2.5-flash --model groq/llama-3.3-70b-versatile
|
|
64
|
+
|
|
65
|
+
# Compare what two versions actually produced
|
|
66
|
+
promptdiff diff-output summarizer 1 2 --model gemini/gemini-2.5-flash
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## API keys
|
|
70
|
+
|
|
71
|
+
PromptDiff uses [LiteLLM](https://github.com/BerriAI/litellm) under the hood, so it works with any LiteLLM-supported provider. It's built and tested primarily against free tiers:
|
|
72
|
+
|
|
73
|
+
- **Gemini** — get a free key at [aistudio.google.com/apikey](https://aistudio.google.com/apikey)
|
|
74
|
+
- **Groq** — get a free key at [console.groq.com/keys](https://console.groq.com/keys)
|
|
75
|
+
|
|
76
|
+
Copy `.env.example` to `.env` in your project directory and fill in the keys you have:
|
|
77
|
+
|
|
78
|
+
```
|
|
79
|
+
GEMINI_API_KEY=your_key_here
|
|
80
|
+
GROQ_API_KEY=your_key_here
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Commands
|
|
84
|
+
|
|
85
|
+
| Command | What it does |
|
|
86
|
+
|---|---|
|
|
87
|
+
| `promptdiff project create <name>` | Create a new project |
|
|
88
|
+
| `promptdiff project list` | List all projects |
|
|
89
|
+
| `promptdiff use <project>` | Set the current project (so you don't need `--project` on every command) |
|
|
90
|
+
| `promptdiff add <prompt>` | Add a new prompt to the current project |
|
|
91
|
+
| `promptdiff commit <prompt> <content_or_file> -m "<message>"` | Commit a new version. Accepts a literal string or a path to a file |
|
|
92
|
+
| `promptdiff log <prompt>` | Show version history |
|
|
93
|
+
| `promptdiff diff <prompt> <v1> <v2>` | Word-level diff between two versions |
|
|
94
|
+
| `promptdiff run <prompt> <version> --model <model>` | Run a version against one or more models (repeat `--model` to run against several at once) |
|
|
95
|
+
| `promptdiff diff-output <prompt> <v1> <v2> [--model <model>]` | Compare what two versions actually produced. If a version was run against multiple models, `--model` is required to avoid an ambiguous comparison |
|
|
96
|
+
|
|
97
|
+
Every command accepts `-p` / `--project` to override the current project for that one call.
|
|
98
|
+
|
|
99
|
+
## Architecture
|
|
100
|
+
|
|
101
|
+
- **Database**: SQLite, 5 tables (`projects`, `prompts`, `versions`, `runs`, `outputs`) via SQLAlchemy + Alembic migrations
|
|
102
|
+
- **Diff engine**: Python's `difflib`, line-level structure with word-level precision inside changed lines
|
|
103
|
+
- **Runner**: [LiteLLM](https://github.com/BerriAI/litellm) for provider-agnostic model calls; failures (rate limits, timeouts, bad keys) are recorded as failed runs rather than crashing the CLI
|
|
104
|
+
- **CLI**: [Typer](https://typer.tiangolo.com/) + [Rich](https://github.com/Textualize/rich)
|
|
105
|
+
|
|
106
|
+
## Development
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
git clone https://github.com/Ragu3175/promptdiff.git
|
|
110
|
+
cd promptdiff
|
|
111
|
+
python -m venv venv
|
|
112
|
+
venv\Scripts\activate # Windows
|
|
113
|
+
# source venv/bin/activate # macOS/Linux
|
|
114
|
+
pip install -r requirements.txt
|
|
115
|
+
pip install -e .
|
|
116
|
+
pytest -v
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Status
|
|
120
|
+
|
|
121
|
+
Core CLI is complete and tested: `commit`, `log`, `diff`, `run`, and `diff-output` all work end-to-end against real Gemini and Groq calls. A REST API layer and web UI are planned but not yet built — the CLI is fully usable on its own today.
|
|
122
|
+
|
|
123
|
+
## Contributing
|
|
124
|
+
|
|
125
|
+
Issues and PRs welcome. This is an early-stage solo project — if you run into something broken or have an idea, please open an issue.
|
|
126
|
+
|
|
127
|
+
## License
|
|
128
|
+
|
|
129
|
+
MIT — see [LICENSE](LICENSE).
|
|
130
|
+
|
|
131
|
+
## Author
|
|
132
|
+
|
|
133
|
+
Built by [Raguram R](https://github.com/Ragu3175).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# PromptDiff package
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# API package
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# CLI package
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import json
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from contextlib import contextmanager
|
|
5
|
+
from typing import Generator
|
|
6
|
+
from sqlalchemy.orm import Session
|
|
7
|
+
import typer
|
|
8
|
+
|
|
9
|
+
from promptdiff.db.session import get_db
|
|
10
|
+
|
|
11
|
+
def get_config_dir() -> Path:
|
|
12
|
+
"""Get the configuration directory path, allowing environment override for tests."""
|
|
13
|
+
env_home = os.environ.get("PROMPTDIFF_HOME")
|
|
14
|
+
if env_home:
|
|
15
|
+
return Path(env_home)
|
|
16
|
+
return Path.home() / ".promptdiff"
|
|
17
|
+
|
|
18
|
+
def get_config_path() -> Path:
|
|
19
|
+
"""Get the path to the config.json file."""
|
|
20
|
+
return get_config_dir() / "config.json"
|
|
21
|
+
|
|
22
|
+
def resolve_project(explicit: str | None) -> str:
|
|
23
|
+
"""Resolve the project name using explicit override or current project config.
|
|
24
|
+
|
|
25
|
+
Raises typer.Exit(code=1) if no project name can be resolved.
|
|
26
|
+
"""
|
|
27
|
+
if explicit:
|
|
28
|
+
return explicit
|
|
29
|
+
|
|
30
|
+
config_file = get_config_path()
|
|
31
|
+
if config_file.is_file():
|
|
32
|
+
try:
|
|
33
|
+
with open(config_file, "r") as f:
|
|
34
|
+
data = json.load(f)
|
|
35
|
+
current = data.get("current_project")
|
|
36
|
+
if current:
|
|
37
|
+
return current
|
|
38
|
+
except Exception:
|
|
39
|
+
pass
|
|
40
|
+
|
|
41
|
+
typer.secho(
|
|
42
|
+
"Error: No project specified. Use --project or run `promptdiff use <project>` first.",
|
|
43
|
+
fg=typer.colors.RED,
|
|
44
|
+
err=True
|
|
45
|
+
)
|
|
46
|
+
raise typer.Exit(code=1)
|
|
47
|
+
|
|
48
|
+
@contextmanager
|
|
49
|
+
def get_cli_db() -> Generator[Session, None, None]:
|
|
50
|
+
"""Yield a database session and guarantee it closes correctly."""
|
|
51
|
+
with get_db() as db:
|
|
52
|
+
yield db
|