methodproof 0.7.20__tar.gz → 0.7.22__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.
Files changed (86) hide show
  1. {methodproof-0.7.20 → methodproof-0.7.22}/CHANGELOG.md +8 -0
  2. {methodproof-0.7.20 → methodproof-0.7.22}/PKG-INFO +1 -1
  3. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/__init__.py +1 -1
  4. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/cli.py +77 -44
  5. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/config.py +2 -1
  6. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/tui/init.py +21 -11
  7. {methodproof-0.7.20 → methodproof-0.7.22}/pyproject.toml +1 -1
  8. {methodproof-0.7.20 → methodproof-0.7.22}/tests/conftest.py +1 -1
  9. {methodproof-0.7.20 → methodproof-0.7.22}/tests/test_cli_start.py +7 -5
  10. {methodproof-0.7.20 → methodproof-0.7.22}/.github/workflows/ci.yml +0 -0
  11. {methodproof-0.7.20 → methodproof-0.7.22}/.gitignore +0 -0
  12. {methodproof-0.7.20 → methodproof-0.7.22}/LICENSE +0 -0
  13. {methodproof-0.7.20 → methodproof-0.7.22}/README.md +0 -0
  14. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/__main__.py +0 -0
  15. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/_daemon.py +0 -0
  16. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/agents/__init__.py +0 -0
  17. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/agents/base.py +0 -0
  18. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/agents/music.py +0 -0
  19. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/agents/terminal.py +0 -0
  20. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/agents/watcher.py +0 -0
  21. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/analysis.py +0 -0
  22. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/binding.py +0 -0
  23. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/bip39.py +0 -0
  24. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/bridge.py +0 -0
  25. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/crypto.py +0 -0
  26. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/e2e.py +0 -0
  27. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/graph.py +0 -0
  28. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/hook.py +0 -0
  29. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/hooks/__init__.py +0 -0
  30. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/hooks/claude_code.py +0 -0
  31. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/hooks/claude_code.sh +0 -0
  32. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/hooks/cline_hook.sh +0 -0
  33. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/hooks/codex_hook.sh +0 -0
  34. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/hooks/gemini_hook.sh +0 -0
  35. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/hooks/install.py +0 -0
  36. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/hooks/kiro_hook.sh +0 -0
  37. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/hooks/mcp_register.py +0 -0
  38. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/hooks/openclaw/HOOK.md +0 -0
  39. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/hooks/openclaw/handler.ts +0 -0
  40. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/hooks/openclaw_install.py +0 -0
  41. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/hooks/opencode_plugin.js +0 -0
  42. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/hooks/wrappers.py +0 -0
  43. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/integrity.py +0 -0
  44. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/kdf.py +0 -0
  45. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/keychain.py +0 -0
  46. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/live.py +0 -0
  47. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/lock.py +0 -0
  48. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/mcp.py +0 -0
  49. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/migrate_db.py +0 -0
  50. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/proxy.py +0 -0
  51. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/proxy_daemon.py +0 -0
  52. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/repos.py +0 -0
  53. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/skills/methodproof/SKILL.md +0 -0
  54. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/store.py +0 -0
  55. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/sync.py +0 -0
  56. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/tui/__init__.py +0 -0
  57. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/tui/consent.py +0 -0
  58. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/tui/log.py +0 -0
  59. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/tui/login_success.py +0 -0
  60. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/tui/review.py +0 -0
  61. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/tui/start.py +0 -0
  62. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/tui/status.py +0 -0
  63. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/tui/theme.py +0 -0
  64. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/viewer.py +0 -0
  65. {methodproof-0.7.20 → methodproof-0.7.22}/methodproof/wordlist.py +0 -0
  66. {methodproof-0.7.20 → methodproof-0.7.22}/test_windows_compat.py +0 -0
  67. {methodproof-0.7.20 → methodproof-0.7.22}/tests/__init__.py +0 -0
  68. {methodproof-0.7.20 → methodproof-0.7.22}/tests/test_analysis.py +0 -0
  69. {methodproof-0.7.20 → methodproof-0.7.22}/tests/test_cli_auth.py +0 -0
  70. {methodproof-0.7.20 → methodproof-0.7.22}/tests/test_cli_config.py +0 -0
  71. {methodproof-0.7.20 → methodproof-0.7.22}/tests/test_cli_helpers.py +0 -0
  72. {methodproof-0.7.20 → methodproof-0.7.22}/tests/test_cli_session.py +0 -0
  73. {methodproof-0.7.20 → methodproof-0.7.22}/tests/test_cli_share.py +0 -0
  74. {methodproof-0.7.20 → methodproof-0.7.22}/tests/test_cli_update.py +0 -0
  75. {methodproof-0.7.20 → methodproof-0.7.22}/tests/test_e2e_integration.py +0 -0
  76. {methodproof-0.7.20 → methodproof-0.7.22}/tests/test_graph.py +0 -0
  77. {methodproof-0.7.20 → methodproof-0.7.22}/tests/test_hooks.py +0 -0
  78. {methodproof-0.7.20 → methodproof-0.7.22}/tests/test_live.py +0 -0
  79. {methodproof-0.7.20 → methodproof-0.7.22}/tests/test_openclaw_hooks.py +0 -0
  80. {methodproof-0.7.20 → methodproof-0.7.22}/tests/test_profiles.py +0 -0
  81. {methodproof-0.7.20 → methodproof-0.7.22}/tests/test_security.py +0 -0
  82. {methodproof-0.7.20 → methodproof-0.7.22}/tests/test_store.py +0 -0
  83. {methodproof-0.7.20 → methodproof-0.7.22}/tests/test_sync.py +0 -0
  84. {methodproof-0.7.20 → methodproof-0.7.22}/tests/test_viewer.py +0 -0
  85. {methodproof-0.7.20 → methodproof-0.7.22}/tests/test_wrappers.py +0 -0
  86. {methodproof-0.7.20 → methodproof-0.7.22}/uv.lock +0 -0
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.7.22] — 2026-04-11
4
+
5
+ ### Added
6
+ - **Username in session output** — `mp start` banner shows `Account: @username` (falls back to email). `mp stop` summary shows the same. Username fetched from `/auth/me` on login and stored in config profile.
7
+
8
+ ### Fixed
9
+ - **`eval "$(methodproof shell-hook)"` missing `mp` alias** — `shell-hook` now emits both the command-logging hooks and `alias mp="methodproof"`, so eval fully activates the CLI without a shell restart.
10
+
3
11
  ## [0.7.20] — 2026-04-11
