diffron 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Diffron Contributors
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,2 @@
1
+ diffron
2
+ docs
docs/HOOKS.md ADDED
@@ -0,0 +1,442 @@
1
+ # Diffron Git Hooks Architecture
2
+
3
+ Detailed technical documentation on how Diffron Git hooks work on Windows.
4
+
5
+ ---
6
+
7
+ ## Table of Contents
8
+
9
+ 1. [Overview](#overview)
10
+ 2. [Hook Types](#hook-types)
11
+ 3. [Installation Methods](#installation-methods)
12
+ 4. [Hook Execution Flow](#hook-execution-flow)
13
+ 5. [File Structure](#file-structure)
14
+ 6. [Windows-Specific Implementation](#windows-specific-implementation)
15
+ 7. [Security Considerations](#security-considerations)
16
+ 8. [Customization](#customization)
17
+
18
+ ---
19
+
20
+ ## Overview
21
+
22
+ Diffron uses Git's `prepare-commit-msg` hook to automatically generate commit messages using AI. The hook runs **before** the commit message editor opens, allowing it to pre-populate the message.
23
+
24
+ ### Key Features
25
+
26
+ - **Automatic:** Runs on every `git commit`
27
+ - **Non-blocking:** Commits still work if Lemonade is unavailable
28
+ - **Smart:** Skips merges, rebases, and amends
29
+ - **Windows-native:** Designed for GitHub Desktop 3.5.5+
30
+
31
+ ---
32
+
33
+ ## Hook Types
34
+
35
+ ### prepare-commit-msg Hook
36
+
37
+ **When it runs:** After Git prepares the default commit message, but before the editor starts.
38
+
39
+ **Purpose:** Modify or replace the default commit message.
40
+
41
+ **Arguments:**
42
+ 1. `$1` - Path to file containing the commit message
43
+ 2. `$2` - Source of the commit message (`message`, `template`, `merge`, `squash`, `commit`)
44
+ 3. `$3` - (Optional) Commit object name (for `commit` source)
45
+
46
+ **Diffron behavior:**
47
+ - Reads staged diff
48
+ - Calls Lemonade API
49
+ - Writes generated message to file
50
+ - Git opens editor with generated message
51
+
52
+ ---
53
+
54
+ ## Installation Methods
55
+
56
+ ### Global Installation
57
+
58
+ **Location:** `C:\Users\YourName\.diffron-hooks\`
59
+
60
+ **Git config:**
61
+ ```bash
62
+ git config --global core.hooksPath "C:/Users/YourName/.diffron-hooks"
63
+ ```
64
+
65
+ **Applies to:** All repositories on the system.
66
+
67
+ **Pros:**
68
+ - Install once, works everywhere
69
+ - Consistent behavior across projects
70
+
71
+ **Cons:**
72
+ - Affects all repositories
73
+ - Requires global Git configuration
74
+
75
+ ### Per-Repository Installation
76
+
77
+ **Location:** `.git\hooks\`
78
+
79
+ **Git config:** None required (Git checks `.git/hooks` by default)
80
+
81
+ **Applies to:** Single repository only.
82
+
83
+ **Pros:**
84
+ - Repository-specific configuration
85
+ - No global changes
86
+
87
+ **Cons:**
88
+ - Must install for each repository
89
+ - Easy to forget when cloning
90
+
91
+ ---
92
+
93
+ ## Hook Execution Flow
94
+
95
+ ```
96
+ ┌─────────────────────────────────────────────────────────────────┐
97
+ │ USER ACTION │
98
+ │ git commit -m "anything" (or GitHub Desktop) │
99
+ └─────────────────────────────────────────────────────────────────┘
100
+
101
+
102
+ ┌─────────────────────────────────────────────────────────────────┐
103
+ │ GIT PREPARES COMMIT │
104
+ │ - Validates staged changes │
105
+ │ - Creates .git/COMMIT_EDITMSG with default message │
106
+ │ - Determines commit source (message/template/merge) │
107
+ └─────────────────────────────────────────────────────────────────┘
108
+
109
+
110
+ ┌─────────────────────────────────────────────────────────────────┐
111
+ │ GIT EXECUTES prepare-commit-msg HOOK │
112
+ │ - Calls: .diffron-hooks/prepare-commit-msg │
113
+ │ - Passes: COMMIT_EDITMSG path, commit source │
114
+ └─────────────────────────────────────────────────────────────────┘
115
+
116
+
117
+ ┌─────────────────────────────────────────────────────────────────┐
118
+ │ SHELL WRAPPER (prepare-commit-msg) │
119
+ │ #!/C:/Program Files/Git/usr/bin/sh.exe │
120
+ │ HOOK_DIR="$(cd "$(dirname "$0")" && pwd)" │
121
+ │ python "$HOOK_DIR/prepare-commit-msg.py" "$1" "$2" │
122
+ └─────────────────────────────────────────────────────────────────┘
123
+
124
+
125
+ ┌─────────────────────────────────────────────────────────────────┐
126
+ │ PYTHON HOOK (prepare-commit-msg.py) │
127
+ │ 1. Parse arguments (msg_file, commit_source) │
128
+ │ 2. Check if should skip (merge/squash/amend) │
129
+ │ 3. Check if Lemonade is running │
130
+ │ 4. Get staged diff (git diff --cached) │
131
+ │ 5. Call Lemonade API for message generation │
132
+ │ 6. Write generated message to msg_file │
133
+ └─────────────────────────────────────────────────────────────────┘
134
+
135
+
136
+ ┌─────────────────────────────────────────────────────────────────┐
137
+ │ GIT OPENS EDITOR │
138
+ │ - Opens COMMIT_EDITMSG with generated content │
139
+ │ - User can review/modify before saving │
140
+ └─────────────────────────────────────────────────────────────────┘
141
+
142
+
143
+ ┌─────────────────────────────────────────────────────────────────┐
144
+ │ COMMIT COMPLETED │
145
+ │ - Git creates commit with final message │
146
+ │ - Hook execution complete │
147
+ └─────────────────────────────────────────────────────────────────┘
148
+ ```
149
+
150
+ ---
151
+
152
+ ## File Structure
153
+
154
+ ### Global Hooks Directory
155
+
156
+ ```
157
+ C:\Users\YourName\.diffron-hooks\
158
+ ├── prepare-commit-msg # Shell wrapper (no extension)
159
+ └── prepare-commit-msg.py # Python hook script
160
+ ```
161
+
162
+ ### File Contents
163
+
164
+ #### prepare-commit-msg (Shell Wrapper)
165
+
166
+ ```bash
167
+ #!/C:/Program Files/Git/usr/bin/sh.exe
168
+ # Diffron prepare-commit-msg hook wrapper
169
+
170
+ # Get the directory where this wrapper script is located
171
+ HOOK_DIR="$(cd "$(dirname "$0")" && pwd)"
172
+ python "$HOOK_DIR/prepare-commit-msg.py" "$1" "$2"
173
+ exit 0
174
+ ```
175
+
176
+ **Purpose:** Git for Windows executes this shell script, which delegates to Python.
177
+
178
+ **Why a wrapper?**
179
+ - Git for Windows uses bundled Git Bash
180
+ - Python may not be in Git Bash PATH
181
+ - Wrapper ensures correct Python interpreter is used
182
+
183
+ #### prepare-commit-msg.py (Python Hook)
184
+
185
+ ```python
186
+ #!/usr/bin/env python
187
+ """Diffron prepare-commit-msg Git hook."""
188
+
189
+ import sys
190
+ import os
191
+ from diffron.commit_gen import generate_commit_message
192
+ from diffron.lemonade import is_lemonade_running
193
+
194
+
195
+ def main():
196
+ # Parse arguments
197
+ if len(sys.argv) < 2:
198
+ sys.exit(1)
199
+
200
+ commit_msg_file = sys.argv[1]
201
+ commit_source = sys.argv[2] if len(sys.argv) > 2 else ""
202
+
203
+ # Skip for merges, rebases, amends
204
+ skip_sources = {"merge", "squash", "commit"}
205
+ if commit_source in skip_sources:
206
+ sys.exit(0)
207
+
208
+ # Check if Lemonade is running
209
+ if not is_lemonade_running():
210
+ sys.exit(0) # Silent skip
211
+
212
+ try:
213
+ # Generate commit message
214
+ commit_message = generate_commit_message()
215
+
216
+ if commit_message:
217
+ # Write to commit message file
218
+ with open(commit_msg_file, "w", encoding="utf-8") as f:
219
+ f.write(commit_message)
220
+ except Exception as e:
221
+ # Log error but don't block commit
222
+ error_msg = f"# Diffron error: {e}\n"
223
+ try:
224
+ with open(commit_msg_file, "a", encoding="utf-8") as f:
225
+ f.write(error_msg)
226
+ except Exception:
227
+ pass
228
+
229
+ sys.exit(0)
230
+
231
+
232
+ if __name__ == "__main__":
233
+ main()
234
+ ```
235
+
236
+ ---
237
+
238
+ ## Windows-Specific Implementation
239
+
240
+ ### GitHub Desktop 3.5.5+ Hooks Support
241
+
242
+ Before version 3.5.5, GitHub Desktop on Windows had issues with Git hooks:
243
+
244
+ | Issue | Status in 3.5.5+ |
245
+ |-------|------------------|
246
+ | PATH not inherited | ✅ Fixed |
247
+ | Shell interpreter missing | ✅ Fixed |
248
+ | Hooks path ignored | ✅ Fixed |
249
+
250
+ ### Why This Implementation Works
251
+
252
+ 1. **Shell Wrapper:** Uses Git Bash's `sh.exe` interpreter
253
+ - Path: `C:/Program Files/Git/usr/bin/sh.exe`
254
+ - Bundled with Git for Windows
255
+
256
+ 2. **Python Path:** Wrapper finds Python from system PATH
257
+ - No hardcoded Python path
258
+ - Works with any Python installation
259
+
260
+ 3. **Absolute Paths:** Hook directory resolved dynamically
261
+ ```bash
262
+ HOOK_DIR="$(cd "$(dirname "$0")" && pwd)"
263
+ ```
264
+
265
+ 4. **UTF-8 Encoding:** All file I/O uses UTF-8
266
+ - Windows default is often CP1252
267
+ - Explicit encoding prevents issues
268
+
269
+ ### Git Configuration
270
+
271
+ **Check current hooks path:**
272
+ ```bash
273
+ git config --global core.hooksPath
274
+ ```
275
+
276
+ **Set hooks path manually:**
277
+ ```bash
278
+ git config --global core.hooksPath "C:/Users/YourName/.diffron-hooks"
279
+ ```
280
+
281
+ **Verify Git can find hooks:**
282
+ ```bash
283
+ git config core.hooksPath
284
+ dir "%USERPROFILE%\.diffron-hooks"
285
+ ```
286
+
287
+ ---
288
+
289
+ ## Security Considerations
290
+
291
+ ### Hook Permissions
292
+
293
+ On Windows, file permissions are less restrictive than Unix. However:
294
+
295
+ - Hooks should only be writable by the user
296
+ - Avoid running Git as Administrator
297
+ - Keep `.diffron-hooks` in user directory
298
+
299
+ ### Code Execution
300
+
301
+ Git hooks execute arbitrary code. Security measures:
302
+
303
+ 1. **Diffron hooks are open source** - code is auditable
304
+ 2. **No network calls except to localhost** - Lemonade runs locally
305
+ 3. **No sensitive data transmitted** - only code diffs
306
+
307
+ ### Supply Chain
308
+
309
+ When installing from PyPI:
310
+
311
+ ```bash
312
+ pip install diffron
313
+ ```
314
+
315
+ The package is verified by PyPI's security measures. For maximum security, install from source:
316
+
317
+ ```bash
318
+ git clone https://github.com/diffron/diffron.git
319
+ cd diffron
320
+ pip install -e .
321
+ ```
322
+
323
+ ---
324
+
325
+ ## Customization
326
+
327
+ ### Modify Hook Behavior
328
+
329
+ Edit `.diffron-hooks/prepare-commit-msg.py`:
330
+
331
+ ```python
332
+ # Change max diff size
333
+ from diffron.commit_gen import generate_commit_message
334
+ msg = generate_commit_message(max_chars=8000) # Default: 4000
335
+
336
+ # Change temperature (creativity)
337
+ from diffron.lemonade import LemonadeClient
338
+ client = LemonadeClient()
339
+ msg = client.generate_commit_message(temperature=0.5) # Default: 0.2
340
+ ```
341
+
342
+ ### Add Custom Logic
343
+
344
+ ```python
345
+ # Add timestamp comment
346
+ with open(commit_msg_file, "a", encoding="utf-8") as f:
347
+ f.write(f"\n# Generated by Diffron at {datetime.now()}")
348
+ ```
349
+
350
+ ### Disable for Specific Repositories
351
+
352
+ ```bash
353
+ # In specific repository
354
+ cd path/to/repo
355
+ git config --unset core.hooksPath
356
+ ```
357
+
358
+ ### Use Different Model Per Repository
359
+
360
+ ```bash
361
+ # In specific repository
362
+ cd path/to/repo
363
+ git config diffron.model "your-model-name"
364
+ ```
365
+
366
+ Then modify hook to read this config:
367
+
368
+ ```python
369
+ import subprocess
370
+ result = subprocess.run(
371
+ ["git", "config", "diffron.model"],
372
+ capture_output=True,
373
+ text=True
374
+ )
375
+ model = result.stdout.strip() or "qwen2.5-it-3b-FLM"
376
+ ```
377
+
378
+ ---
379
+
380
+ ## Debugging Hooks
381
+
382
+ ### Enable Verbose Output
383
+
384
+ Add to `prepare-commit-msg.py`:
385
+
386
+ ```python
387
+ import sys
388
+
389
+ # Log to file for debugging
390
+ with open("C:/temp/diffron-hook.log", "a", encoding="utf-8") as log:
391
+ log.write(f"Arguments: {sys.argv}\n")
392
+ log.write(f"Commit source: {commit_source}\n")
393
+ ```
394
+
395
+ ### Test Hook Manually
396
+
397
+ ```bash
398
+ # Create test commit message file
399
+ echo "test message" > C:\temp\test-commit-msg.txt
400
+
401
+ # Run hook manually
402
+ python C:\Users\YourName\.diffron-hooks\prepare-commit-msg.py C:\temp\test-commit-msg.txt message
403
+
404
+ # Check result
405
+ type C:\temp\test-commit-msg.txt
406
+ ```
407
+
408
+ ### Check Git Hook Execution
409
+
410
+ ```bash
411
+ # Enable Git trace
412
+ export GIT_TRACE=1
413
+ git commit -m "test"
414
+
415
+ # Look for hook execution in output
416
+ ```
417
+
418
+ ---
419
+
420
+ ## Hook Lifecycle
421
+
422
+ ### Installation
423
+ 1. User runs `install_hooks(global_install=True)`
424
+ 2. Files copied to `.diffron-hooks`
425
+ 3. Git config set to hooks path
426
+
427
+ ### Execution (per commit)
428
+ 1. Git detects `prepare-commit-msg` hook
429
+ 2. Shell wrapper executes
430
+ 3. Python script runs
431
+ 4. Message generated and written
432
+ 5. Git opens editor
433
+
434
+ ### Uninstallation
435
+ 1. User runs `uninstall_hooks(global_install=True)`
436
+ 2. Git config unset
437
+ 3. `.diffron-hooks` directory removed
438
+
439
+ ---
440
+
441
+ *Last updated: 2026-03-28*
442
+ *Version: 0.1.0*