methodproof 0.7.14__tar.gz → 0.7.16__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.14 → methodproof-0.7.16}/PKG-INFO +1 -1
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/__init__.py +1 -1
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/cli.py +15 -0
- methodproof-0.7.16/methodproof/tui/init.py +387 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/pyproject.toml +1 -1
- {methodproof-0.7.14 → methodproof-0.7.16}/.code-review-graph/.gitignore +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/.code-review-graph/graph.db +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/.github/workflows/ci.yml +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/.gitignore +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/CHANGELOG.md +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/LICENSE +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/README.md +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/__main__.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/_daemon.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/agents/__init__.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/agents/base.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/agents/music.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/agents/terminal.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/agents/watcher.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/analysis.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/binding.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/bip39.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/bridge.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/config.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/crypto.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/e2e.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/graph.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/hook.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/hooks/__init__.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/hooks/claude_code.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/hooks/claude_code.sh +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/hooks/cline_hook.sh +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/hooks/codex_hook.sh +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/hooks/gemini_hook.sh +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/hooks/install.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/hooks/kiro_hook.sh +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/hooks/mcp_register.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/hooks/openclaw/HOOK.md +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/hooks/openclaw/handler.ts +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/hooks/openclaw_install.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/hooks/opencode_plugin.js +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/hooks/wrappers.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/integrity.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/kdf.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/keychain.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/live.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/lock.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/mcp.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/migrate_db.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/proxy.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/proxy_daemon.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/repos.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/skills/methodproof/SKILL.md +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/store.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/sync.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/tui/__init__.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/tui/consent.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/tui/log.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/tui/review.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/tui/start.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/tui/status.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/tui/theme.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/viewer.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/methodproof/wordlist.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/test_windows_compat.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/tests/__init__.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/tests/conftest.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/tests/test_analysis.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/tests/test_cli_auth.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/tests/test_cli_config.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/tests/test_cli_helpers.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/tests/test_cli_session.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/tests/test_cli_share.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/tests/test_cli_start.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/tests/test_cli_update.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/tests/test_e2e_integration.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/tests/test_graph.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/tests/test_hooks.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/tests/test_live.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/tests/test_openclaw_hooks.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/tests/test_profiles.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/tests/test_security.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/tests/test_store.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/tests/test_sync.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/tests/test_viewer.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/tests/test_wrappers.py +0 -0
- {methodproof-0.7.14 → methodproof-0.7.16}/uv.lock +0 -0
|
@@ -339,6 +339,18 @@ def cmd_init(args: argparse.Namespace) -> None:
|
|
|
339
339
|
cfg.pop(key, None)
|
|
340
340
|
config.save(cfg)
|
|
341
341
|
|
|
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
|
+
try:
|
|
347
|
+
_tui_guard()
|
|
348
|
+
from methodproof.tui.init import run as tui_init
|
|
349
|
+
tui_init(cfg)
|
|
350
|
+
return
|
|
351
|
+
except SystemExit:
|
|
352
|
+
pass # textual not installed — fall through to classic
|
|
353
|
+
|
|
342
354
|
if not cfg.get("consent_acknowledged"):
|
|
343
355
|
cfg = _run_consent(cfg)
|
|
344
356
|
config.save(cfg)
|
|
@@ -2079,11 +2091,14 @@ def cmd_extension(args: argparse.Namespace) -> None:
|
|
|
2079
2091
|
|
|
2080
2092
|
|
|
2081
2093
|
def main() -> None:
|
|
2094
|
+
from methodproof import __version__
|
|
2082
2095
|
p = argparse.ArgumentParser(prog="methodproof", description=_banner())
|
|
2096
|
+
p.add_argument("--version", action="version", version=f"methodproof {__version__}")
|
|
2083
2097
|
sub = p.add_subparsers(dest="cmd")
|
|
2084
2098
|
|
|
2085
2099
|
s = sub.add_parser("init", help="Install shell hook")
|
|
2086
2100
|
s.add_argument("--force", action="store_true", help="Re-run all setup prompts from scratch")
|
|
2101
|
+
_add_ui_flags(s)
|
|
2087
2102
|
sub.add_parser("shell-hook", help="Print shell hook for eval (activates without restart)")
|
|
2088
2103
|
s = sub.add_parser("start", help="Start recording")
|
|
2089
2104
|
s.add_argument("--dir", help="Directory to watch")
|
|
@@ -0,0 +1,387 @@
|
|
|
1
|
+
"""Textual TUI for mp init — two-screen setup wizard."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from textual.app import App, ComposeResult
|
|
5
|
+
from textual.binding import Binding
|
|
6
|
+
from textual.containers import Horizontal, ScrollableContainer, Vertical
|
|
7
|
+
from textual.screen import Screen
|
|
8
|
+
from textual.widgets import Button, Footer, Header, Label, RichLog, Rule, Static, Switch
|
|
9
|
+
|
|
10
|
+
from methodproof import config as cfg_mod
|
|
11
|
+
from methodproof.tui.theme import BASE_CSS, BORDER, DIM, GOLD, GREEN, PURPLE, RED, TEXT
|
|
12
|
+
|
|
13
|
+
_REDACTABLE = [
|
|
14
|
+
("command_output", "Terminal output"),
|
|
15
|
+
("ai_prompts", "AI prompt text"),
|
|
16
|
+
("ai_responses", "AI response text"),
|
|
17
|
+
("code_capture", "File diffs"),
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
_CSS = BASE_CSS + f"""
|
|
21
|
+
PrefsScreen {{
|
|
22
|
+
padding: 0;
|
|
23
|
+
}}
|
|
24
|
+
#prefs-scroll {{
|
|
25
|
+
padding: 1 3;
|
|
26
|
+
}}
|
|
27
|
+
.section-heading {{
|
|
28
|
+
color: {GOLD};
|
|
29
|
+
text-style: bold;
|
|
30
|
+
margin: 1 0 0 0;
|
|
31
|
+
}}
|
|
32
|
+
.section-sub {{
|
|
33
|
+
color: {DIM};
|
|
34
|
+
margin: 0 0 1 0;
|
|
35
|
+
}}
|
|
36
|
+
.toggle-row {{
|
|
37
|
+
height: 2;
|
|
38
|
+
align: left middle;
|
|
39
|
+
}}
|
|
40
|
+
.toggle-row Switch {{
|
|
41
|
+
margin: 0 1 0 0;
|
|
42
|
+
width: 4;
|
|
43
|
+
}}
|
|
44
|
+
.row-label {{
|
|
45
|
+
color: {TEXT};
|
|
46
|
+
}}
|
|
47
|
+
.pro-row .row-label {{
|
|
48
|
+
color: {PURPLE};
|
|
49
|
+
}}
|
|
50
|
+
.pro-badge {{
|
|
51
|
+
background: #200a26;
|
|
52
|
+
color: {PURPLE};
|
|
53
|
+
padding: 0 1;
|
|
54
|
+
margin: 0 0 0 1;
|
|
55
|
+
width: 5;
|
|
56
|
+
}}
|
|
57
|
+
.opt-row {{
|
|
58
|
+
height: 2;
|
|
59
|
+
align: left middle;
|
|
60
|
+
}}
|
|
61
|
+
.opt-row Switch {{
|
|
62
|
+
margin: 0 1 0 0;
|
|
63
|
+
width: 4;
|
|
64
|
+
}}
|
|
65
|
+
#fs-status {{
|
|
66
|
+
color: {DIM};
|
|
67
|
+
height: 1;
|
|
68
|
+
margin: 1 0 0 0;
|
|
69
|
+
}}
|
|
70
|
+
#fs-status.full {{
|
|
71
|
+
color: {GOLD};
|
|
72
|
+
}}
|
|
73
|
+
#begin-btn {{
|
|
74
|
+
margin: 2 0 1 0;
|
|
75
|
+
background: {GOLD};
|
|
76
|
+
color: #12110f;
|
|
77
|
+
border: none;
|
|
78
|
+
width: 20;
|
|
79
|
+
}}
|
|
80
|
+
|
|
81
|
+
ResultsScreen {{
|
|
82
|
+
padding: 0;
|
|
83
|
+
}}
|
|
84
|
+
#results-log {{
|
|
85
|
+
padding: 1 2;
|
|
86
|
+
border: none;
|
|
87
|
+
}}
|
|
88
|
+
#eval-box {{
|
|
89
|
+
background: #050403;
|
|
90
|
+
border: solid {BORDER};
|
|
91
|
+
margin: 1 2;
|
|
92
|
+
padding: 1 2;
|
|
93
|
+
height: 5;
|
|
94
|
+
}}
|
|
95
|
+
#eval-label {{
|
|
96
|
+
color: {DIM};
|
|
97
|
+
margin: 0 0 1 0;
|
|
98
|
+
}}
|
|
99
|
+
#eval-cmd {{
|
|
100
|
+
color: {GOLD};
|
|
101
|
+
text-style: bold;
|
|
102
|
+
}}
|
|
103
|
+
"""
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
class PrefsScreen(Screen[dict | None]):
|
|
107
|
+
"""Step 1: collect all preferences before any side effects run."""
|
|
108
|
+
|
|
109
|
+
BINDINGS = [
|
|
110
|
+
Binding("enter", "begin", "begin setup"),
|
|
111
|
+
Binding("escape", "cancel", "cancel"),
|
|
112
|
+
]
|
|
113
|
+
|
|
114
|
+
def __init__(self, cfg: dict) -> None:
|
|
115
|
+
super().__init__()
|
|
116
|
+
self._capture = dict(cfg.get("capture", {}))
|
|
117
|
+
self._redact = dict(cfg.get("publish_redact", {}))
|
|
118
|
+
self._auto_update = cfg.get("auto_update", True)
|
|
119
|
+
self._alias = cfg.get("alias_installed", True)
|
|
120
|
+
|
|
121
|
+
def compose(self) -> ComposeResult:
|
|
122
|
+
yield Header(show_clock=False)
|
|
123
|
+
with ScrollableContainer(id="prefs-scroll"):
|
|
124
|
+
yield Static("Capture settings", classes="section-heading")
|
|
125
|
+
yield Static("Choose what MethodProof records during your sessions.", classes="section-sub")
|
|
126
|
+
|
|
127
|
+
for cat in cfg_mod.STANDARD_CATEGORIES:
|
|
128
|
+
desc = cfg_mod.CAPTURE_DESCRIPTIONS.get(cat, cat)
|
|
129
|
+
enabled = self._capture.get(cat, True)
|
|
130
|
+
with Horizontal(classes="toggle-row", id=f"row-cap-{cat}"):
|
|
131
|
+
yield Switch(value=enabled, id=f"cap-{cat}", animate=False)
|
|
132
|
+
yield Label(desc, classes="row-label")
|
|
133
|
+
|
|
134
|
+
with Horizontal(classes="toggle-row pro-row", id="row-cap-code_capture"):
|
|
135
|
+
yield Switch(value=self._capture.get("code_capture", False),
|
|
136
|
+
id="cap-code_capture", animate=False)
|
|
137
|
+
yield Label("Full code diffs and git patches", classes="row-label")
|
|
138
|
+
yield Static("Pro", classes="pro-badge")
|
|
139
|
+
|
|
140
|
+
yield Static("", id="fs-status")
|
|
141
|
+
|
|
142
|
+
yield Rule()
|
|
143
|
+
yield Static("Publish redaction", classes="section-heading")
|
|
144
|
+
yield Static(
|
|
145
|
+
"Fields stripped when you make a session public via mp publish.",
|
|
146
|
+
classes="section-sub",
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
for key, desc in _REDACTABLE:
|
|
150
|
+
redacted = self._redact.get(key, True)
|
|
151
|
+
with Horizontal(classes="toggle-row", id=f"row-red-{key}"):
|
|
152
|
+
yield Switch(value=redacted, id=f"red-{key}", animate=False)
|
|
153
|
+
yield Label(f"Redact: {desc}", classes="row-label")
|
|
154
|
+
|
|
155
|
+
yield Rule()
|
|
156
|
+
yield Static("Options", classes="section-heading")
|
|
157
|
+
|
|
158
|
+
with Horizontal(classes="opt-row"):
|
|
159
|
+
yield Switch(value=self._auto_update, id="opt-auto-update", animate=False)
|
|
160
|
+
yield Label("Auto-update before each session", classes="row-label")
|
|
161
|
+
|
|
162
|
+
with Horizontal(classes="opt-row"):
|
|
163
|
+
yield Switch(value=self._alias, id="opt-alias", animate=False)
|
|
164
|
+
yield Label("Install `mp` shorthand alias", classes="row-label")
|
|
165
|
+
|
|
166
|
+
yield Button("Begin Setup →", id="begin-btn", variant="primary")
|
|
167
|
+
|
|
168
|
+
yield Footer()
|
|
169
|
+
|
|
170
|
+
def on_mount(self) -> None:
|
|
171
|
+
self._refresh_fs()
|
|
172
|
+
|
|
173
|
+
def on_switch_changed(self, event: Switch.Changed) -> None:
|
|
174
|
+
sid = event.switch.id or ""
|
|
175
|
+
if sid.startswith("cap-"):
|
|
176
|
+
cat = sid[4:]
|
|
177
|
+
self._capture[cat] = event.value
|
|
178
|
+
self._refresh_fs()
|
|
179
|
+
elif sid.startswith("red-"):
|
|
180
|
+
self._redact[sid[4:]] = event.value
|
|
181
|
+
elif sid == "opt-auto-update":
|
|
182
|
+
self._auto_update = event.value
|
|
183
|
+
elif sid == "opt-alias":
|
|
184
|
+
self._alias = event.value
|
|
185
|
+
|
|
186
|
+
def _refresh_fs(self) -> None:
|
|
187
|
+
all_on = all(self._capture.get(c, True) for c in cfg_mod.STANDARD_CATEGORIES)
|
|
188
|
+
widget = self.query_one("#fs-status", Static)
|
|
189
|
+
if all_on:
|
|
190
|
+
widget.update(f"[{GOLD}]★ Full Spectrum — live streaming unlocked[/{GOLD}]")
|
|
191
|
+
widget.add_class("full")
|
|
192
|
+
else:
|
|
193
|
+
widget.update(f"[{DIM}]Enable all 10 standard categories for Full Spectrum[/{DIM}]")
|
|
194
|
+
widget.remove_class("full")
|
|
195
|
+
|
|
196
|
+
def on_button_pressed(self, event: Button.Pressed) -> None:
|
|
197
|
+
if event.button.id == "begin-btn":
|
|
198
|
+
self.action_begin()
|
|
199
|
+
|
|
200
|
+
def action_begin(self) -> None:
|
|
201
|
+
self.dismiss({
|
|
202
|
+
"capture": self._capture,
|
|
203
|
+
"publish_redact": self._redact,
|
|
204
|
+
"auto_update": self._auto_update,
|
|
205
|
+
"install_alias": self._alias,
|
|
206
|
+
})
|
|
207
|
+
|
|
208
|
+
def action_cancel(self) -> None:
|
|
209
|
+
self.dismiss(None)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class ResultsScreen(Screen[None]):
|
|
213
|
+
"""Step 2: run side effects and display progress."""
|
|
214
|
+
|
|
215
|
+
BINDINGS = [Binding("escape", "done", "done")]
|
|
216
|
+
|
|
217
|
+
def __init__(self, cfg: dict, prefs: dict) -> None:
|
|
218
|
+
super().__init__()
|
|
219
|
+
self._cfg = cfg
|
|
220
|
+
self._prefs = prefs
|
|
221
|
+
|
|
222
|
+
def compose(self) -> ComposeResult:
|
|
223
|
+
yield Header(show_clock=False)
|
|
224
|
+
yield RichLog(id="results-log", highlight=True, markup=True)
|
|
225
|
+
with Vertical(id="eval-box"):
|
|
226
|
+
yield Static("Activate now (or restart your shell):", id="eval-label")
|
|
227
|
+
yield Static('eval "$(methodproof shell-hook)"', id="eval-cmd", markup=False)
|
|
228
|
+
yield Footer()
|
|
229
|
+
|
|
230
|
+
def on_mount(self) -> None:
|
|
231
|
+
self.run_worker(self._run_setup, exclusive=True, thread=True)
|
|
232
|
+
|
|
233
|
+
def _log(self, msg: str) -> None:
|
|
234
|
+
self.query_one(RichLog).write(msg)
|
|
235
|
+
|
|
236
|
+
def _run_setup(self) -> None:
|
|
237
|
+
from methodproof import config, store
|
|
238
|
+
from methodproof.hooks import hook
|
|
239
|
+
|
|
240
|
+
cfg = self._cfg
|
|
241
|
+
prefs = self._prefs
|
|
242
|
+
|
|
243
|
+
# Apply preferences
|
|
244
|
+
cfg["capture"] = prefs["capture"]
|
|
245
|
+
cfg["publish_redact"] = prefs["publish_redact"]
|
|
246
|
+
cfg["auto_update"] = prefs["auto_update"]
|
|
247
|
+
cfg["auto_update_offered"] = True
|
|
248
|
+
cfg["alias_offered"] = True
|
|
249
|
+
cfg["ui_mode_offered"] = True
|
|
250
|
+
cfg["ui_mode"] = True
|
|
251
|
+
cfg["consent_acknowledged"] = True
|
|
252
|
+
|
|
253
|
+
if prefs["install_alias"]:
|
|
254
|
+
try:
|
|
255
|
+
from methodproof.cli import _install_alias
|
|
256
|
+
_install_alias()
|
|
257
|
+
cfg["alias_installed"] = True
|
|
258
|
+
self._log(f"[{GREEN}]✓[/{GREEN}] Alias: mp → methodproof")
|
|
259
|
+
except Exception as exc:
|
|
260
|
+
self._log(f"[{DIM}] Alias: skipped ({exc})[/{DIM}]")
|
|
261
|
+
else:
|
|
262
|
+
self._log(f"[{DIM}] Alias: skipped[/{DIM}]")
|
|
263
|
+
|
|
264
|
+
config.save(cfg)
|
|
265
|
+
store.init_db()
|
|
266
|
+
|
|
267
|
+
# Shell hook
|
|
268
|
+
capture = cfg["capture"]
|
|
269
|
+
if capture.get("terminal_commands", True):
|
|
270
|
+
try:
|
|
271
|
+
rc = hook.install()
|
|
272
|
+
self._log(f"[{GREEN}]✓[/{GREEN}] Shell hook: {rc}")
|
|
273
|
+
except Exception as exc:
|
|
274
|
+
self._log(f"[{RED}]✗[/{RED}] Shell hook: {exc}")
|
|
275
|
+
else:
|
|
276
|
+
self._log(f"[{DIM}] Shell hook: skipped (terminal_commands off)[/{DIM}]")
|
|
277
|
+
|
|
278
|
+
# AI hooks
|
|
279
|
+
ai_enabled = capture.get("ai_prompts", True) or capture.get("ai_responses", True)
|
|
280
|
+
if ai_enabled:
|
|
281
|
+
try:
|
|
282
|
+
from methodproof.hooks.install import install as install_claude_hooks
|
|
283
|
+
result = install_claude_hooks()
|
|
284
|
+
if result is None:
|
|
285
|
+
self._log(f"[{DIM}] Claude Code: not found[/{DIM}]")
|
|
286
|
+
else:
|
|
287
|
+
self._log(f"[{GREEN}]✓[/{GREEN}] Claude Code hooks: {result}")
|
|
288
|
+
except Exception as exc:
|
|
289
|
+
self._log(f"[{DIM}] Claude Code: {exc}[/{DIM}]")
|
|
290
|
+
|
|
291
|
+
try:
|
|
292
|
+
from methodproof.mcp import register_with_claude
|
|
293
|
+
mcp = register_with_claude()
|
|
294
|
+
if mcp is None:
|
|
295
|
+
self._log(f"[{DIM}] Claude Code MCP: skipped[/{DIM}]")
|
|
296
|
+
elif mcp == "already registered":
|
|
297
|
+
self._log(f"[{GREEN}]✓[/{GREEN}] Claude Code MCP: already registered")
|
|
298
|
+
else:
|
|
299
|
+
self._log(f"[{GREEN}]✓[/{GREEN}] Claude Code MCP: registered in {mcp}")
|
|
300
|
+
except Exception as exc:
|
|
301
|
+
self._log(f"[{DIM}] MCP: {exc}[/{DIM}]")
|
|
302
|
+
|
|
303
|
+
try:
|
|
304
|
+
from methodproof.hooks.wrappers import install as install_wrappers
|
|
305
|
+
wrapped = install_wrappers()
|
|
306
|
+
if wrapped:
|
|
307
|
+
self._log(f"[{GREEN}]✓[/{GREEN}] AI CLI wrappers: {', '.join(wrapped)}")
|
|
308
|
+
else:
|
|
309
|
+
self._log(f"[{DIM}] AI CLI wrappers: no tools found[/{DIM}]")
|
|
310
|
+
except Exception as exc:
|
|
311
|
+
self._log(f"[{DIM}] AI CLI wrappers: {exc}[/{DIM}]")
|
|
312
|
+
|
|
313
|
+
try:
|
|
314
|
+
from methodproof.hooks.openclaw_install import install as install_oc, install_skill
|
|
315
|
+
oc = install_oc()
|
|
316
|
+
if oc is None:
|
|
317
|
+
self._log(f"[{DIM}] OpenClaw: not found[/{DIM}]")
|
|
318
|
+
else:
|
|
319
|
+
self._log(f"[{GREEN}]✓[/{GREEN}] OpenClaw hooks: {oc}")
|
|
320
|
+
skill = install_skill()
|
|
321
|
+
if skill:
|
|
322
|
+
self._log(f"[{GREEN}]✓[/{GREEN}] OpenClaw skill: {skill}")
|
|
323
|
+
except Exception as exc:
|
|
324
|
+
self._log(f"[{DIM}] OpenClaw: {exc}[/{DIM}]")
|
|
325
|
+
else:
|
|
326
|
+
self._log(f"[{DIM}] AI hooks: skipped[/{DIM}]")
|
|
327
|
+
|
|
328
|
+
# Local AI ports — skip interactive prompt, use defaults
|
|
329
|
+
if ai_enabled and not cfg.get("local_ai_ports_offered"):
|
|
330
|
+
cfg["local_ai_ports_offered"] = True
|
|
331
|
+
cfg["local_ai_ports"] = []
|
|
332
|
+
config.save(cfg)
|
|
333
|
+
self._log(f"[{DIM}] Local AI ports: using defaults (Ollama 11434, Jan 1234)[/{DIM}]")
|
|
334
|
+
|
|
335
|
+
# Signing key
|
|
336
|
+
try:
|
|
337
|
+
from methodproof.integrity import has_keypair
|
|
338
|
+
if not has_keypair():
|
|
339
|
+
from methodproof.integrity import generate_keypair
|
|
340
|
+
pub = generate_keypair()
|
|
341
|
+
self._log(f"[{GREEN}]✓[/{GREEN}] Signing key: generated ({len(pub)} bytes)")
|
|
342
|
+
else:
|
|
343
|
+
self._log(f"[{GREEN}]✓[/{GREEN}] Signing key: exists")
|
|
344
|
+
except ImportError:
|
|
345
|
+
self._log(f"[{DIM}] Signing key: skipped (pip install methodproof[signing])[/{DIM}]")
|
|
346
|
+
|
|
347
|
+
# Research consent sync
|
|
348
|
+
if cfg.get("token"):
|
|
349
|
+
try:
|
|
350
|
+
cfg["_pending_research_sync"] = True
|
|
351
|
+
config.save(cfg)
|
|
352
|
+
from methodproof.sync import sync_research_consent
|
|
353
|
+
sync_research_consent(cfg["token"], cfg["api_url"])
|
|
354
|
+
self._log(f"[{GREEN}]✓[/{GREEN}] Research consent synced")
|
|
355
|
+
except Exception:
|
|
356
|
+
pass
|
|
357
|
+
|
|
358
|
+
self._log("")
|
|
359
|
+
self._log(f"[{GOLD}]Setup complete.[/{GOLD}] Press Esc to exit.")
|
|
360
|
+
|
|
361
|
+
def action_done(self) -> None:
|
|
362
|
+
self.dismiss(None)
|
|
363
|
+
|
|
364
|
+
|
|
365
|
+
class InitApp(App[None]):
|
|
366
|
+
"""mp init setup wizard — preferences then install."""
|
|
367
|
+
|
|
368
|
+
TITLE = "methodproof — mp init"
|
|
369
|
+
CSS = _CSS
|
|
370
|
+
|
|
371
|
+
def __init__(self, cfg: dict) -> None:
|
|
372
|
+
super().__init__()
|
|
373
|
+
self._cfg = cfg
|
|
374
|
+
|
|
375
|
+
def on_mount(self) -> None:
|
|
376
|
+
self.push_screen(PrefsScreen(self._cfg), self._on_prefs_done)
|
|
377
|
+
|
|
378
|
+
def _on_prefs_done(self, prefs: dict | None) -> None:
|
|
379
|
+
if prefs is None:
|
|
380
|
+
self.exit(None)
|
|
381
|
+
return
|
|
382
|
+
self.push_screen(ResultsScreen(self._cfg, prefs))
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
def run(cfg: dict) -> None:
|
|
386
|
+
"""Launch the init wizard."""
|
|
387
|
+
InitApp(cfg).run()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "methodproof"
|
|
3
|
-
version = "0.7.
|
|
3
|
+
version = "0.7.16"
|
|
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"]
|
|
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
|
|
File without changes
|