4
12
 
5
13
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: methodproof
3
- Version: 0.7.20
3
+ Version: 0.7.22
4
4
  Summary: See how you code. Capture and visualize your engineering process.
5
5
  License-Expression: Apache-2.0
6
6
  License-File: LICENSE
@@ -1,3 +1,3 @@
1
1
  """MethodProof — see how you code."""
2
2
 
3
- __version__ = "0.7.19"
3
+ __version__ = "0.7.21"
@@ -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
- cfg = _run_consent(cfg)
352
- config.save(cfg)
353
- if cfg.get("token"):
354
- cfg["_pending_research_sync"] = True
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
- from methodproof.sync import sync_research_consent
357
- sync_research_consent(cfg["token"], cfg["api_url"])
358
- print()
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
- answer = input("Enable auto-update (recommended)? [Y/n]: ").strip().lower()
366
- cfg["auto_update_offered"] = True
367
- cfg["auto_update"] = answer != "n"
368
- print(f"Auto-update: {'ON — updates install before each session' if cfg['auto_update'] else 'OFF — toggle with: mp update --auto'}")
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
- answer = input("Install `mp` as a shorthand alias? [Y/n]: ").strip().lower()
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
- print("Alias: skipped")
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
- answer = input("Prefer classic terminal output instead of the rich TUI? [y/N]: ").strip().lower()
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 (toggle anytime with: mp ui off)")
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 answer == "y":
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: skipped (built-in: Ollama 11434, Jan 1234)")
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
@@ -475,7 +491,8 @@ def cmd_init(args: argparse.Namespace) -> None:
475
491
  def cmd_shell_hook(_args: argparse.Namespace) -> None:
