repr-cli 0.2.15__py3-none-any.whl → 0.2.17__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 +1 -1
- repr/api.py +363 -62
- repr/auth.py +47 -38
- repr/change_synthesis.py +478 -0
- repr/cli.py +4103 -267
- repr/config.py +119 -11
- repr/configure.py +889 -0
- repr/cron.py +419 -0
- repr/dashboard/__init__.py +9 -0
- repr/dashboard/build.py +126 -0
- repr/dashboard/dist/assets/index-BYFVbEev.css +1 -0
- repr/dashboard/dist/assets/index-BrrhyJFO.css +1 -0
- repr/dashboard/dist/assets/index-CcEg74ts.js +270 -0
- repr/dashboard/dist/assets/index-Cerc-iA_.js +377 -0
- repr/dashboard/dist/assets/index-CjVcBW2L.css +1 -0
- repr/dashboard/dist/assets/index-Dfl3mR5E.js +377 -0
- repr/dashboard/dist/favicon.svg +4 -0
- repr/dashboard/dist/index.html +14 -0
- repr/dashboard/manager.py +234 -0
- repr/dashboard/server.py +1298 -0
- repr/db.py +980 -0
- repr/hooks.py +3 -2
- repr/loaders/__init__.py +22 -0
- repr/loaders/base.py +156 -0
- repr/loaders/claude_code.py +287 -0
- repr/loaders/clawdbot.py +313 -0
- repr/loaders/gemini_antigravity.py +381 -0
- repr/mcp_server.py +1196 -0
- repr/models.py +503 -0
- repr/openai_analysis.py +25 -0
- repr/session_extractor.py +481 -0
- repr/storage.py +360 -0
- repr/story_synthesis.py +1296 -0
- repr/templates.py +68 -4
- repr/timeline.py +710 -0
- repr/tools.py +17 -8
- {repr_cli-0.2.15.dist-info → repr_cli-0.2.17.dist-info}/METADATA +50 -10
- repr_cli-0.2.17.dist-info/RECORD +52 -0
- {repr_cli-0.2.15.dist-info → repr_cli-0.2.17.dist-info}/WHEEL +1 -1
- {repr_cli-0.2.15.dist-info → repr_cli-0.2.17.dist-info}/entry_points.txt +1 -0
- repr_cli-0.2.15.dist-info/RECORD +0 -26
- {repr_cli-0.2.15.dist-info → repr_cli-0.2.17.dist-info}/licenses/LICENSE +0 -0
- {repr_cli-0.2.15.dist-info → repr_cli-0.2.17.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>repr dashboard</title>
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-Cerc-iA_.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-BYFVbEev.css">
|
|
10
|
+
</head>
|
|
11
|
+
<body>
|
|
12
|
+
<div id="app"></div>
|
|
13
|
+
</body>
|
|
14
|
+
</html>
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Dashboard version manager.
|
|
3
|
+
|
|
4
|
+
Handles downloading and updating the Vue dashboard from GitHub releases.
|
|
5
|
+
Falls back to bundled dist/ if download unavailable.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import json
|
|
9
|
+
import shutil
|
|
10
|
+
import tarfile
|
|
11
|
+
import tempfile
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from urllib.request import urlopen, Request
|
|
14
|
+
from urllib.error import URLError
|
|
15
|
+
|
|
16
|
+
# Configuration
|
|
17
|
+
GITHUB_REPO = "everdraft/repr-dashboard" # Update with actual repo
|
|
18
|
+
RELEASE_URL = f"https://api.github.com/repos/{GITHUB_REPO}/releases/latest"
|
|
19
|
+
DOWNLOAD_TIMEOUT = 30 # seconds
|
|
20
|
+
|
|
21
|
+
# Paths
|
|
22
|
+
USER_DASHBOARD_DIR = Path.home() / ".repr" / "dashboard"
|
|
23
|
+
BUNDLED_DASHBOARD_DIR = Path(__file__).parent / "dist"
|
|
24
|
+
VERSION_FILE = "version.json"
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def get_user_dashboard_path() -> Path:
|
|
28
|
+
"""Get path to user-installed dashboard, or None if not installed."""
|
|
29
|
+
version_file = USER_DASHBOARD_DIR / VERSION_FILE
|
|
30
|
+
index_file = USER_DASHBOARD_DIR / "index.html"
|
|
31
|
+
|
|
32
|
+
if version_file.exists() and index_file.exists():
|
|
33
|
+
return USER_DASHBOARD_DIR
|
|
34
|
+
return None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def get_bundled_dashboard_path() -> Path:
|
|
38
|
+
"""Get path to bundled dashboard."""
|
|
39
|
+
if (BUNDLED_DASHBOARD_DIR / "index.html").exists():
|
|
40
|
+
return BUNDLED_DASHBOARD_DIR
|
|
41
|
+
return None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def get_dashboard_path() -> Path:
|
|
45
|
+
"""
|
|
46
|
+
Get the best available dashboard path.
|
|
47
|
+
|
|
48
|
+
Priority:
|
|
49
|
+
1. User-installed dashboard (~/.repr/dashboard/) if exists
|
|
50
|
+
2. Bundled dashboard (repr/dashboard/dist/) as fallback
|
|
51
|
+
|
|
52
|
+
Returns None if neither exists.
|
|
53
|
+
"""
|
|
54
|
+
user_path = get_user_dashboard_path()
|
|
55
|
+
if user_path:
|
|
56
|
+
return user_path
|
|
57
|
+
|
|
58
|
+
return get_bundled_dashboard_path()
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def get_installed_version() -> str | None:
|
|
62
|
+
"""Get version of user-installed dashboard."""
|
|
63
|
+
version_file = USER_DASHBOARD_DIR / VERSION_FILE
|
|
64
|
+
if not version_file.exists():
|
|
65
|
+
return None
|
|
66
|
+
|
|
67
|
+
try:
|
|
68
|
+
data = json.loads(version_file.read_text())
|
|
69
|
+
return data.get("version")
|
|
70
|
+
except Exception:
|
|
71
|
+
return None
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def get_bundled_version() -> str | None:
|
|
75
|
+
"""Get version of bundled dashboard."""
|
|
76
|
+
version_file = BUNDLED_DASHBOARD_DIR / VERSION_FILE
|
|
77
|
+
if not version_file.exists():
|
|
78
|
+
return None
|
|
79
|
+
|
|
80
|
+
try:
|
|
81
|
+
data = json.loads(version_file.read_text())
|
|
82
|
+
return data.get("version")
|
|
83
|
+
except Exception:
|
|
84
|
+
return None
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def get_latest_release_info() -> dict | None:
|
|
88
|
+
"""
|
|
89
|
+
Fetch latest release info from GitHub.
|
|
90
|
+
|
|
91
|
+
Returns dict with 'version' and 'download_url' or None if unavailable.
|
|
92
|
+
"""
|
|
93
|
+
try:
|
|
94
|
+
req = Request(
|
|
95
|
+
RELEASE_URL,
|
|
96
|
+
headers={"Accept": "application/vnd.github.v3+json", "User-Agent": "repr-cli"}
|
|
97
|
+
)
|
|
98
|
+
with urlopen(req, timeout=10) as resp:
|
|
99
|
+
data = json.loads(resp.read().decode())
|
|
100
|
+
|
|
101
|
+
version = data.get("tag_name", "").lstrip("v")
|
|
102
|
+
|
|
103
|
+
# Find the tarball asset
|
|
104
|
+
download_url = None
|
|
105
|
+
for asset in data.get("assets", []):
|
|
106
|
+
if asset["name"].endswith(".tar.gz"):
|
|
107
|
+
download_url = asset["browser_download_url"]
|
|
108
|
+
break
|
|
109
|
+
|
|
110
|
+
# Fallback to source tarball if no asset
|
|
111
|
+
if not download_url:
|
|
112
|
+
download_url = data.get("tarball_url")
|
|
113
|
+
|
|
114
|
+
if version and download_url:
|
|
115
|
+
return {"version": version, "download_url": download_url}
|
|
116
|
+
except (URLError, json.JSONDecodeError, KeyError):
|
|
117
|
+
pass
|
|
118
|
+
|
|
119
|
+
return None
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def download_and_install(download_url: str, version: str) -> bool:
|
|
123
|
+
"""
|
|
124
|
+
Download and install dashboard from URL.
|
|
125
|
+
|
|
126
|
+
Returns True on success, False on failure.
|
|
127
|
+
"""
|
|
128
|
+
try:
|
|
129
|
+
# Create temp directory for download
|
|
130
|
+
with tempfile.TemporaryDirectory() as tmpdir:
|
|
131
|
+
tmpdir_path = Path(tmpdir)
|
|
132
|
+
tarball_path = tmpdir_path / "dashboard.tar.gz"
|
|
133
|
+
|
|
134
|
+
# Download
|
|
135
|
+
print(f" Downloading dashboard v{version}...")
|
|
136
|
+
req = Request(download_url, headers={"User-Agent": "repr-cli"})
|
|
137
|
+
with urlopen(req, timeout=DOWNLOAD_TIMEOUT) as resp:
|
|
138
|
+
tarball_path.write_bytes(resp.read())
|
|
139
|
+
|
|
140
|
+
# Extract
|
|
141
|
+
print(" Extracting...")
|
|
142
|
+
extract_dir = tmpdir_path / "extracted"
|
|
143
|
+
extract_dir.mkdir()
|
|
144
|
+
|
|
145
|
+
with tarfile.open(tarball_path, "r:gz") as tar:
|
|
146
|
+
tar.extractall(extract_dir)
|
|
147
|
+
|
|
148
|
+
# Find the dist directory (might be nested)
|
|
149
|
+
dist_dir = None
|
|
150
|
+
for item in extract_dir.rglob("index.html"):
|
|
151
|
+
dist_dir = item.parent
|
|
152
|
+
break
|
|
153
|
+
|
|
154
|
+
if not dist_dir:
|
|
155
|
+
print(" Error: Could not find index.html in archive")
|
|
156
|
+
return False
|
|
157
|
+
|
|
158
|
+
# Install to user directory
|
|
159
|
+
USER_DASHBOARD_DIR.parent.mkdir(parents=True, exist_ok=True)
|
|
160
|
+
|
|
161
|
+
if USER_DASHBOARD_DIR.exists():
|
|
162
|
+
shutil.rmtree(USER_DASHBOARD_DIR)
|
|
163
|
+
|
|
164
|
+
shutil.copytree(dist_dir, USER_DASHBOARD_DIR)
|
|
165
|
+
|
|
166
|
+
# Write version file
|
|
167
|
+
version_data = {"version": version}
|
|
168
|
+
(USER_DASHBOARD_DIR / VERSION_FILE).write_text(json.dumps(version_data))
|
|
169
|
+
|
|
170
|
+
print(f" Dashboard v{version} installed to {USER_DASHBOARD_DIR}")
|
|
171
|
+
return True
|
|
172
|
+
|
|
173
|
+
except Exception as e:
|
|
174
|
+
print(f" Error installing dashboard: {e}")
|
|
175
|
+
return False
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def check_for_updates(quiet: bool = False) -> bool:
|
|
179
|
+
"""
|
|
180
|
+
Check for dashboard updates and install if available.
|
|
181
|
+
|
|
182
|
+
Returns True if an update was installed.
|
|
183
|
+
"""
|
|
184
|
+
installed = get_installed_version()
|
|
185
|
+
|
|
186
|
+
release = get_latest_release_info()
|
|
187
|
+
if not release:
|
|
188
|
+
if not quiet:
|
|
189
|
+
print(" Could not check for dashboard updates (offline?)")
|
|
190
|
+
return False
|
|
191
|
+
|
|
192
|
+
latest = release["version"]
|
|
193
|
+
|
|
194
|
+
# Compare versions (simple string comparison, assumes semver)
|
|
195
|
+
if installed and installed >= latest:
|
|
196
|
+
if not quiet:
|
|
197
|
+
print(f" Dashboard is up to date (v{installed})")
|
|
198
|
+
return False
|
|
199
|
+
|
|
200
|
+
if not quiet:
|
|
201
|
+
if installed:
|
|
202
|
+
print(f" New dashboard version available: v{installed} -> v{latest}")
|
|
203
|
+
else:
|
|
204
|
+
print(f" Installing dashboard v{latest}...")
|
|
205
|
+
|
|
206
|
+
return download_and_install(release["download_url"], latest)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def ensure_dashboard() -> Path:
|
|
210
|
+
"""
|
|
211
|
+
Ensure dashboard is available, downloading if needed.
|
|
212
|
+
|
|
213
|
+
Returns path to dashboard directory.
|
|
214
|
+
Raises RuntimeError if no dashboard available.
|
|
215
|
+
"""
|
|
216
|
+
# First, try user-installed
|
|
217
|
+
user_path = get_user_dashboard_path()
|
|
218
|
+
if user_path:
|
|
219
|
+
return user_path
|
|
220
|
+
|
|
221
|
+
# Try to download latest
|
|
222
|
+
release = get_latest_release_info()
|
|
223
|
+
if release:
|
|
224
|
+
if download_and_install(release["download_url"], release["version"]):
|
|
225
|
+
return USER_DASHBOARD_DIR
|
|
226
|
+
|
|
227
|
+
# Fall back to bundled
|
|
228
|
+
bundled_path = get_bundled_dashboard_path()
|
|
229
|
+
if bundled_path:
|
|
230
|
+
return bundled_path
|
|
231
|
+
|
|
232
|
+
raise RuntimeError(
|
|
233
|
+
"No dashboard available. Bundled dashboard not found and could not download from GitHub."
|
|
234
|
+
)
|