repr-cli 0.2.5__py3-none-any.whl → 0.2.7__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.
repr/__init__.py CHANGED
@@ -5,6 +5,11 @@ Analyzes your local git repositories and generates a compelling
5
5
  developer profile without ever sending your source code to the cloud.
6
6
  """
7
7
 
8
- __version__ = "0.2.0"
8
+ try:
9
+ from importlib.metadata import version
10
+ __version__ = version("repr-cli")
11
+ except Exception:
12
+ # Fallback for PyInstaller builds where metadata isn't available
13
+ __version__ = "0.2.7"
9
14
  __author__ = "Repr"
10
15
  __email__ = "hello@repr.dev"
repr/cli.py CHANGED
@@ -136,6 +136,7 @@ def dev_callback(value: bool):
136
136
 
137
137
  @app.callback()
138
138
  def main(
139
+ ctx: typer.Context,
139
140
  version: bool = typer.Option(
140
141
  False, "--version", "-v",
141
142
  callback=version_callback,
@@ -155,6 +156,11 @@ def main(
155
156
  """
156
157
  # Migrate plaintext auth tokens on startup
157
158
  migrate_plaintext_auth()
159
+
160
+ # Track command usage (if telemetry enabled)
161
+ from .telemetry import track_command
162
+ if ctx.invoked_subcommand:
163
+ track_command(ctx.invoked_subcommand)
158
164
 
159
165
 
160
166
  # =============================================================================
@@ -1686,6 +1692,90 @@ def llm_test():
1686
1692
  # PRIVACY
1687
1693
  # =============================================================================
1688
1694
 
1695
+ @privacy_app.command("telemetry")
1696
+ def privacy_telemetry(
1697
+ action: str = typer.Argument("status", help="Action: status, enable, disable"),
1698
+ json_output: bool = typer.Option(False, "--json", help="Output as JSON"),
1699
+ ):
1700
+ """
1701
+ Manage anonymous telemetry.
1702
+
1703
+ Telemetry is disabled by default. When enabled, it sends:
1704
+ - Command names and timestamps
1705
+ - OS type and CLI version
1706
+ - Anonymous device ID (random, not linked to you)
1707
+
1708
+ It NEVER sends: code, commits, paths, usernames, emails.
1709
+
1710
+ Examples:
1711
+ repr privacy telemetry Show telemetry status
1712
+ repr privacy telemetry enable Opt-in to telemetry
1713
+ repr privacy telemetry disable Opt-out of telemetry
1714
+ """
1715
+ from .telemetry import (
1716
+ is_telemetry_enabled,
1717
+ enable_telemetry,
1718
+ disable_telemetry,
1719
+ get_queue_stats,
1720
+ get_pending_events,
1721
+ )
1722
+
1723
+ if action == "status":
1724
+ stats = get_queue_stats()
1725
+
1726
+ if json_output:
1727
+ print(json.dumps(stats, indent=2))
1728
+ return
1729
+
1730
+ status = f"[{BRAND_SUCCESS}]enabled[/]" if stats["enabled"] else f"[{BRAND_MUTED}]disabled[/]"
1731
+ console.print(f"[bold]Telemetry[/]: {status}")
1732
+ console.print()
1733
+
1734
+ if stats["enabled"]:
1735
+ console.print(f"Device ID: {stats['device_id']}")
1736
+ console.print(f"Pending events: {stats['pending_events']}")
1737
+ console.print()
1738
+
1739
+ # Show pending events for transparency
1740
+ pending = get_pending_events()
1741
+ if pending:
1742
+ console.print("[bold]Pending events:[/]")
1743
+ for event in pending[-5:]:
1744
+ console.print(f" • {event.get('event', '')} ({event.get('timestamp', '')[:10]})")
1745
+ if len(pending) > 5:
1746
+ console.print(f" [{BRAND_MUTED}]... and {len(pending) - 5} more[/]")
1747
+ else:
1748
+ console.print("Enable with: repr privacy telemetry enable")
1749
+
1750
+ console.print()
1751
+ console.print(f"[{BRAND_MUTED}]Telemetry helps improve repr. No PII is ever sent.[/]")
1752
+
1753
+ elif action == "enable":
1754
+ enable_telemetry()
1755
+ print_success("Telemetry enabled")
1756
+ console.print()
1757
+ console.print("What we collect:")
1758
+ console.print(" ✓ Command names and timestamps")
1759
+ console.print(" ✓ OS type and CLI version")
1760
+ console.print(" ✓ Anonymous device ID")
1761
+ console.print()
1762
+ console.print("What we NEVER collect:")
1763
+ console.print(" ✗ Code, commits, diffs")
1764
+ console.print(" ✗ Paths, filenames")
1765
+ console.print(" ✗ Usernames, emails, PII")
1766
+ console.print()
1767
+ console.print(f"[{BRAND_MUTED}]Disable anytime: repr privacy telemetry disable[/]")
1768
+
1769
+ elif action == "disable":
1770
+ disable_telemetry()
1771
+ print_success("Telemetry disabled")
1772
+ console.print("No data will be collected.")
1773
+
1774
+ else:
1775
+ print_error(f"Unknown action: {action}")
1776
+ print_info("Valid actions: status, enable, disable")
1777
+
1778
+
1689
1779
  @privacy_app.command("explain")
1690
1780
  def privacy_explain():
