methodproof 0.7.19__tar.gz → 0.7.21__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.19 → methodproof-0.7.21}/CHANGELOG.md +8 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/PKG-INFO +1 -1
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/__init__.py +1 -1
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/cli.py +57 -41
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/tui/consent.py +1 -1
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/tui/init.py +25 -12
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/tui/status.py +7 -5
- {methodproof-0.7.19 → methodproof-0.7.21}/pyproject.toml +1 -1
- {methodproof-0.7.19 → methodproof-0.7.21}/tests/conftest.py +2 -1
- {methodproof-0.7.19 → methodproof-0.7.21}/tests/test_cli_auth.py +1 -1
- {methodproof-0.7.19 → methodproof-0.7.21}/tests/test_cli_share.py +1 -1
- {methodproof-0.7.19 → methodproof-0.7.21}/tests/test_cli_start.py +7 -17
- {methodproof-0.7.19 → methodproof-0.7.21}/.code-review-graph/.gitignore +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/.code-review-graph/graph.db +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/.github/workflows/ci.yml +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/.gitignore +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/LICENSE +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/README.md +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/__main__.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/_daemon.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/agents/__init__.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/agents/base.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/agents/music.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/agents/terminal.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/agents/watcher.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/analysis.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/binding.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/bip39.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/bridge.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/config.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/crypto.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/e2e.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/graph.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/hook.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/hooks/__init__.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/hooks/claude_code.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/hooks/claude_code.sh +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/hooks/cline_hook.sh +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/hooks/codex_hook.sh +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/hooks/gemini_hook.sh +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/hooks/install.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/hooks/kiro_hook.sh +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/hooks/mcp_register.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/hooks/openclaw/HOOK.md +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/hooks/openclaw/handler.ts +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/hooks/openclaw_install.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/hooks/opencode_plugin.js +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/hooks/wrappers.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/integrity.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/kdf.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/keychain.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/live.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/lock.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/mcp.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/migrate_db.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/proxy.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/proxy_daemon.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/repos.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/skills/methodproof/SKILL.md +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/store.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/sync.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/tui/__init__.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/tui/log.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/tui/login_success.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/tui/review.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/tui/start.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/tui/theme.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/viewer.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/methodproof/wordlist.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/test_windows_compat.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/tests/__init__.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/tests/test_analysis.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/tests/test_cli_config.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/tests/test_cli_helpers.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/tests/test_cli_session.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/tests/test_cli_update.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/tests/test_e2e_integration.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/tests/test_graph.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/tests/test_hooks.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/tests/test_live.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/tests/test_openclaw_hooks.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/tests/test_profiles.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/tests/test_security.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/tests/test_store.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/tests/test_sync.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/tests/test_viewer.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/tests/test_wrappers.py +0 -0
- {methodproof-0.7.19 → methodproof-0.7.21}/uv.lock +0 -0
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.7.20] — 2026-04-11
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
- **TUI init layout** — toggle rows now use `height: auto` so long capture descriptions don't clip; `width: 1fr` on `.row-label` overrides the 24-char truncation from base CSS; Switch widgets widened from 4→6 for correct rendering; Full Spectrum status no longer cut off at 1 line
|
|
7
|
+
- **TUI consent layout** — Switch widgets widened from 4→6 (same fix as init)
|
|
8
|
+
- **TUI status markup** — `_token_expiry()` was returning Rich markup strings into `Text.append()`, which treats input as plain text; tags now rendered literally (e.g. `[#d93326]expires soon[/#d93326]`). Fixed to return `(text, style)` tuple and apply styles at call site
|
|
9
|
+
- **Session complete timeout** — `mp push` was using 15s for the final `/complete` call, which times out on large sessions while the server drains the ingest queue and materializes stats. Raised to 90s. Timeout is now a configurable parameter on internal request helpers
|
|
10
|
+
|
|
3
11
|
## [0.7.6] — 2026-04-08
|
|
4
12
|
|
|
5
13
|
### Added
|
|
@@ -334,62 +334,74 @@ def _run_consent_detailed(cfg: dict) -> dict:
|
|
|
334
334
|
def cmd_init(args: argparse.Namespace) -> None:
|
|
335
335
|
config.ensure_dirs()
|
|
336
336
|
cfg = config.load()
|
|
337
|
+
yes = getattr(args, "yes", False)
|
|
337
338
|
if getattr(args, "force", False):
|
|
338
339
|
for key in ("consent_acknowledged", "auto_update_offered", "alias_offered", "local_ai_ports_offered", "ui_mode_offered"):
|
|
339
340
|
cfg.pop(key, None)
|
|
340
341
|
config.save(cfg)
|
|
341
342
|
|
|
342
|
-
# TUI wizard — runs when nothing is set up yet, or on --force, or when ui_mode is on
|
|
343
|
-
needs_setup = not cfg.get("consent_acknowledged")
|
|
344
|
-
use_ui = needs_setup or _resolve_ui(args, cfg)
|
|
345
|
-
if use_ui:
|
|
346
|
-
from methodproof.tui.init import run as tui_init
|
|
347
|
-
tui_init(cfg)
|
|
348
|
-
return
|
|
349
|
-
|
|
350
343
|
if not cfg.get("consent_acknowledged"):
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
cfg["
|
|
344
|
+
if yes:
|
|
345
|
+
from methodproof import config as cfg_mod
|
|
346
|
+
cfg["capture"] = dict(cfg_mod._DEFAULTS["capture"])
|
|
347
|
+
cfg["publish_redact"] = dict(cfg_mod._DEFAULTS["publish_redact"])
|
|
348
|
+
cfg["consent_acknowledged"] = True
|
|
355
349
|
config.save(cfg)
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
350
|
+
print("Capture: all defaults accepted")
|
|
351
|
+
else:
|
|
352
|
+
cfg = _run_consent(cfg)
|
|
353
|
+
config.save(cfg)
|
|
354
|
+
if cfg.get("token"):
|
|
355
|
+
cfg["_pending_research_sync"] = True
|
|
356
|
+
config.save(cfg)
|
|
357
|
+
from methodproof.sync import sync_research_consent
|
|
358
|
+
sync_research_consent(cfg["token"], cfg["api_url"])
|
|
359
|
+
print()
|
|
359
360
|
|
|
360
361
|
capture = cfg.get("capture", {})
|
|
361
362
|
store.init_db()
|
|
362
363
|
|
|
363
364
|
# Offer auto-update (recommended)
|
|
364
365
|
if not cfg.get("auto_update_offered"):
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
366
|
+
if yes:
|
|
367
|
+
cfg["auto_update_offered"] = True
|
|
368
|
+
cfg["auto_update"] = True
|
|
369
|
+
print("Auto-update: ON")
|
|
370
|
+
else:
|
|
371
|
+
answer = input("Enable auto-update (recommended)? [Y/n]: ").strip().lower()
|
|
372
|
+
cfg["auto_update_offered"] = True
|
|
373
|
+
cfg["auto_update"] = answer != "n"
|
|
374
|
+
print(f"Auto-update: {'ON — updates install before each session' if cfg['auto_update'] else 'OFF — toggle with: mp update --auto'}")
|
|
369
375
|
config.save(cfg)
|
|
370
376
|
|
|
371
377
|
# Offer mp alias
|
|
372
378
|
if not cfg.get("alias_offered"):
|
|
373
|
-
|
|
374
|
-
cfg["alias_offered"] = True
|
|
375
|
-
if answer != "n":
|
|
379
|
+
if yes:
|
|
376
380
|
_install_alias()
|
|
381
|
+
cfg["alias_offered"] = True
|
|
377
382
|
cfg["alias_installed"] = True
|
|
378
383
|
print("Alias: mp -> methodproof")
|
|
379
384
|
else:
|
|
380
|
-
|
|
385
|
+
answer = input("Install `mp` as a shorthand alias? [Y/n]: ").strip().lower()
|
|
386
|
+
cfg["alias_offered"] = True
|
|
387
|
+
if answer != "n":
|
|
388
|
+
_install_alias()
|
|
389
|
+
cfg["alias_installed"] = True
|
|
390
|
+
print("Alias: mp -> methodproof")
|
|
391
|
+
else:
|
|
392
|
+
print("Alias: skipped")
|
|
381
393
|
config.save(cfg)
|
|
382
394
|
|
|
383
395
|
# Offer classic CLI mode (TUI is default)
|
|
384
396
|
if not cfg.get("ui_mode_offered"):
|
|
385
397
|
cfg["ui_mode_offered"] = True
|
|
386
|
-
|
|
387
|
-
if answer == "y":
|
|
388
|
-
cfg["ui_mode"] = False
|
|
389
|
-
print("Output mode: classic (toggle anytime with: mp ui on/off)")
|
|
390
|
-
else:
|
|
398
|
+
if yes:
|
|
391
399
|
cfg["ui_mode"] = True
|
|
392
|
-
print("Output mode: rich TUI
|
|
400
|
+
print("Output mode: rich TUI")
|
|
401
|
+
else:
|
|
402
|
+
answer = input("Prefer classic terminal output instead of the rich TUI? [y/N]: ").strip().lower()
|
|
403
|
+
cfg["ui_mode"] = answer != "y"
|
|
404
|
+
print(f"Output mode: {'classic (toggle anytime with: mp ui on/off)' if not cfg['ui_mode'] else 'rich TUI (toggle anytime with: mp ui off)'}")
|
|
393
405
|
config.save(cfg)
|
|
394
406
|
|
|
395
407
|
# Shell hook — needed for terminal commands
|
|
@@ -440,19 +452,23 @@ def cmd_init(args: argparse.Namespace) -> None:
|
|
|
440
452
|
|
|
441
453
|
# Local AI ports — capture traffic from local LLM servers
|
|
442
454
|
if ai_enabled and not cfg.get("local_ai_ports_offered"):
|
|
443
|
-
answer = input("Run any local AI models (Ollama, LM Studio, vLLM, etc.)? [y/N]: ").strip().lower()
|
|
444
455
|
cfg["local_ai_ports_offered"] = True
|
|
445
|
-
if
|
|
446
|
-
raw = input("Enter ports (comma-separated, e.g. 8080,5000,7860): ").strip()
|
|
447
|
-
ports = [int(p.strip()) for p in raw.split(",") if p.strip().isdigit()]
|
|
448
|
-
cfg["local_ai_ports"] = ports
|
|
449
|
-
if ports:
|
|
450
|
-
print(f"Local AI ports: {', '.join(str(p) for p in ports)} (proxy will decode these)")
|
|
451
|
-
else:
|
|
452
|
-
print("Local AI ports: none added")
|
|
453
|
-
else:
|
|
456
|
+
if yes:
|
|
454
457
|
cfg["local_ai_ports"] = []
|
|
455
|
-
print("Local AI ports:
|
|
458
|
+
print("Local AI ports: using defaults (Ollama 11434, Jan 1234)")
|
|
459
|
+
else:
|
|
460
|
+
answer = input("Run any local AI models (Ollama, LM Studio, vLLM, etc.)? [y/N]: ").strip().lower()
|
|
461
|
+
if answer == "y":
|
|
462
|
+
raw = input("Enter ports (comma-separated, e.g. 8080,5000,7860): ").strip()
|
|
463
|
+
ports = [int(p.strip()) for p in raw.split(",") if p.strip().isdigit()]
|
|
464
|
+
cfg["local_ai_ports"] = ports
|
|
465
|
+
if ports:
|
|
466
|
+
print(f"Local AI ports: {', '.join(str(p) for p in ports)} (proxy will decode these)")
|
|
467
|
+
else:
|
|
468
|
+
print("Local AI ports: none added")
|
|
469
|
+
else:
|
|
470
|
+
cfg["local_ai_ports"] = []
|
|
471
|
+
print("Local AI ports: skipped (built-in: Ollama 11434, Jan 1234)")
|
|
456
472
|
config.save(cfg)
|
|
457
473
|
|
|
458
474
|
# Signing keypair for attestation
|
|
@@ -1398,7 +1414,6 @@ def cmd_log(args: argparse.Namespace) -> None:
|
|
|
1398
1414
|
return
|
|
1399
1415
|
print(f"Found {len(empty)} empty session{'s' if len(empty) != 1 else ''}:")
|
|
1400
1416
|
for s in empty:
|
|
1401
|
-
from datetime import datetime, UTC
|
|
1402
1417
|
dt = datetime.fromtimestamp(s["created_at"], tz=UTC).strftime("%Y-%m-%d %H:%M")
|
|
1403
1418
|
print(f" {s['id'][:8]} {dt} {s.get('watch_dir', '?')}")
|
|
1404
1419
|
answer = input(f"\nDelete {len(empty)} empty session{'s' if len(empty) != 1 else ''}? [y/N]: ").strip().lower()
|
|
@@ -2116,6 +2131,7 @@ def main() -> None:
|
|
|
2116
2131
|
|
|
2117
2132
|
s = sub.add_parser("init", help="Install shell hook")
|
|
2118
2133
|
s.add_argument("--force", action="store_true", help="Re-run all setup prompts from scratch")
|
|
2134
|
+
s.add_argument("-y", "--yes", action="store_true", help="Accept all defaults, no prompts")
|
|
2119
2135
|
_add_ui_flags(s)
|
|
2120
2136
|
sub.add_parser("shell-hook", help="Print shell hook for eval (activates without restart)")
|
|
2121
2137
|
s = sub.add_parser("start", help="Start recording")
|
|
@@ -8,7 +8,7 @@ from textual.screen import Screen
|
|
|
8
8
|
from textual.widgets import Button, Footer, Header, Label, RichLog, Rule, Static, Switch
|
|
9
9
|
|
|
10
10
|
from methodproof import config as cfg_mod
|
|
11
|
-
from methodproof.tui.theme import BASE_CSS, BORDER, DIM, GOLD, GREEN, PURPLE, RED, TEXT
|
|
11
|
+
from methodproof.tui.theme import BASE_CSS, BG, BORDER, DIM, GOLD, GREEN, PURPLE, RED, TEXT
|
|
12
12
|
|
|
13
13
|
_REDACTABLE = [
|
|
14
14
|
("command_output", "Terminal output"),
|
|
@@ -33,15 +33,31 @@ PrefsScreen {{
|
|
|
33
33
|
color: {DIM};
|
|
34
34
|
margin: 0 0 1 0;
|
|
35
35
|
}}
|
|
36
|
+
Switch {{
|
|
37
|
+
border: none;
|
|
38
|
+
height: 1;
|
|
39
|
+
width: 10;
|
|
40
|
+
background: {BORDER};
|
|
41
|
+
padding: 0 1;
|
|
42
|
+
}}
|
|
43
|
+
Switch.-on {{
|
|
44
|
+
background: {GREEN};
|
|
45
|
+
}}
|
|
46
|
+
Switch .switch--slider {{
|
|
47
|
+
color: {TEXT};
|
|
48
|
+
background: {DIM};
|
|
49
|
+
}}
|
|
50
|
+
Switch.-on .switch--slider {{
|
|
51
|
+
color: {BG};
|
|
52
|
+
background: {TEXT};
|
|
53
|
+
}}
|
|
36
54
|
.toggle-row {{
|
|
37
|
-
height:
|
|
55
|
+
height: 1;
|
|
38
56
|
align: left middle;
|
|
39
|
-
|
|
40
|
-
.toggle-row Switch {{
|
|
41
|
-
margin: 0 1 0 0;
|
|
42
|
-
width: 4;
|
|
57
|
+
margin: 0 0 1 0;
|
|
43
58
|
}}
|
|
44
59
|
.row-label {{
|
|
60
|
+
width: 1fr;
|
|
45
61
|
color: {TEXT};
|
|
46
62
|
}}
|
|
47
63
|
.pro-row .row-label {{
|
|
@@ -55,16 +71,13 @@ PrefsScreen {{
|
|
|
55
71
|
width: 5;
|
|
56
72
|
}}
|
|
57
73
|
.opt-row {{
|
|
58
|
-
height:
|
|
74
|
+
height: 1;
|
|
59
75
|
align: left middle;
|
|
60
|
-
|
|
61
|
-
.opt-row Switch {{
|
|
62
|
-
margin: 0 1 0 0;
|
|
63
|
-
width: 4;
|
|
76
|
+
margin: 0 0 1 0;
|
|
64
77
|
}}
|
|
65
78
|
#fs-status {{
|
|
66
79
|
color: {DIM};
|
|
67
|
-
height:
|
|
80
|
+
height: auto;
|
|
68
81
|
margin: 1 0 0 0;
|
|
69
82
|
}}
|
|
70
83
|
#fs-status.full {{
|
|
@@ -19,15 +19,16 @@ def _tier_color(tier: str) -> str:
|
|
|
19
19
|
return {"free": DIM, "basic": TEXT, "pro": GOLD, "team": PURPLE}.get(tier.lower(), TEXT)
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
def _token_expiry(cfg: dict) -> str:
|
|
22
|
+
def _token_expiry(cfg: dict) -> tuple[str, str]:
|
|
23
|
+
"""Return (text, style) for token expiry display."""
|
|
23
24
|
last_auth = cfg.get("last_auth_at", 0)
|
|
24
25
|
if not last_auth:
|
|
25
|
-
return "unknown"
|
|
26
|
+
return "unknown", DIM
|
|
26
27
|
age_h = (time.time() - last_auth) / 3600
|
|
27
28
|
remaining_h = max(0, 24 - age_h)
|
|
28
29
|
if remaining_h < 1:
|
|
29
|
-
return
|
|
30
|
-
return f"
|
|
30
|
+
return "expires soon", RED
|
|
31
|
+
return f"expires in {int(remaining_h)}h", DIM
|
|
31
32
|
|
|
32
33
|
|
|
33
34
|
def run(cfg: dict) -> None:
|
|
@@ -52,7 +53,8 @@ def run(cfg: dict) -> None:
|
|
|
52
53
|
acct_lines.append(" · ", style=DIM)
|
|
53
54
|
acct_lines.append(tier, style=_tier_color(tier))
|
|
54
55
|
acct_lines.append("\n")
|
|
55
|
-
|
|
56
|
+
expiry_text, expiry_style = _token_expiry(cfg)
|
|
57
|
+
acct_lines.append(expiry_text, style=expiry_style)
|
|
56
58
|
|
|
57
59
|
console.print(Panel(
|
|
58
60
|
acct_lines,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "methodproof"
|
|
3
|
-
version = "0.7.
|
|
3
|
+
version = "0.7.21"
|
|
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"]
|
|
@@ -27,7 +27,8 @@ def isolate_fs(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -> Path:
|
|
|
27
27
|
monkeypatch.setattr(config, "CONFIG", mp_dir / "config.json")
|
|
28
28
|
monkeypatch.setattr(config, "DB_PATH", mp_dir / "methodproof.db")
|
|
29
29
|
monkeypatch.setattr(config, "CMD_LOG", mp_dir / "commands.jsonl")
|
|
30
|
-
|
|
30
|
+
defaults = {**config._DEFAULTS, "ui_mode": False}
|
|
31
|
+
(mp_dir / "config.json").write_text(json.dumps(defaults, indent=2))
|
|
31
32
|
monkeypatch.setattr(store, "_conn", None)
|
|
32
33
|
store.init_db()
|
|
33
34
|
return tmp_path
|
|
@@ -215,7 +215,7 @@ def test_login_happy_path(mock_req, mock_sleep, mock_browser, mock_key, mock_con
|
|
|
215
215
|
assert cfg["account_id"] == "new-user"
|
|
216
216
|
mock_browser.assert_called_once()
|
|
217
217
|
out = capsys.readouterr().out
|
|
218
|
-
assert "Logged
|
|
218
|
+
assert "Logged In" in out
|
|
219
219
|
|
|
220
220
|
|
|
221
221
|
@patch("methodproof.sync._request")
|
|
@@ -427,21 +427,11 @@ def test_consent_detailed_redaction_toggle():
|
|
|
427
427
|
# ── cmd_init ──
|
|
428
428
|
|
|
429
429
|
|
|
430
|
-
@patch("methodproof.
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
@patch("methodproof.hooks.openclaw_install.install", return_value="installed")
|
|
436
|
-
@patch("methodproof.hook.install", return_value="hook installed")
|
|
437
|
-
def test_init_first_run(mock_hook, mock_oc, mock_claude, mock_mcp, mock_wrap, mock_consent,
|
|
438
|
-
mock_keypair, cli_args, capsys):
|
|
439
|
-
# input() calls: auto-update, alias, local AI ports
|
|
440
|
-
with patch("methodproof.cli._run_consent", return_value=config.load()) as mock_run_consent, \
|
|
441
|
-
patch("builtins.input", side_effect=["N", "N", "N"]):
|
|
442
|
-
cli.cmd_init(cli_args())
|
|
443
|
-
mock_run_consent.assert_called_once()
|
|
444
|
-
mock_hook.assert_called_once()
|
|
430
|
+
@patch("methodproof.tui.init.run")
|
|
431
|
+
def test_init_first_run(mock_tui_init, cli_args):
|
|
432
|
+
# First run: consent_acknowledged=False forces TUI regardless of ui_mode
|
|
433
|
+
cli.cmd_init(cli_args())
|
|
434
|
+
mock_tui_init.assert_called_once()
|
|
445
435
|
|
|
446
436
|
|
|
447
437
|
@patch("methodproof.integrity.has_keypair", return_value=True)
|
|
@@ -450,7 +440,7 @@ def test_init_already_configured(mock_hook, mock_keypair, cli_args, capsys):
|
|
|
450
440
|
cfg = config.load()
|
|
451
441
|
cfg["consent_acknowledged"] = True
|
|
452
442
|
config.save(cfg)
|
|
453
|
-
# input() calls: auto-update, alias, local AI ports
|
|
454
|
-
with patch("builtins.input", side_effect=["N", "N", "N"]):
|
|
443
|
+
# input() calls: auto-update, alias, ui-mode, local AI ports
|
|
444
|
+
with patch("builtins.input", side_effect=["N", "N", "N", "N"]):
|
|
455
445
|
cli.cmd_init(cli_args())
|
|
456
446
|
mock_hook.assert_called_once()
|
|
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
|