476
492
  """Print the shell hook text for the current shell (for eval)."""
477
493
  _, hook_text = hook.get_shell_rc()
478
- print(hook_text.strip())
494
+ alias = 'Set-Alias mp methodproof' if sys.platform == "win32" else 'alias mp="methodproof"'
495
+ print(hook_text.strip() + "\n" + alias)
479
496
 
480
497
 
481
498
  # ── TUI mode helpers ──────────────────────────────────────────────────────────
@@ -1187,8 +1204,11 @@ def cmd_start(args: argparse.Namespace) -> None:
1187
1204
  config.save(cfg)
1188
1205
 
1189
1206
  active = [k for k, v in capture.items() if v]
1207
+ username = cfg.get("username")
1208
+ account_label = f"@{username}" if username else (cfg.get("email") or cfg.get("account_id", "")[:8])
1190
1209
  print(f"\n{_banner()}")
1191
1210
  print(f"Recording: {sid[:8]}")
1211
+ print(f"Account: {account_label}")
1192
1212
  print(f"Watching: {watch_dir}")
1193
1213
  if repo_url:
1194
1214
  print(f"Repo: {repo_url}")
@@ -1381,7 +1401,7 @@ def cmd_stop(args: argparse.Namespace) -> None:
1381
1401
  session = store.get_session(sid)
1382
1402
  cfg["active_session"] = None
1383
1403
  config.save(cfg)
1384
- _print_summary(session, stats)
1404
+ _print_summary(session, stats, cfg)
1385
1405
 
1386
1406
 
1387
1407
  def cmd_view(args: argparse.Namespace) -> None:
@@ -1689,6 +1709,13 @@ def cmd_login(args: argparse.Namespace) -> None:
1689
1709
  cfg["account_id"] = claims.get("user_id", "")
1690
1710
  cfg["last_auth_at"] = time.time()
1691
1711
  cfg["master_key_fingerprint"] = "" # clear stale fingerprint from previous account
1712
+ # Fetch profile to store email and username
1713
+ try:
1714
+ profile = _request("GET", "/auth/me", api, poll["token"])
1715
+ cfg["email"] = profile.get("email", "")
1716
+ cfg["username"] = profile.get("username") or ""
1717
+ except Exception as exc:
1718
+ _log_debug("auth.profile_fetch_failed", error=str(exc))
1692
1719
  config.save(cfg)
1693
1720
  config.save_active_profile(cfg)
1694
1721
  print(" done.\n")
@@ -1698,7 +1725,7 @@ def cmd_login(args: argparse.Namespace) -> None:
1698
1725
  sync_research_consent(cfg["token"], cfg["api_url"])
1699
1726
  from methodproof.tui.login_success import run as show_success