1691
1781
  """
repr/telemetry.py ADDED
@@ -0,0 +1,279 @@
1
+ """
2
+ Opt-in telemetry for repr CLI.
3
+
4
+ Privacy guarantees:
5
+ - Disabled by default (user must explicitly opt-in)
6
+ - Anonymous device ID (no PII)
7
+ - Events are logged locally first (visible via `repr privacy audit`)
8
+ - Only sends: command name, timestamp, OS, CLI version
9
+ - Never sends: code, commits, diffs, paths, usernames, emails
10
+ - Can be disabled at any time
11
+
12
+ Transparency:
13
+ - All sent events visible in `repr privacy audit`
14
+ - Source code is open (you're reading it!)
15
+ """
16
+
17
+ import hashlib
18
+ import json
19
+ import os
20
+ import platform
21
+ import uuid
22
+ from datetime import datetime
23
+ from pathlib import Path
24
+ from typing import Any
25
+
26
+ import httpx
27
+
28
+ from . import __version__
29
+ from .config import (
30
+ CONFIG_DIR,
31
+ AUDIT_DIR,
32
+ load_config,
33
+ save_config,
34
+ get_config_value,
35
+ set_config_value,
36
+ )
37
+
38
+ # Telemetry endpoint (can be overridden via env var for testing)
39
+ TELEMETRY_ENDPOINT = os.getenv(
40
+ "REPR_TELEMETRY_ENDPOINT",
41
+ "https://api.repr.dev/api/cli/telemetry"
42
+ )
43
+
44
+ # Local telemetry queue file
45
+ TELEMETRY_QUEUE_FILE = AUDIT_DIR / "telemetry_queue.json"
46
+
47
+ # Device ID file (anonymous, persistent)
48
+ DEVICE_ID_FILE = CONFIG_DIR / ".device_id"
49
+
50
+
51
+ def is_telemetry_enabled() -> bool:
52
+ """Check if telemetry is enabled."""
53
+ config = load_config()
54
+ return config.get("privacy", {}).get("telemetry_enabled", False)
55
+
56
+
57
+ def enable_telemetry() -> None:
58
+ """Enable telemetry (opt-in)."""
59
+ set_config_value("privacy.telemetry_enabled", True)
60
+
61
+ # Track the opt-in event
62
+ track("telemetry_enabled", {"source": "cli"})
63
+
64
+
65
+ def disable_telemetry() -> None:
66
+ """Disable telemetry."""
67
+ set_config_value("privacy.telemetry_enabled", False)
68
+
69
+ # Clear any pending events
70
+ clear_queue()
71
+
72
+
73
+ def get_device_id() -> str:
74
+ """
75
+ Get or create anonymous device ID.
76
+
77
+ The ID is:
78
+ - Random UUID, hashed for extra anonymity
79
+ - Persistent across sessions
80
+ - Not linked to any PII
81
+ """
82
+ CONFIG_DIR.mkdir(parents=True, exist_ok=True)
83
+
84
+ if DEVICE_ID_FILE.exists():
85
+ return DEVICE_ID_FILE.read_text().strip()
86
+
87
+ # Generate new anonymous ID
88
+ raw_id = str(uuid.uuid4())
89
+ # Hash it to ensure no UUID format that could be traced
90
+ device_id = hashlib.sha256(raw_id.encode()).hexdigest()[:32]
91
+
92
+ DEVICE_ID_FILE.write_text(device_id)
93
+ return device_id
94
+
95
+
96
+ def get_context() -> dict[str, Any]:
97
+ """
98
+ Get anonymous context for telemetry events.
99
+
100
+ Includes only:
101
+ - OS type and version
102
+ - CLI version
103
+ - Anonymous device ID
104
+
105
+ Never includes:
106
+ - Username, email, paths, code, etc.
107
+ """
108
+ return {
109
+ "device_id": get_device_id(),
110
+ "cli_version": __version__,
111
+ "os": platform.system().lower(),
112
+ "os_version": platform.release(),
113
+ "python_version": platform.python_version(),
114
+ }
115
+
116
+
117
+ def track(event: str, properties: dict[str, Any] | None = None) -> None:
118
+ """
119
+ Track an event (if telemetry is enabled).
120
+
121
+ Args:
122
+ event: Event name (e.g., "command_run", "story_generated")
123
+ properties: Additional properties (must not contain PII)
124
+ """
125
+ if not is_telemetry_enabled():
126
+ return
127
+
128
+ # Build event
129
+ event_data = {
130
+ "event": event,
131
+ "timestamp": datetime.utcnow().isoformat() + "Z",
132
+ "context": get_context(),
133
+ "properties": properties or {},
134
+ }
135
+
136
+ # Queue event locally
137
+ _queue_event(event_data)
138
+
139
+ # Try to flush queue (non-blocking)
140
+ _try_flush_queue()
141
+
142
+
143
+ def track_command(command: str, subcommand: str | None = None, success: bool = True) -> None:
144
+ """
145
+ Track a CLI command execution.
146
+
147
+ Args:
148
+ command: Main command name (e.g., "generate", "push")
149
+ subcommand: Optional subcommand (e.g., "llm add")
150
+ success: Whether command succeeded
151
+ """
152
+ properties = {
153
+ "command": command,
154
+ "success": success,
155
+ }
156
+ if subcommand:
157
+ properties["subcommand"] = subcommand
158
+
159
+ track("command_run", properties)
160
+
161
+
162
+ def track_feature(feature: str, action: str, metadata: dict[str, Any] | None = None) -> None:
163
+ """
164
+ Track feature usage.
165
+
166
+ Args:
167
+ feature: Feature name (e.g., "local_llm", "cloud_sync")
168
+ action: Action taken (e.g., "configured", "used")
169
+ metadata: Additional metadata (no PII!)
170
+ """
171
+ properties = {
172
+ "feature": feature,
173
+ "action": action,
174
+ }
175
+ if metadata:
176
+ # Sanitize metadata to ensure no PII
177
+ safe_metadata = {
178
+ k: v for k, v in metadata.items()
179
+ if k in ("count", "duration_ms", "template", "mode", "provider")
180
+ }
181
+ properties.update(safe_metadata)
182
+
183
+ track("feature_used", properties)
184
+
185
+
186
+ def _queue_event(event: dict[str, Any]) -> None:
187
+ """Queue an event locally for later sending."""
188
+ AUDIT_DIR.mkdir(parents=True, exist_ok=True)
189
+
190
+ # Load existing queue
191
+ queue = _load_queue()
192
+
193
+ # Add event
194
+ queue.append(event)
195
+
196
+ # Keep only last 100 events
197
+ if len(queue) > 100:
198
+ queue = queue[-100:]
199
+
200
+ # Save
201
+ TELEMETRY_QUEUE_FILE.write_text(json.dumps(queue, indent=2))
202
+
203
+
204
+ def _load_queue() -> list[dict[str, Any]]:
205
+ """Load the telemetry queue."""
206
+ if not TELEMETRY_QUEUE_FILE.exists():
207
+ return []
208
+
209
+ try:
210
+ return json.loads(TELEMETRY_QUEUE_FILE.read_text())
211
+ except (json.JSONDecodeError, IOError):
212
+ return []
213
+
214
+
215
+ def _try_flush_queue() -> None:
216
+ """Try to send queued events (non-blocking, best effort)."""
217
+ queue = _load_queue()
218
+ if not queue:
219
+ return
220
+
221
+ try:
222
+ # Send batch (timeout: 2 seconds to not block CLI)
223
+ with httpx.Client(timeout=2.0) as client:
224
+ response = client.post(
225
+ TELEMETRY_ENDPOINT,
226
+ json={"events": queue},
227
+ headers={"Content-Type": "application/json"},
228
+ )
229
+
230
+ if response.status_code == 200:
231
+ # Clear queue on success
232
+ clear_queue()
233
+ except Exception:
234
+ # Silently fail - telemetry should never break the CLI
235
+ pass
236
+
237
+
238
+ def clear_queue() -> int:
239
+ """
240
+ Clear the telemetry queue.
241
+
242
+ Returns:
243
+ Number of events cleared
244
+ """
245
+ queue = _load_queue()
246
+ count = len(queue)
247
+
248
+ if TELEMETRY_QUEUE_FILE.exists():
249
+ TELEMETRY_QUEUE_FILE.unlink()
250
+
251
+ return count
252
+
253
+
254
+ def get_queue_stats() -> dict[str, Any]:
255
+ """
256
+ Get statistics about the telemetry queue.
257
+
258
+ Returns:
259
+ Dict with queue statistics
260
+ """
261
+ queue = _load_queue()
262
+
263
+ return {
264
+ "enabled": is_telemetry_enabled(),
265
+ "pending_events": len(queue),
266
+ "device_id": get_device_id() if DEVICE_ID_FILE.exists() else None,
267
+ "endpoint": TELEMETRY_ENDPOINT,
268
+ }
269
+
270
+
271
+ def get_pending_events() -> list[dict[str, Any]]:
272
+ """
273
+ Get all pending telemetry events (for transparency).
274
+
275
+ Returns:
276
+ List of pending events
277
+ """
278
+ return _load_queue()
279
+
@@ -0,0 +1,370 @@
1
+ Metadata-Version: 2.4
2
+ Name: repr-cli
3
+ Version: 0.2.7
4
+ Summary: A beautiful, privacy-first CLI that analyzes your code repositories and generates a compelling developer profile
5
+ Author-email: Repr <hello@repr.dev>
6
+ License: MIT License
7
+
8
+ Copyright (c) 2024 Repr
9
+
10
+ Permission is hereby granted, free of charge, to any person obtaining a copy
11
+ of this software and associated documentation files (the "Software"), to deal
12
+ in the Software without restriction, including without limitation the rights
13
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
+ copies of the Software, and to permit persons to whom the Software is
15
+ furnished to do so, subject to the following conditions:
16
+
17
+ The above copyright notice and this permission notice shall be included in all
18
+ copies or substantial portions of the Software.
19
+
20
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
+ SOFTWARE.
27
+
28
+ Project-URL: Homepage, https://repr.dev
29
+ Project-URL: Documentation, https://repr.dev/docs
30
+ Project-URL: Repository, https://github.com/repr-app/cli
31
+ Keywords: cli,developer,profile,git,analysis,repr
32
+ Classifier: Development Status :: 4 - Beta
33
+ Classifier: Environment :: Console
34
+ Classifier: Intended Audience :: Developers
35
+ Classifier: Operating System :: OS Independent
36
+ Classifier: Programming Language :: Python :: 3
37
+ Classifier: Programming Language :: Python :: 3.10
38
+ Classifier: Programming Language :: Python :: 3.11
39
+ Classifier: Programming Language :: Python :: 3.12
40
+ Classifier: Topic :: Software Development :: Version Control :: Git
41
+ Requires-Python: >=3.10
42
+ Description-Content-Type: text/markdown
43
+ License-File: LICENSE
44
+ Requires-Dist: typer>=0.9.0
45
+ Requires-Dist: rich>=13.0.0
46
+ Requires-Dist: gitpython>=3.1.0
47
+ Requires-Dist: pygments>=2.16.0
48
+ Requires-Dist: httpx>=0.25.0
49
+ Requires-Dist: openai>=1.0.0
50
+ Requires-Dist: keyring>=24.0.0
51
+ Provides-Extra: dev
52
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
53
+ Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
54
+ Requires-Dist: black>=23.0.0; extra == "dev"
55
+ Requires-Dist: ruff>=0.1.0; extra == "dev"
56
+ Dynamic: license-file
57
+
58
+ # Repr CLI
59
+
60
+ **Stop trying to remember what you did.** Your git history is already a career diary—repr unlocks it.
61
+
62
+ Turn commits into professional narratives for interviews, performance reviews, and career growth. Local-first, privacy-focused, works offline.
63
+
64
+ [![PyPI version](https://img.shields.io/pypi/v/repr-cli.svg)](https://pypi.org/project/repr-cli/)
65
+ [![Python versions](https://img.shields.io/pypi/pyversions/repr-cli.svg)](https://pypi.org/project/repr-cli/)
66
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
67
+ [![Build](https://github.com/repr-app/cli/actions/workflows/build-release.yml/badge.svg)](https://github.com/repr-app/cli/actions/workflows/build-release.yml)
68
+
69
+ ## Real Developers, Real Results
70
+
71
+ > *"I used repr to prep for my Meta interview in 30 minutes. Turned 2 years of commits into 8 STAR-format stories. Nailed every behavioral question."*
72
+ > **— Sarah, Senior Backend Engineer**
73
+
74
+ > *"Our sprint demos went from chaos to polished in 5 minutes. Just run `repr since '2 weeks ago'` and export. Stakeholders love it."*
75
+ > **— Marcus, Engineering Manager**
76
+
77
+ > *"I run repr in a fully air-gapped environment. Zero network calls, 100% local. It's the only tool I trust for this."*
78
+ > **— Alex, Defense Contractor**
79
+
80
+ ## Perfect For
81
+
82
+ - 🎯 **Interview Prep** — Generate STAR-format stories in 30 minutes instead of hours of commit archaeology
83
+ - 📊 **Performance Reviews** — Turn 6 months of work into quantified impact with one command
84
+ - 🚀 **Sprint Demos** — Professional changelogs for stakeholders in seconds
85
+ - 👔 **Weekly 1-on-1s** — Show up with specific examples instead of vague "I worked on stuff"
86
+ - 🔒 **Sensitive Work** — Air-gapped support for defense, healthcare, finance
87
+ - 💼 **Engineering Managers** — Prep for team reviews with per-developer summaries
88
+
89
+ ## Why Repr
90
+
91
+ ### Privacy First (Not an Afterthought)
92
+
93
+ - ✅ **Local-first by default** — Your repos, diffs, and stories stay on your machine in `~/.repr/`
94
+ - ✅ **Air-gapped ready** — Works in fully offline environments (defense, healthcare, finance approved)
95
+ - ✅ **Bring your own model** — Use local LLMs (Ollama) or your own API keys (OpenAI/Anthropic)
96
+ - ✅ **Privacy audit** — See exactly what data (if any) left your machine with `repr privacy audit`
97
+ - ✅ **OS keychain** — API keys never touch config files, stored in system keychain
98
+ - ✅ **Zero telemetry** — No tracking, no analytics, no silent uploads
99
+
100
+ ### Time Savings
101
+
102
+ | Task | Without repr | With repr | Savings |
103
+ |------|--------------|-----------|---------|
104
+ | Interview prep | 3-4 hours digging through commits | 30 minutes | **85% faster** |
105
+ | Performance review | 2 days remembering work | 5 minutes | **99% faster** |
106
+ | Sprint demo prep | 30 min asking "what did we ship?" | 2 minutes | **93% faster** |
107
+ | Weekly 1-on-1 prep | 15 min trying to remember | 30 seconds | **97% faster** |
108
+
109
+ ### vs. Alternatives
110
+
111
+ **vs. Manual brag documents:**
112
+ ❌ Requires discipline to maintain
113
+ ❌ Easy to forget to update
114
+ ❌ No structure or templates
115
+ ✅ repr: Automatic, retroactive, professional templates
116
+
117
+ **vs. GitHub commit history:**
118
+ ❌ Raw commits are cryptic
119
+ ❌ No narrative or context
120
+ ❌ Not interview/resume ready
121
+ ✅ repr: LLM transforms commits into narratives
122
+
123
+ **vs. Trying to remember at review time:**
124
+ ❌ Forget 80% of your work
125
+ ❌ Can't quantify impact
126
+ ❌ Miss your best stories
127
+ ✅ repr: Never forget, always quantified
128
+
129
+ ## Install
130
+
131
+ ### macOS / Linux (Homebrew)
132
+
133
+ ```bash
134
+ brew tap repr-app/tap
135
+ brew install repr
136
+ ```
137
+
138
+ ### Direct Download
139
+
140
+ Grab pre-built binaries for macOS, Linux, and Windows from the [latest release](https://github.com/repr-app/cli/releases/latest).
141
+
142
+ ### Python (pipx)
143
+
144
+ ```bash
145
+ pipx install repr-cli
146
+ ```
147
+
148
+ ## Quickstart (60 seconds)
149
+
150
+ ```bash
151
+ # 1) Scan your repos and set up local config
152
+ repr init ~/code
153
+
154
+ # 2) Generate stories from your recent work (local LLM)
155
+ repr generate --local
156
+
157
+ # 3) See what you created
158
+ repr stories
159
+ repr story view <id>
160
+ ```
161
+
162
+ ## Common workflows
163
+
164
+ For full step-by-step guides, see the [documentation](https://repr.dev/docs/cli/workflows/). Below are the quick happy-path snippets.
165
+
166
+ ### First-time setup
167
+
168
+ ```bash
169
+ repr init ~/code
170
+ repr week
171
+ repr generate --local
172
+ ```
173
+
174
+ [Full guide →](https://repr.dev/docs/cli/workflows/first-time-setup)
175
+
176
+ ### Daily workflow
177
+
178
+ ```bash
179
+ repr hooks install --all
180
+ repr generate --local
181
+ repr review
182
+ ```
183
+
184
+ [Full guide →](https://repr.dev/docs/cli/workflows/daily-workflow)
185
+
186
+ ### Weekly reflection
187
+
188
+ ```bash
189
+ repr week
190
+ repr generate --local
191
+ repr story edit <id>
192
+ repr story feature <id>
193
+ ```
194
+
195
+ [Full guide →](https://repr.dev/docs/cli/workflows/weekly-reflection)
196
+
197
+ ### Interview prep (STAR stories)
198
+
199
+ ```bash
200
+ repr generate --template interview --local
201
+ repr stories
202
+ repr story view <id>
203
+ ```
204
+
205
+ [Full guide →](https://repr.dev/docs/cli/workflows/interview-prep)
206
+
207
+ ### Publish your profile (optional)
208
+
209
+ ```bash
210
+ repr login
211
+ repr push --dry-run
212
+ repr push --all
213
+ repr profile link
214
+ ```
215
+
216
+ [Full guide →](https://repr.dev/docs/cli/workflows/publishing-profile)
217
+
218
+ ### Privacy-focused (local only)
219
+
220
+ ```bash
221
+ repr privacy lock-local
222
+ repr llm configure
223
+ repr llm test
224
+ repr generate --local
225
+ ```
226
+
227
+ [Full guide →](https://repr.dev/docs/cli/workflows/privacy-local-only)
228
+
229
+ ### Multi-device sync
230
+
231
+ ```bash
232
+ repr login
233
+ repr sync
234
+ ```
235
+
236
+ [Full guide →](https://repr.dev/docs/cli/workflows/multi-device-sync)
237
+
238
+ ### Troubleshooting
239
+
240
+ ```bash
241
+ repr status
242
+ repr mode
243
+ repr doctor
244
+ ```
245
+
246
+ [Full guide →](https://repr.dev/docs/cli/workflows/troubleshooting)
247
+
248
+ ## Configure your models
249
+
250
+ Your config lives at `~/.repr/config.json`.
251
+
252
+ ### Local LLM (Ollama/LocalAI)
253
+
254
+ ```bash
255
+ repr llm configure
256
+
257
+ # or set it manually:
258
+ repr config set llm.local_api_url http://localhost:11434/v1
259
+ repr config set llm.local_model llama3.2
260
+ ```
261
+
262
+ ### Bring your own API keys (BYOK)
263
+
264
+ ```bash
265
+ repr llm add openai
266
+ repr llm add anthropic
267
+ repr llm use byok:openai
268
+ ```
269
+
270
+ ### Privacy modes
271
+
272
+ | Mode | Typical command | What happens |
273
+ |------|-----------------|--------------|
274
+ | **Local LLM** | `repr generate --local` | Talks only to your local endpoint. |
275
+ | **BYOK** | `repr llm add <provider>` | Calls your provider directly with your key. |
276
+ | **Cloud** | `repr generate --cloud` | Requires login; you initiate all network calls. |
277
+ | **Offline** | `repr week` / `repr stories` | Pure local operations. |
278
+
279
+ ## Command help
280
+
281
+ For the full flag reference:
282
+
283
+ ```bash
284
+ repr --help
285
+ repr <command> --help
286
+ ```
287
+
288
+ ## Enterprise & Compliance
289
+
290
+ ### Air-Gapped Environments
291
+
292
+ repr works in fully offline, air-gapped environments:
293
+
294
+ ```bash
295
+ # 1. Install repr (transfer binary via USB)
296
+ # 2. Install Ollama and download models offline
297
+ # 3. Lock to local-only permanently
298
+ repr privacy lock-local --permanent
299
+
300
+ # 4. Generate stories (zero network calls)
301
+ repr generate --local
302
+ ```
303
+
304
+ **Use cases:**
305
+ - Defense contractors (classified environments)
306
+ - Healthcare (HIPAA compliance)
307
+ - Finance (SOX/PCI requirements)
308
+ - Stealth startups (pre-launch confidentiality)
309
+
310
+ ### Privacy Audit Trail
311
+
312
+ See exactly what data left your machine:
313
+
314
+ ```bash
315
+ repr privacy audit --days 30
316
+ ```
317
+
318
+ Output:
319
+ ```
320
+ Network Activity Audit (Last 30 days)
321
+
322
+ No network activity detected.
323
+
324
+ Local operations:
325
+ • 143 commits analyzed
326
+ • 23 stories generated
327
+ • 0 cloud syncs
328
+ • 0 API calls to repr.dev
329
+
330
+ Mode: LOCAL_ONLY (locked)
331
+ ```
332
+
333
+ Perfect for security audits and compliance reviews.
334
+
335
+ ### BYOK (Bring Your Own Key)
336
+
337
+ Use your own API keys, stored securely:
338
+
339
+ ```bash
340
+ # Keys stored in OS keychain (never in config files)
341
+ repr llm add openai
342
+ repr llm add anthropic
343
+
344
+ # Calls go directly to your provider, not repr.dev
345
+ repr generate # Uses your OpenAI key
346
+ ```
347
+
348
+ - ✅ Keys stored in macOS Keychain / Windows Credential Manager / Linux Secret Service
349
+ - ✅ repr.dev never sees your keys or data
350
+ - ✅ Full control over costs and models
351
+
352
+ ## Documentation
353
+
354
+ - **[Full Documentation](https://repr.dev/docs)** — Comprehensive guides
355
+ - **[USER_WORKFLOWS.md](docs/USER_WORKFLOWS.md)** — 10 detailed workflow examples
356
+ - **[Privacy Model](https://repr.dev/docs/concepts/privacy-model)** — How data is protected
357
+
358
+ ## License
359
+
360
+ MIT License — see [LICENSE](LICENSE).
361
+
362
+ ---
363
+
364
+ **🚀 Ready to unlock your git history?**
365
+
366
+ ```bash
367
+ brew install repr
368
+ repr init ~/code
369
+ repr generate --local
370
+ ```
@@ -1,8 +1,8 @@
1
- repr/__init__.py,sha256=5Lyw-m_Us0430M83D0ku-LzaZMoU9JnhjsmhPn09Z6U,269
1
+ repr/__init__.py,sha256=qbD2NcYyw-BtP4j51T_luaVaN_o78LdHAEneVIVKA_4,446
2
2
  repr/__main__.py,sha256=M0ECtxOrmmYoYrYV5XI9UhDnOjWThxn0-PPysKs3RT0,127
3
3
  repr/api.py,sha256=Rr6MEUkjf7LJ6TcxbdVstfpUM_mDpTKhllbFwy9jK2w,11893
4
4
  repr/auth.py,sha256=-tqd2MMgFlowbhAqLHeSnVpDBkintkZ4kmPDZmczQFU,11682
5
- repr/cli.py,sha256=67qBrsoV6VaBo7DcynJ8U9LGsYyPtIDGEQyCi4Etf7k,73990
5
+ repr/cli.py,sha256=X0oeeaJ8ygH6QGYJw8VyislEyjyDW0KSw24JPY1P3cw,77291
6
6
  repr/config.py,sha256=GZf5ucrBFIfOo9UtKE-DAZ9Ns1suAKG0jvUAY64oGIc,30601
7
7
  repr/discovery.py,sha256=2RYmJleqV7TbxIMMYP2izkEBUeKH7U1F-U4KAUlUNww,14816
8
8
  repr/doctor.py,sha256=6cI21xXIlTNRzHi2fRfHpm__erO8jBZc6vge8-29ip4,13404
@@ -13,12 +13,13 @@ repr/llm.py,sha256=gTYloz7ONTpFQm73YFIVGOrjsk0iyocMTM4YkF4s4xI,14598
13
13
  repr/openai_analysis.py,sha256=-9POoLF6B15_oBKJw_CjKH2DuWEIgIlOmtyjS4Gjbck,25764
14
14
  repr/privacy.py,sha256=HITso2pzwN8R0Izh3SjUsrzcpjVw5bJEhbippAGeMiY,9795
15
15
  repr/storage.py,sha256=72nfFcR2Y98vpSjaO7zVHisq_Ln2UrHmGyDhEqEmDjU,14863
16
+ repr/telemetry.py,sha256=7ANJJUB4Dd7A_HFVPqc92Gy77ruREzlmgayFQkwuC9s,6961
16
17
  repr/templates.py,sha256=RQl7nUfy8IK6QFKzgpcebkBbQH0E_brbYh83pzym1TM,6530
17
18
  repr/tools.py,sha256=QoGeti5Sye2wVuE-7UPxd_TDNXoen-xYfsFoT9rYRPs,20737
18
19
  repr/ui.py,sha256=5jycUT-5Q0az4FFUzgarI8CfVAEEUPSEsT24Fad2kG8,3994
19
- repr_cli-0.2.5.dist-info/licenses/LICENSE,sha256=tI16Ry3IQhjsde6weJ_in6czzWW2EF4Chz1uicyDLAA,1061
20
- repr_cli-0.2.5.dist-info/METADATA,sha256=8967iE8dOQfpmUUm9CBGgu4VBpiRKwtdOSSpk_PusbQ,9999
21
- repr_cli-0.2.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
22
- repr_cli-0.2.5.dist-info/entry_points.txt,sha256=SJoKgNB-fRy6O2T_lztFr9T3ND_BQl0ijWxNW-J7dUU,38
23
- repr_cli-0.2.5.dist-info/top_level.txt,sha256=LNgPqdJPQnlicRve7uzI4a6rEUdcxHrNkUq_2w7eeiA,5
24
- repr_cli-0.2.5.dist-info/RECORD,,
20
+ repr_cli-0.2.7.dist-info/licenses/LICENSE,sha256=tI16Ry3IQhjsde6weJ_in6czzWW2EF4Chz1uicyDLAA,1061
21
+ repr_cli-0.2.7.dist-info/METADATA,sha256=mYlev_fipoCBpxgh9Hp62Dp--lilxSQYltXVJyd9LRI,10898
22
+ repr_cli-0.2.7.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
23
+ repr_cli-0.2.7.dist-info/entry_points.txt,sha256=SJoKgNB-fRy6O2T_lztFr9T3ND_BQl0ijWxNW-J7dUU,38
24
+ repr_cli-0.2.7.dist-info/top_level.txt,sha256=LNgPqdJPQnlicRve7uzI4a6rEUdcxHrNkUq_2w7eeiA,5
25
+ repr_cli-0.2.7.dist-info/RECORD,,
@@ -1,283 +0,0 @@
1
- Metadata-Version: 2.4
2
- Name: repr-cli
3
- Version: 0.2.5
4
- Summary: A beautiful, privacy-first CLI that analyzes your code repositories and generates a compelling developer profile
5
- Author-email: Repr <hello@repr.dev>
6
- License: MIT License
7
-
8
- Copyright (c) 2024 Repr
9
-
10
- Permission is hereby granted, free of charge, to any person obtaining a copy
11
- of this software and associated documentation files (the "Software"), to deal
12
- in the Software without restriction, including without limitation the rights
13
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14
- copies of the Software, and to permit persons to whom the Software is
15
- furnished to do so, subject to the following conditions:
16
-
17
- The above copyright notice and this permission notice shall be included in all
18
- copies or substantial portions of the Software.
19
-
20
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
- SOFTWARE.
27
-
28
- Project-URL: Homepage, https://repr.dev
29
- Project-URL: Documentation, https://repr.dev/docs
30
- Project-URL: Repository, https://github.com/repr-app/cli
31
- Keywords: cli,developer,profile,git,analysis,repr
32
- Classifier: Development Status :: 4 - Beta
33
- Classifier: Environment :: Console
34
- Classifier: Intended Audience :: Developers
35
- Classifier: Operating System :: OS Independent
36
- Classifier: Programming Language :: Python :: 3
37
- Classifier: Programming Language :: Python :: 3.10
38
- Classifier: Programming Language :: Python :: 3.11
39
- Classifier: Programming Language :: Python :: 3.12
40
- Classifier: Topic :: Software Development :: Version Control :: Git
41
- Requires-Python: >=3.10
42
- Description-Content-Type: text/markdown
43
- License-File: LICENSE
44
- Requires-Dist: typer>=0.9.0
45
- Requires-Dist: rich>=13.0.0
46
- Requires-Dist: gitpython>=3.1.0
47
- Requires-Dist: pygments>=2.16.0
48
- Requires-Dist: httpx>=0.25.0
49
- Requires-Dist: openai>=1.0.0
50
- Requires-Dist: keyring>=24.0.0
51
- Provides-Extra: dev
52
- Requires-Dist: pytest>=7.0.0; extra == "dev"
53
- Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
54
- Requires-Dist: black>=23.0.0; extra == "dev"
55
- Requires-Dist: ruff>=0.1.0; extra == "dev"
56
- Dynamic: license-file
57
-
58
- # Repr CLI
59
-
60
- A local-first developer tool that turns your git commit history into professional narratives.
61
-
62
- **Privacy Guarantee:** Zero data leaves your machine unless you explicitly publish. Your keys, your models, your data.
63
-
64
- [![PyPI version](https://img.shields.io/pypi/v/repr-cli.svg)](https://pypi.org/project/repr-cli/)
65
- [![Python versions](https://img.shields.io/pypi/pyversions/repr-cli.svg)](https://pypi.org/project/repr-cli/)
66
- [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
67
- [![Build](https://github.com/repr-app/cli/actions/workflows/build-release.yml/badge.svg)](https://github.com/repr-app/cli/actions/workflows/build-release.yml)
68
-
69
- ## Philosophy
70
-
71
- Repr is built on three core principles:
72
-
73
- 1. **Local-First:** Analysis happens on your machine. You own the output.
74
- 2. **Bring Your Own Keys:** Use your own OpenAI API key or a local LLM (Ollama, etc.). We don't sit in the middle.
75
- 3. **Opt-In Cloud:** Publishing to `repr.dev` is strictly optional. Use it for backup or sharing, or ignore it entirely.
76
-
77
- ## Installation
78
-
79
- ### macOS / Linux (Homebrew)
80
- ```bash
81
- brew tap repr-app/tap
82
- brew install repr
83
- ```
84
-
85
- ### Direct Download
86
- Download pre-built binaries for macOS, Linux, and Windows from the [latest release](https://github.com/repr-app/cli/releases/latest).
87
-
88
- ### Python (pipx)
89
- ```bash
90
- pipx install repr-cli
91
- ```
92
-
93
- ## The Local Workflow
94
-
95
- You can use Repr entirely offline or with your own API keys. No account required.
96
-
97
- ### 1. Initialize
98
- Scan for repositories and set up local config.
99
-
100
- ```bash
101
- repr init ~/code
102
- ```
103
-
104
- ### 2. Generate stories
105
- Create stories from your commit history.
106
-
107
- ```bash
108
- # Using a local LLM (e.g., Ollama running Llama 3)
109
- repr generate --local
110
-
111
- # Or configure your own API key (BYOK)
112
- repr llm add openai
113
- repr generate
114
-
115
- # Or use cloud (requires login)
116
- repr login
117
- repr generate --cloud
118
- ```
119
-
120
- This reads your git log, diffs, and file context to generate meaningful summaries of your work. All processing happens locally or directly against the API you specify.
121
-
122
- ### 3. View your stories
123
- Inspect the generated stories stored on your machine.
124
-
125
- ```bash
126
- repr stories
127
- repr story view <id>
128
- ```
129
-
130
- Output is stored in `~/.repr/`, staying fully under your control.
131
-
132
- ### 4. Track multiple repositories
133
- Configure Repr to watch multiple projects.
134
-
135
- ```bash
136
- repr repos add ~/code/work-project
137
- repr repos add ~/code/side-project
138
- ```
139
-
140
- ## Optional: Cloud & Publishing
141
-
142
- If you want convenience without managing your own API keys, you can use Repr's backend. It processes your code with proprietary models but operates under a **zero data retention (ZDR) policy**—no logging, no storage beyond ephemeral processing.
143
-
144
- Alternatively, use the cloud for backup and sharing: sync your locally generated stories or create a public profile (e.g., `repr.dev/yourname`).
145
-
146
- **This is the only time data leaves your machine.**
147
-
148
- ### 1. Authenticate
149
- ```bash
150
- repr login
151
- ```
152
-
153
- ### 2. Push stories
154
- Publish your locally generated stories to your profile.
155
-
156
- ```bash
157
- repr push
158
- ```
159
-
160
- ### 3. Sync across devices
161
- Keep your stories in sync.
162
-
163
- ```bash
164
- repr sync
165
- ```
166
-
167
- ### 4. Automate (Optional)
168
- Install git hooks to automatically track new commits as you work.
169
-
170
- ```bash
171
- repr hooks install --all
172
- ```
173
-
174
- ## Configuration
175
-
176
- Repr respects standard environment variables and local configuration.
177
-
178
- **Config file:** `~/.repr/config.json`
179
-
180
- ### Using Local LLMs (Ollama, LocalAI)
181
- Point Repr to any OpenAI-compatible endpoint:
182
-
183
- ```bash
184
- repr llm configure
185
- # Or manually:
186
- repr config set llm.local_api_url http://localhost:11434/v1
187
- repr config set llm.local_model llama3.2
188
- ```
189
-
190
- ### Bring Your Own Key (BYOK)
191
- Configure your own API keys:
192
-
193
- ```bash
194
- repr llm add openai
195
- repr llm add anthropic
196
- repr llm use byok:openai
197
- ```
198
-
199
- ### Privacy Modes
200
-
201
- | Mode | Command | Behavior |
202
- |------|---------|----------|
203
- | **Local LLM** | `repr generate --local` | Uses your local LLM endpoint (Ollama, etc.). Zero external network calls. |
204
- | **BYOK** | `repr llm add <provider>` | Configure your own API keys (OpenAI, Anthropic, etc.). Direct connection, no middleman. |
205
- | **Cloud** | `repr generate --cloud` | **(Requires Login)** Uses Repr's backend. Sends metadata + diffs. Zero data retention (ZDR) policy—no logging, ephemeral processing only. |
206
- | **Offline** | Local operations only | Works without network. View stories, repos, export profiles. |
207
-
208
- ## Command Reference
209
-
210
- ### Getting Started
211
- - `repr init [path]` - Initialize repr, scan for repositories
212
- - `repr login` - Authenticate with repr.dev
213
- - `repr whoami` - Show current user
214
- - `repr logout` - Sign out
215
- - `repr status` - Show overall status and health
216
- - `repr mode` - Show current execution mode
217
- - `repr doctor` - Run health checks and diagnostics
218
-
219
- ### Generation & Analysis
220
- - `repr generate [--local|--cloud]` - Generate stories from commits
221
- - `--repo <path>` - Generate for specific repo
222
- - `--commits <sha1,sha2>` - Generate from specific commits
223
- - `--template <name>` - Use template (resume, changelog, narrative, interview)
224
- - `--dry-run` - Preview what would be sent
225
- - `repr week [--save]` - Show work from this week
226
- - `repr since <date> [--save]` - Show work since a date
227
- - `repr standup [--days N]` - Quick summary for standup
228
-
229
- ### Stories
230
- - `repr stories [--repo NAME] [--needs-review]` - List all stories
231
- - `repr story <action> <id>` - Manage a story (view, edit, delete, hide, feature)
232
- - `repr review` - Interactive review workflow
233
- - `repr commits [--repo NAME] [--limit N]` - List recent commits
234
-
235
- ### Cloud Operations
236
- - `repr push [--story ID] [--all]` - Publish stories to repr.dev
237
- - `repr sync` - Sync stories across devices
238
- - `repr pull` - Pull remote stories to local
239
-
240
- ### Repositories
241
- - `repr repos [list|add|remove|pause|resume] [path]` - Manage tracked repos
242
-
243
- ### Git Hooks
244
- - `repr hooks install [--all|--repo PATH]` - Install post-commit hooks
245
- - `repr hooks remove [--all|--repo PATH]` - Remove hooks
246
- - `repr hooks status` - Show hook status
247
-
248
- ### LLM Configuration
249
- - `repr llm add <provider>` - Configure BYOK provider (openai, anthropic, groq, together)
250
- - `repr llm remove <provider>` - Remove BYOK provider
251
- - `repr llm use <mode>` - Set default mode (local, cloud, byok:<provider>)
252
- - `repr llm configure` - Configure local LLM interactively
253
- - `repr llm test` - Test LLM connection
254
-
255
- ### Privacy
256
- - `repr privacy explain` - Show privacy guarantees
257
- - `repr privacy audit [--days N]` - Show what data was sent to cloud
258
- - `repr privacy lock-local [--permanent]` - Disable cloud features
259
- - `repr privacy unlock-local` - Re-enable cloud features
260
-
261
- ### Configuration
262
- - `repr config show [key]` - Display configuration
263
- - `repr config set <key> <value>` - Set configuration value
264
- - `repr config edit` - Open config in $EDITOR
265
-
266
- ### Data Management
267
- - `repr data` - Show local storage info
268
- - `repr data backup [--output FILE]` - Backup all local data
269
- - `repr data restore <file> [--merge]` - Restore from backup
270
- - `repr data clear-cache` - Clear local cache
271
-
272
- ### Profile
273
- - `repr profile` - View profile
274
- - `repr profile update [--preview]` - Generate/update profile from stories
275
- - `repr profile set-bio <text>` - Set profile bio
276
- - `repr profile set-location <text>` - Set location
277
- - `repr profile set-available <bool>` - Set availability status
278
- - `repr profile export [--format FORMAT]` - Export profile (md, json)
279
- - `repr profile link` - Get shareable profile link
280
-
281
- ## License
282
-
283
- MIT License - see [LICENSE](LICENSE).