methodproof 0.7.23__tar.gz → 0.7.25__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.
- {methodproof-0.7.23 → methodproof-0.7.25}/CHANGELOG.md +12 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/PKG-INFO +1 -1
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/store.py +21 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/tui/start.py +27 -15
- {methodproof-0.7.23 → methodproof-0.7.25}/pyproject.toml +1 -1
- {methodproof-0.7.23 → methodproof-0.7.25}/.github/workflows/ci.yml +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/.gitignore +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/LICENSE +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/README.md +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/__init__.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/__main__.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/_daemon.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/agents/__init__.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/agents/base.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/agents/music.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/agents/terminal.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/agents/watcher.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/analysis.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/binding.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/bip39.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/bridge.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/cli.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/config.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/crypto.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/e2e.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/graph.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/hook.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/hooks/__init__.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/hooks/claude_code.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/hooks/claude_code.sh +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/hooks/cline_hook.sh +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/hooks/codex_hook.sh +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/hooks/gemini_hook.sh +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/hooks/install.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/hooks/kiro_hook.sh +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/hooks/mcp_register.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/hooks/openclaw/HOOK.md +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/hooks/openclaw/handler.ts +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/hooks/openclaw_install.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/hooks/opencode_plugin.js +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/hooks/wrappers.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/integrity.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/kdf.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/keychain.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/live.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/lock.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/mcp.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/migrate_db.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/proxy.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/proxy_daemon.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/repos.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/skills/methodproof/SKILL.md +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/sync.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/tui/__init__.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/tui/consent.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/tui/init.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/tui/log.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/tui/login_success.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/tui/review.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/tui/status.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/tui/theme.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/viewer.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/methodproof/wordlist.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/test_windows_compat.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/tests/__init__.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/tests/conftest.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/tests/test_analysis.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/tests/test_cli_auth.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/tests/test_cli_config.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/tests/test_cli_helpers.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/tests/test_cli_session.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/tests/test_cli_share.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/tests/test_cli_start.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/tests/test_cli_update.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/tests/test_e2e_integration.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/tests/test_graph.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/tests/test_hooks.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/tests/test_live.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/tests/test_openclaw_hooks.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/tests/test_profiles.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/tests/test_security.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/tests/test_store.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/tests/test_sync.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/tests/test_viewer.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/tests/test_wrappers.py +0 -0
- {methodproof-0.7.23 → methodproof-0.7.25}/uv.lock +0 -0
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.7.25] — 2026-04-12
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- **TUI event metadata never rendered** — `_fmt_meta` read fields like `path`, `command`, `message` from the top-level event dict, but they live inside the `metadata` sub-dict. All event-type formatters now read from `ev["metadata"]`.
|
|
7
|
+
- **Tier hardcoded as "Pro" in session bar** — decoded from JWT on mount; now shows actual account type (Free / Basic / Pro / Team).
|
|
8
|
+
- **Unused `Worker`/`WorkerState` imports** removed from `tui/start.py`.
|
|
9
|
+
|
|
10
|
+
## [0.7.24] — 2026-04-12
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- **TUI event feed was always empty** — `_poll_events` called `store.get_session_events` which did not exist; `except Exception: return` silently swallowed the `AttributeError`. Added `get_session_events(session_id, after_id="")` to store — uses SQLite `rowid` for monotonic pagination so the TUI feed populates in real time. Also surfaced poll errors to the Textual log instead of swallowing them.
|
|
14
|
+
|
|
3
15
|
## [0.7.23] — 2026-04-12
|
|
4
16
|
|
|
5
17
|
### Fixed
|
|
@@ -247,6 +247,27 @@ def get_events(session_id: str) -> list[dict[str, Any]]:
|
|
|
247
247
|
return result
|
|
248
248
|
|
|
249
249
|
|
|
250
|
+
def get_session_events(session_id: str, after_id: str = "") -> list[dict[str, Any]]:
|
|
251
|
+
"""Return events for session, optionally after a given event ID (for TUI polling)."""
|
|
252
|
+
db = _db()
|
|
253
|
+
if after_id:
|
|
254
|
+
row = db.execute("SELECT rowid FROM events WHERE id = ?", (after_id,)).fetchone()
|
|
255
|
+
after_rowid = row[0] if row else 0
|
|
256
|
+
else:
|
|
257
|
+
after_rowid = 0
|
|
258
|
+
rows = db.execute(
|
|
259
|
+
"SELECT rowid, * FROM events WHERE session_id = ? AND rowid > ? ORDER BY rowid",
|
|
260
|
+
(session_id, after_rowid),
|
|
261
|
+
).fetchall()
|
|
262
|
+
result = []
|
|
263
|
+
for r in rows:
|
|
264
|
+
d = dict(r)
|
|
265
|
+
d["ts"] = d.pop("timestamp", 0)
|
|
266
|
+
d["metadata"] = _decompress_meta(d["metadata"])
|
|
267
|
+
result.append(d)
|
|
268
|
+
return result
|
|
269
|
+
|
|
270
|
+
|
|
250
271
|
def get_graph(session_id: str) -> dict[str, Any]:
|
|
251
272
|
"""Build GraphResponse-compatible dict from SQLite."""
|
|
252
273
|
events = get_events(session_id)
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"""Textual TUI for mp start — live session event feed."""
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
|
+
import json
|
|
4
5
|
import time
|
|
5
6
|
from datetime import datetime, UTC
|
|
6
7
|
|
|
@@ -9,9 +10,7 @@ from textual.binding import Binding
|
|
|
9
10
|
from textual.containers import Horizontal, Vertical
|
|
10
11
|
from textual.reactive import reactive
|
|
11
12
|
from textual.widgets import Footer, Header, RichLog, Static
|
|
12
|
-
from
|
|
13
|
-
|
|
14
|
-
from methodproof import store
|
|
13
|
+
from methodproof import config, store
|
|
15
14
|
from methodproof.tui.theme import BASE_CSS, BORDER, DIM, GOLD, GREEN, PURPLE, RED, TEXT
|
|
16
15
|
|
|
17
16
|
_CSS = BASE_CSS + f"""
|
|
@@ -94,7 +93,7 @@ class StartApp(App[None]):
|
|
|
94
93
|
watch_dir = self._session.get("watch_dir", "?")
|
|
95
94
|
sid = self._session_id[:8]
|
|
96
95
|
yield Static(
|
|
97
|
-
f" session: [{GOLD}]{sid}[/{GOLD}] · {watch_dir} · [{GREEN}]●[/{GREEN}] 00:00:00
|
|
96
|
+
f" session: [{GOLD}]{sid}[/{GOLD}] · {watch_dir} · [{GREEN}]●[/{GREEN}] 00:00:00",
|
|
98
97
|
id="session-bar",
|
|
99
98
|
markup=True,
|
|
100
99
|
)
|
|
@@ -108,6 +107,15 @@ class StartApp(App[None]):
|
|
|
108
107
|
yield Footer()
|
|
109
108
|
|
|
110
109
|
def on_mount(self) -> None:
|
|
110
|
+
import base64
|
|
111
|
+
cfg = config.load()
|
|
112
|
+
token = cfg.get("token", "")
|
|
113
|
+
try:
|
|
114
|
+
payload = token.split(".")[1] + "=="
|
|
115
|
+
claims = json.loads(base64.urlsafe_b64decode(payload))
|
|
116
|
+
except Exception:
|
|
117
|
+
claims = {}
|
|
118
|
+
self._account_type = (claims.get("account_type") or "free").capitalize()
|
|
111
119
|
self.set_interval(_POLL_INTERVAL, self._poll_events)
|
|
112
120
|
self.set_interval(1.0, self._tick_timer)
|
|
113
121
|
|
|
@@ -120,7 +128,7 @@ class StartApp(App[None]):
|
|
|
120
128
|
watch_dir = self._session.get("watch_dir", "?")
|
|
121
129
|
self.query_one("#session-bar", Static).update(
|
|
122
130
|
f" session: [{GOLD}]{sid}[/{GOLD}] · {watch_dir} · [{GREEN}]●[/{GREEN}]"
|
|
123
|
-
f" {h:02d}:{m:02d}:{s:02d} · [{PURPLE}]
|
|
131
|
+
f" {h:02d}:{m:02d}:{s:02d} · [{PURPLE}]{self._account_type}[/{PURPLE}]"
|
|
124
132
|
)
|
|
125
133
|
|
|
126
134
|
def _poll_events(self) -> None:
|
|
@@ -128,7 +136,8 @@ class StartApp(App[None]):
|
|
|
128
136
|
return
|
|
129
137
|
try:
|
|
130
138
|
events = store.get_session_events(self._session_id, after_id=self._last_seen_id)
|
|
131
|
-
except Exception:
|
|
139
|
+
except Exception as exc:
|
|
140
|
+
self.log.warning(f"poll_events failed: {exc}")
|
|
132
141
|
return
|
|
133
142
|
|
|
134
143
|
feed = self.query_one(RichLog)
|
|
@@ -172,25 +181,28 @@ class StartApp(App[None]):
|
|
|
172
181
|
|
|
173
182
|
def _fmt_meta(ev: dict) -> str:
|
|
174
183
|
etype = ev.get("type", "")
|
|
184
|
+
meta = ev.get("metadata") or {}
|
|
185
|
+
if not isinstance(meta, dict):
|
|
186
|
+
meta = {}
|
|
175
187
|
if etype in ("file_edit", "file_create", "file_delete"):
|
|
176
|
-
path =
|
|
177
|
-
delta =
|
|
178
|
-
return f"{path} {f'+{delta}' if delta else ''}"
|
|
188
|
+
path = meta.get("path") or meta.get("file_path", "")
|
|
189
|
+
delta = meta.get("line_delta") or meta.get("lines_added", "")
|
|
190
|
+
return f"{path} {f'+{delta}' if delta else ''}".strip()
|
|
179
191
|
if etype == "terminal_cmd":
|
|
180
|
-
cmd =
|
|
181
|
-
ec =
|
|
192
|
+
cmd = (meta.get("command") or "")[:40]
|
|
193
|
+
ec = meta.get("exit_code", 0)
|
|
182
194
|
return f"{cmd} {'✓' if ec == 0 else f'✗{ec}'}"
|
|
183
195
|
if etype == "git_commit":
|
|
184
|
-
return (
|
|
196
|
+
return (meta.get("message") or "")[:40]
|
|
185
197
|
if etype in ("llm_prompt", "agent_prompt"):
|
|
186
|
-
tokens =
|
|
198
|
+
tokens = meta.get("prompt_tokens") or meta.get("input_length", "")
|
|
187
199
|
return f"{tokens} tokens" if tokens else ""
|
|
188
200
|
if etype in ("llm_completion", "agent_completion"):
|
|
189
|
-
tokens =
|
|
201
|
+
tokens = meta.get("completion_tokens") or meta.get("output_length", "")
|
|
190
202
|
dur = ev.get("duration_ms", "")
|
|
191
203
|
return f"{tokens} tokens {dur}ms" if tokens else ""
|
|
192
204
|
if etype == "test_run":
|
|
193
|
-
p, f =
|
|
205
|
+
p, f = meta.get("passed", 0), meta.get("failed", 0)
|
|
194
206
|
return f"{p} passed {f} failed" if f else f"{p} passed"
|
|
195
207
|
return ""
|
|
196
208
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "methodproof"
|
|
3
|
-
version = "0.7.
|
|
3
|
+
version = "0.7.25"
|
|
4
4
|
description = "See how you code. Capture and visualize your engineering process."
|
|
5
5
|
requires-python = ">=3.11"
|
|
6
6
|
dependencies = ["watchdog>=4.0", "websocket-client>=1.7", "cryptography>=43.0", "keyring>=25.0", "textual>=0.59", "rich>=13.7"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|