1700
1727
  show_success(
1701
- display_name=cfg.get("email") or cfg.get("account_id", "")[:8],
1728
+ display_name=cfg.get("username") or cfg.get("email") or cfg.get("account_id", "")[:8],
1702
1729
  email=cfg.get("email", ""),
1703
1730
  account_count=len(cfg.get("profiles", {})),
1704
1731
  added=getattr(args, "add", False),
@@ -1995,11 +2022,16 @@ def _duration(s: dict) -> str:
1995
2022
  return f"{secs // 60}:{secs % 60:02d}"
1996
2023
 
1997
2024
 
1998
- def _print_summary(session: dict | None, stats: dict) -> None:
2025
+ def _print_summary(session: dict | None, stats: dict, cfg: dict | None = None) -> None:
1999
2026
  if not session:
2000
2027
  return
2028
+ cfg = cfg or {}
2029
+ username = cfg.get("username")
2030
+ account_label = f"@{username}" if username else (cfg.get("email") or cfg.get("account_id", "")[:8])
2001
2031
  print(f"\n{_banner()}")
2002
2032
  print(f"Session: {session['id'][:8]}")
2033
+ if account_label:
2034
+ print(f" Account: {account_label}")
2003
2035
  print(f" Events: {session['total_events']}")
2004
2036
  print(f" Duration: {_duration(session)}")
2005
2037
  print(f" Graph: {stats['next']} links, {stats['causal']} causal")
@@ -2115,6 +2147,7 @@ def main() -> None:
2115
2147
 
2116
2148
  s = sub.add_parser("init", help="Install shell hook")
2117
2149
  s.add_argument("--force", action="store_true", help="Re-run all setup prompts from scratch")
2150
+ s.add_argument("-y", "--yes", action="store_true", help="Accept all defaults, no prompts")
2118
2151
  _add_ui_flags(s)
2119
2152
  sub.add_parser("shell-hook", help="Print shell hook for eval (activates without restart)")
2120
2153
  s = sub.add_parser("start", help="Start recording")
@@ -42,6 +42,7 @@ _DEFAULTS: dict[str, Any] = {
42
42
  "e2e_fingerprint": "",
43
43
  "auto_update": False,
44
44
  "account_id": "",
45
+ "username": "",
45
46
  "last_auth_at": 0,
46
47
  "local_ai_ports": [], # user-configured localhost ports for local LLM capture
47
48
  "publish_redact": {
@@ -161,7 +162,7 @@ def save(cfg: dict[str, Any]) -> None:
161
162
  # --- Multi-account profiles ---
162
163
 
163
164
  _PROFILE_KEYS = [
164
- "token", "refresh_token", "email", "account_id",
165
+ "token", "refresh_token", "email", "account_id", "username",
165
166
  "last_auth_at", "master_key_fingerprint",
166
167
  "e2e_mode", "e2e_fingerprint",
167
168
  "journal_mode", "journal_credits",
@@ -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,29 @@ 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: auto;
55
+ height: 1;
38
56
  align: left middle;
39
57
  margin: 0 0 1 0;
40
58
  }}
41
- .toggle-row Switch {{
42
- margin: 0 1 0 0;
43
- width: 6;
44
- }}
45
59
  .row-label {{
46
60
  width: 1fr;
47
61
  color: {TEXT};
@@ -57,14 +71,10 @@ PrefsScreen {{
57
71
  width: 5;
58
72
  }}
59
73
  .opt-row {{
60
- height: auto;
74
+ height: 1;
61
75
  align: left middle;
62
76
  margin: 0 0 1 0;
63
77
  }}
64
- .opt-row Switch {{
65
- margin: 0 1 0 0;
66
- width: 6;
67
- }}
68
78
  #fs-status {{
69
79
  color: {DIM};
70
80
  height: auto;
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "methodproof"
3
- version = "0.7.20"
3
+ version = "0.7.22"
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"]
@@ -125,7 +125,7 @@ def cli_args():
125
125
  "verbose": False, "streaming": False, "force": False,
126
126
  "local": False, "api_url": None, "no_key": False, "auto": None,
127
127
  "account": None, "purge": False, "keep_sessions": False,
128
- "anonymous": False,
128
+ "anonymous": False, "yes": False,
129
129
  }
130
130
  defaults.update(kwargs)
131
131
  return argparse.Namespace(**defaults)
@@ -427,11 +427,13 @@ def test_consent_detailed_redaction_toggle():
427
427
  # ── cmd_init ──
428
428
 
429
429
 
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()
430
+ @patch("methodproof.hook.install", return_value="hook installed")
431
+ @patch("methodproof.integrity.has_keypair", return_value=True)
432
+ def test_init_first_run(mock_keypair, mock_hook, cli_args, capsys):
433
+ # First run with --yes: all prompts auto-accepted, no stdin required
434
+ cli.cmd_init(cli_args(yes=True))
435
+ out = capsys.readouterr().out
436
+ assert "METHODPROOF" in out or "Recording" in out or "mp start" in out
435
437
 
436
438
 
437
439
  @patch("methodproof.integrity.has_keypair", return_value=True)
File without changes
File without changes
File without changes
File without changes