methodproof 0.5.3__tar.gz → 0.6.0__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 (64) hide show
  1. {methodproof-0.5.3 → methodproof-0.6.0}/PKG-INFO +89 -6
  2. {methodproof-0.5.3 → methodproof-0.6.0}/README.md +88 -5
  3. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/__init__.py +1 -1
  4. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/_daemon.py +2 -1
  5. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/agents/base.py +7 -7
  6. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/bridge.py +13 -5
  7. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/cli.py +1 -0
  8. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/config.py +2 -3
  9. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/sync.py +15 -5
  10. {methodproof-0.5.3 → methodproof-0.6.0}/pyproject.toml +1 -1
  11. {methodproof-0.5.3 → methodproof-0.6.0}/uv.lock +2 -2
  12. {methodproof-0.5.3 → methodproof-0.6.0}/.github/workflows/ci.yml +0 -0
  13. {methodproof-0.5.3 → methodproof-0.6.0}/.gitignore +0 -0
  14. {methodproof-0.5.3 → methodproof-0.6.0}/CHANGELOG.md +0 -0
  15. {methodproof-0.5.3 → methodproof-0.6.0}/LICENSE +0 -0
  16. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/__main__.py +0 -0
  17. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/agents/__init__.py +0 -0
  18. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/agents/music.py +0 -0
  19. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/agents/terminal.py +0 -0
  20. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/agents/watcher.py +0 -0
  21. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/analysis.py +0 -0
  22. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/binding.py +0 -0
  23. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/bip39.py +0 -0
  24. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/crypto.py +0 -0
  25. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/graph.py +0 -0
  26. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/hook.py +0 -0
  27. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/hooks/__init__.py +0 -0
  28. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/hooks/claude_code.py +0 -0
  29. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/hooks/claude_code.sh +0 -0
  30. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/hooks/cline_hook.sh +0 -0
  31. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/hooks/codex_hook.sh +0 -0
  32. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/hooks/gemini_hook.sh +0 -0
  33. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/hooks/install.py +0 -0
  34. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/hooks/kiro_hook.sh +0 -0
  35. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/hooks/mcp_register.py +0 -0
  36. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/hooks/openclaw/HOOK.md +0 -0
  37. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/hooks/openclaw/handler.ts +0 -0
  38. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/hooks/openclaw_install.py +0 -0
  39. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/hooks/opencode_plugin.js +0 -0
  40. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/hooks/wrappers.py +0 -0
  41. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/integrity.py +0 -0
  42. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/kdf.py +0 -0
  43. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/keychain.py +0 -0
  44. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/live.py +0 -0
  45. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/lock.py +0 -0
  46. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/mcp.py +0 -0
  47. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/migrate_db.py +0 -0
  48. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/proxy.py +0 -0
  49. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/proxy_daemon.py +0 -0
  50. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/repos.py +0 -0
  51. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/skills/methodproof/SKILL.md +0 -0
  52. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/store.py +0 -0
  53. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/viewer.py +0 -0
  54. {methodproof-0.5.3 → methodproof-0.6.0}/methodproof/wordlist.py +0 -0
  55. {methodproof-0.5.3 → methodproof-0.6.0}/test_windows_compat.py +0 -0
  56. {methodproof-0.5.3 → methodproof-0.6.0}/tests/__init__.py +0 -0
  57. {methodproof-0.5.3 → methodproof-0.6.0}/tests/test_analysis.py +0 -0
  58. {methodproof-0.5.3 → methodproof-0.6.0}/tests/test_graph.py +0 -0
  59. {methodproof-0.5.3 → methodproof-0.6.0}/tests/test_hooks.py +0 -0
  60. {methodproof-0.5.3 → methodproof-0.6.0}/tests/test_live.py +0 -0
  61. {methodproof-0.5.3 → methodproof-0.6.0}/tests/test_openclaw_hooks.py +0 -0
  62. {methodproof-0.5.3 → methodproof-0.6.0}/tests/test_security.py +0 -0
  63. {methodproof-0.5.3 → methodproof-0.6.0}/tests/test_store.py +0 -0
  64. {methodproof-0.5.3 → methodproof-0.6.0}/tests/test_wrappers.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: methodproof
3
- Version: 0.5.3
3
+ Version: 0.6.0
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
@@ -67,6 +67,87 @@ methodproof view # explore your session in the browser
67
67
  - **Auto-detection** — hooks for shell, Claude Code, OpenClaw, codex, gemini, aider installed automatically
68
68
  - **Platform sync** — `methodproof push` uploads sessions. `methodproof publish` makes them public and shareable
69
69
 
70
+ ## Security Architecture
71
+
72
+ Every event passes through consent gating, encryption, and hash chaining before touching disk. The platform adds a server co-signature on push, creating two-party evidence.
73
+
74
+ ```mermaid
75
+ flowchart TB
76
+ subgraph LOCAL["LOCAL MACHINE"]
77
+ direction TB
78
+ subgraph AGENTS["Capture Agents"]
79
+ direction LR
80
+ W["File Watcher"] & T["Terminal Hook"] & B["Browser Bridge"] & H["AI Tool Hooks"]
81
+ end
82
+ W & T & B & H -->|"raw event"| EMIT["emit(type, metadata)"]
83
+
84
+ subgraph CONSENT["Consent Layer"]
85
+ direction TB
86
+ EMIT --> EG{"Event Gate"}
87
+ EG -->|"category OFF"| DROP["Dropped"]
88
+ EG -->|"category ON"| FG["Field Gate: strip opted-out fields"]
89
+ FG --> JG{"Journal Mode?"}
90
+ JG -->|"OFF: structural only"| STRIP["Strip content fields"]
91
+ JG -->|"ON: full content"| KEEP["Keep all fields"]
92
+ end
93
+
94
+ subgraph CRYPTO["Encryption + Integrity"]
95
+ direction TB
96
+ STRIP & KEEP --> AES["AES-256-GCM: encrypt sensitive fields"]
97
+ AES --> LOCK["Thread Lock: atomic hash + buffer"]
98
+ LOCK --> CHAIN["SHA-256 Hash Chain"]
99
+ CHAIN --> BUF["Batched Flush"]
100
+ end
101
+
102
+ BUF --> DB[("SQLite WAL")]
103
+ BUF -.->|"--live"| WS["WebSocket Stream"]
104
+
105
+ subgraph KEYS["Key Vault"]
106
+ direction LR
107
+ ENT["Entropy"] --> KDF["Key Derivation"]
108
+ KDF --> DBK["Encryption Key"]
109
+ KDF --> BINDK["Binding Key"]
110
+ KDF --> ED25["Signing Key"]
111
+ ENT -.-> REC["Recovery Phrase"]
112
+ KDF -.-> KC["OS Keychain"]
113
+ end
114
+ end
115
+
116
+ subgraph PUSH["PUSH PROTOCOL"]
117
+ direction TB
118
+ DB --> BATCH["Batched Upload"]
119
+ BATCH --> BIND["Session Binding: HMAC over session metadata"]
120
+ BIND --> SIGN["Ed25519 Sign: session summary"]
121
+ end
122
+
123
+ subgraph PLATFORM["PLATFORM TRUST BOUNDARY"]
124
+ direction TB
125
+ SIGN --> VERIFY["Verify Ed25519 against registered public key"]
126
+ VERIFY --> COSIG["Server Co-Sign: HMAC over attestation receipt"]
127
+ COSIG --> NEO[("Graph Store")]
128
+ NEO --> SCORE["Integrity Score: chain + attestation + cosig + git xref + anomaly"]
129
+ end
130
+
131
+ style DROP fill:#d93326,stroke:#d93326,color:#fff
132
+ style AES fill:#803794,stroke:#803794,color:#fff
133
+ style CHAIN fill:#803794,stroke:#803794,color:#fff
134
+ style LOCK fill:#803794,stroke:#803794,color:#fff
135
+ style EG fill:#109446,stroke:#109446,color:#fff
136
+ style JG fill:#109446,stroke:#109446,color:#fff
137
+ style STRIP fill:#109446,stroke:#109446,color:#fff
138
+ style VERIFY fill:#c9a84c,stroke:#c9a84c,color:#fff
139
+ style COSIG fill:#c9a84c,stroke:#c9a84c,color:#fff
140
+ style SCORE fill:#c9a84c,stroke:#c9a84c,color:#fff
141
+ style SIGN fill:#192a56,stroke:#192a56,color:#fff
142
+ style BIND fill:#192a56,stroke:#192a56,color:#fff
143
+ style DB fill:#192a56,stroke:#192a56,color:#fff
144
+ style NEO fill:#192a56,stroke:#192a56,color:#fff
145
+ style KC fill:#803794,stroke:#803794,color:#fff
146
+ style REC fill:#803794,stroke:#803794,color:#fff
147
+ ```
148
+
149
+ <sup>Green = consent gates · Purple = cryptographic operations · Navy = storage + binding · Gold = integrity verification</sup>
150
+
70
151
  ## Commands
71
152
 
72
153
  | Command | What it does |
@@ -167,13 +248,15 @@ At session end, outcome metrics are computed: first-shot apply rate, follow-up s
167
248
  <details>
168
249
  <summary>Integrity verification</summary>
169
250
 
170
- Three layers ensure session data hasn't been tampered with:
251
+ Four layers ensure session data hasn't been tampered with (see [architecture diagram](#security-architecture) above):
252
+
253
+ **Hash-chained events** — every event includes a SHA-256 hash linking to the previous event. Hash computation is thread-safe (atomic with buffer append). Any modification breaks the chain, detectable via `GET /sessions/{id}/chain/verify`.
171
254
 
172
- **Hash-chained events** — every event includes a SHA-256 hash linking to the previous event. Any modification breaks the chain, detectable via `GET /sessions/{id}/chain/verify`.
255
+ **Ed25519 attestation** — on `methodproof push`, the CLI signs a session summary with your private key. Key generated during `methodproof init`, stored in `~/.methodproof/`.
173
256
 
174
- **Ed25519 attestation** — on `methodproof push`, the CLI signs a session summary with your private key. Install with `pip install methodproof[signing]`. Key generated during `methodproof init`, stored in `~/.methodproof/config.json`.
257
+ **Server co-signature** — the platform independently signs the attestation receipt with its own key and timestamp, creating two-party evidence. Sessions pushed without server co-signature receive a lower integrity score.
175
258
 
176
- **Binary hash self-reporting** — the CLI reports its own binary hash on push. The platform compares against known release hashes to detect modified builds.
259
+ **Binary hash self-reporting** — the CLI reports its own source hash on push. The platform compares against known release hashes to detect modified builds.
177
260
 
178
261
  </details>
179
262
 
@@ -222,7 +305,7 @@ methodproof start
222
305
 
223
306
  **Excluded patterns:** `__pycache__`, `.pyc`, `.git/`, `node_modules`, `.DS_Store`, `.swp`, temp files ending in `~`
224
307
 
225
- **Git commits** are detected by polling `.git/refs/heads/` every 2 seconds — only commits in a git repo rooted at (or above) the watch directory are captured.
308
+ **Git commits** are detected automatically — only commits in a git repo rooted at (or above) the watch directory are captured.
226
309
 
227
310
  ## Data Directory
228
311
 
@@ -52,6 +52,87 @@ methodproof view # explore your session in the browser
52
52
  - **Auto-detection** — hooks for shell, Claude Code, OpenClaw, codex, gemini, aider installed automatically
53
53
  - **Platform sync** — `methodproof push` uploads sessions. `methodproof publish` makes them public and shareable
54
54
 
55
+ ## Security Architecture
56
+
57
+ Every event passes through consent gating, encryption, and hash chaining before touching disk. The platform adds a server co-signature on push, creating two-party evidence.
58
+
59
+ ```mermaid
60
+ flowchart TB
61
+ subgraph LOCAL["LOCAL MACHINE"]
62
+ direction TB
63
+ subgraph AGENTS["Capture Agents"]
64
+ direction LR
65
+ W["File Watcher"] & T["Terminal Hook"] & B["Browser Bridge"] & H["AI Tool Hooks"]
66
+ end
67
+ W & T & B & H -->|"raw event"| EMIT["emit(type, metadata)"]
68
+
69
+ subgraph CONSENT["Consent Layer"]
70
+ direction TB
71
+ EMIT --> EG{"Event Gate"}
72
+ EG -->|"category OFF"| DROP["Dropped"]
73
+ EG -->|"category ON"| FG["Field Gate: strip opted-out fields"]
74
+ FG --> JG{"Journal Mode?"}
75
+ JG -->|"OFF: structural only"| STRIP["Strip content fields"]
76
+ JG -->|"ON: full content"| KEEP["Keep all fields"]
77
+ end
78
+
79
+ subgraph CRYPTO["Encryption + Integrity"]
80
+ direction TB
81
+ STRIP & KEEP --> AES["AES-256-GCM: encrypt sensitive fields"]
82
+ AES --> LOCK["Thread Lock: atomic hash + buffer"]
83
+ LOCK --> CHAIN["SHA-256 Hash Chain"]
84
+ CHAIN --> BUF["Batched Flush"]
85
+ end
86
+
87
+ BUF --> DB[("SQLite WAL")]
88
+ BUF -.->|"--live"| WS["WebSocket Stream"]
89
+
90
+ subgraph KEYS["Key Vault"]
91
+ direction LR
92
+ ENT["Entropy"] --> KDF["Key Derivation"]
93
+ KDF --> DBK["Encryption Key"]
94
+ KDF --> BINDK["Binding Key"]
95
+ KDF --> ED25["Signing Key"]
96
+ ENT -.-> REC["Recovery Phrase"]
97
+ KDF -.-> KC["OS Keychain"]
98
+ end
99
+ end
100
+
101
+ subgraph PUSH["PUSH PROTOCOL"]
102
+ direction TB
103
+ DB --> BATCH["Batched Upload"]
104
+ BATCH --> BIND["Session Binding: HMAC over session metadata"]
105
+ BIND --> SIGN["Ed25519 Sign: session summary"]
106
+ end
107
+
108
+ subgraph PLATFORM["PLATFORM TRUST BOUNDARY"]
109
+ direction TB
110
+ SIGN --> VERIFY["Verify Ed25519 against registered public key"]
111
+ VERIFY --> COSIG["Server Co-Sign: HMAC over attestation receipt"]
112
+ COSIG --> NEO[("Graph Store")]
113
+ NEO --> SCORE["Integrity Score: chain + attestation + cosig + git xref + anomaly"]
114
+ end
115
+
116
+ style DROP fill:#d93326,stroke:#d93326,color:#fff
117
+ style AES fill:#803794,stroke:#803794,color:#fff
118
+ style CHAIN fill:#803794,stroke:#803794,color:#fff
119
+ style LOCK fill:#803794,stroke:#803794,color:#fff
120
+ style EG fill:#109446,stroke:#109446,color:#fff
121
+ style JG fill:#109446,stroke:#109446,color:#fff
122
+ style STRIP fill:#109446,stroke:#109446,color:#fff
123
+ style VERIFY fill:#c9a84c,stroke:#c9a84c,color:#fff
124
+ style COSIG fill:#c9a84c,stroke:#c9a84c,color:#fff
125
+ style SCORE fill:#c9a84c,stroke:#c9a84c,color:#fff
126
+ style SIGN fill:#192a56,stroke:#192a56,color:#fff
127
+ style BIND fill:#192a56,stroke:#192a56,color:#fff
128
+ style DB fill:#192a56,stroke:#192a56,color:#fff
129
+ style NEO fill:#192a56,stroke:#192a56,color:#fff
130
+ style KC fill:#803794,stroke:#803794,color:#fff
131
+ style REC fill:#803794,stroke:#803794,color:#fff
132
+ ```
133
+
134
+ <sup>Green = consent gates · Purple = cryptographic operations · Navy = storage + binding · Gold = integrity verification</sup>
135
+
55
136
  ## Commands
56
137
 
57
138
  | Command | What it does |
@@ -152,13 +233,15 @@ At session end, outcome metrics are computed: first-shot apply rate, follow-up s
152
233
  <details>
153
234
  <summary>Integrity verification</summary>
154
235
 
155
- Three layers ensure session data hasn't been tampered with:
236
+ Four layers ensure session data hasn't been tampered with (see [architecture diagram](#security-architecture) above):
237
+
238
+ **Hash-chained events** — every event includes a SHA-256 hash linking to the previous event. Hash computation is thread-safe (atomic with buffer append). Any modification breaks the chain, detectable via `GET /sessions/{id}/chain/verify`.
156
239
 
157
- **Hash-chained events** — every event includes a SHA-256 hash linking to the previous event. Any modification breaks the chain, detectable via `GET /sessions/{id}/chain/verify`.
240
+ **Ed25519 attestation** — on `methodproof push`, the CLI signs a session summary with your private key. Key generated during `methodproof init`, stored in `~/.methodproof/`.
158
241
 
159
- **Ed25519 attestation** — on `methodproof push`, the CLI signs a session summary with your private key. Install with `pip install methodproof[signing]`. Key generated during `methodproof init`, stored in `~/.methodproof/config.json`.
242
+ **Server co-signature** — the platform independently signs the attestation receipt with its own key and timestamp, creating two-party evidence. Sessions pushed without server co-signature receive a lower integrity score.
160
243
 
161
- **Binary hash self-reporting** — the CLI reports its own binary hash on push. The platform compares against known release hashes to detect modified builds.
244
+ **Binary hash self-reporting** — the CLI reports its own source hash on push. The platform compares against known release hashes to detect modified builds.
162
245
 
163
246
  </details>
164
247
 
@@ -207,7 +290,7 @@ methodproof start
207
290
 
208
291
  **Excluded patterns:** `__pycache__`, `.pyc`, `.git/`, `node_modules`, `.DS_Store`, `.swp`, temp files ending in `~`
209
292
 
210
- **Git commits** are detected by polling `.git/refs/heads/` every 2 seconds — only commits in a git repo rooted at (or above) the watch directory are captured.
293
+ **Git commits** are detected automatically — only commits in a git repo rooted at (or above) the watch directory are captured.
211
294
 
212
295
  ## Data Directory
213
296
 
@@ -1,3 +1,3 @@
1
1
  """MethodProof — see how you code."""
2
2
 
3
- __version__ = "0.5.3"
3
+ __version__ = "0.6.0"
@@ -64,7 +64,8 @@ def main() -> None:
64
64
  threads.append(threading.Thread(
65
65
  target=bridge.start,
66
66
  args=(sid, stop_event, 9877,
67
- cfg.get("token", ""), cfg.get("api_url", ""), cfg.get("e2e_key", "")),
67
+ cfg.get("token", ""), cfg.get("api_url", ""), cfg.get("e2e_key", ""),
68
+ cfg.get("journal_mode", False)),
68
69
  daemon=True,
69
70
  ))
70
71
 
@@ -145,17 +145,17 @@ def emit(event_type: str, metadata: dict[str, Any]) -> None:
145
145
  if _e2e_key:
146
146
  from methodproof.crypto import encrypt_metadata
147
147
  entry["metadata"] = encrypt_metadata(dict(entry["metadata"]), _e2e_key)
148
- global _prev_hash
149
- from methodproof.integrity import compute_event_hash
150
- entry["_chain_hash"] = compute_event_hash(entry, _prev_hash, _account_id)
151
- _prev_hash = entry["_chain_hash"]
152
- if _live_mode:
153
- from methodproof import live as live_mod
154
- live_mod.send(entry)
155
148
  with _lock:
149
+ global _prev_hash
150
+ from methodproof.integrity import compute_event_hash
151
+ entry["_chain_hash"] = compute_event_hash(entry, _prev_hash, _account_id)
152
+ _prev_hash = entry["_chain_hash"]
156
153
  _buffer.append(entry)
157
154
  if len(_buffer) >= _FLUSH_SIZE:
158
155
  _flush_locked()
156
+ if _live_mode:
157
+ from methodproof import live as live_mod
158
+ live_mod.send(entry)
159
159
 
160
160
 
161
161
  def flush() -> None:
@@ -12,7 +12,8 @@ _session_id = ""
12
12
  _api_token = ""
13
13
  _api_base = ""
14
14
  _e2e_key = ""
15
- _pairing: dict[str, Any] = {} # {token: {session_id, api_token, api_base, e2e_key, paired}}
15
+ _journal = False
16
+ _pairing: dict[str, Any] = {} # {token: {session_id, api_token, api_base, e2e_key, journal, paired}}
16
17
  _extension_paired = threading.Event()
17
18
  MAX_BODY = 10 * 1024 * 1024 # 10 MB
18
19
 
@@ -47,6 +48,7 @@ PAIR_PAGE = """<!DOCTYPE html>
47
48
  data-token="{api_token}"
48
49
  data-api-base="{api_base}"
49
50
  data-e2e-key="{e2e_key}"
51
+ data-journal="{journal}"
50
52
  style="display:none"></div>
51
53
  </div>
52
54
  <script>
@@ -62,11 +64,12 @@ PAIR_PAGE = """<!DOCTYPE html>
62
64
  </html>"""
63
65
 
64
66
 
65
- def generate_pair_token(session_id: str, api_token: str, api_base: str, e2e_key: str = "") -> str:
67
+ def generate_pair_token(session_id: str, api_token: str, api_base: str,
68
+ e2e_key: str = "", journal: bool = False) -> str:
66
69
  token = secrets.token_urlsafe(16)
67
70
  _pairing[token] = {
68
71
  "session_id": session_id, "api_token": api_token,
69
- "api_base": api_base, "e2e_key": e2e_key, "paired": False,
72
+ "api_base": api_base, "e2e_key": e2e_key, "journal": journal, "paired": False,
70
73
  }
71
74
  return token
72
75
 
@@ -92,6 +95,7 @@ class _Handler(BaseHTTPRequestHandler):
92
95
  api_token=data["api_token"],
93
96
  api_base=data["api_base"],
94
97
  e2e_key=data["e2e_key"],
98
+ journal="true" if data.get("journal") else "false",
95
99
  pair_token=token,
96
100
  ).encode()
97
101
  self.send_response(200)
@@ -109,6 +113,7 @@ class _Handler(BaseHTTPRequestHandler):
109
113
  "token": _api_token,
110
114
  "api_base": _api_base,
111
115
  "e2e_key": _e2e_key,
116
+ "journal": _journal,
112
117
  })
113
118
  _extension_paired.set()
114
119
  base.log("info", "extension.auto_paired", session_id=_session_id)
@@ -149,6 +154,7 @@ class _Handler(BaseHTTPRequestHandler):
149
154
  "api_token": body.get("api_token", ""),
150
155
  "api_base": body.get("api_base", ""),
151
156
  "e2e_key": body.get("e2e_key", ""),
157
+ "journal": body.get("journal", False),
152
158
  "paired": False,
153
159
  }
154
160
  self._json({"ok": True, "token": token})
@@ -185,12 +191,14 @@ class _Handler(BaseHTTPRequestHandler):
185
191
 
186
192
 
187
193
  def start(session_id: str, stop: threading.Event, port: int = 9877,
188
- api_token: str = "", api_base: str = "", e2e_key: str = "") -> None:
189
- global _session_id, _api_token, _api_base, _e2e_key
194
+ api_token: str = "", api_base: str = "", e2e_key: str = "",
195
+ journal: bool = False) -> None:
196
+ global _session_id, _api_token, _api_base, _e2e_key, _journal
190
197
  _session_id = session_id
191
198
  _api_token = api_token
192
199
  _api_base = api_base
193
200
  _e2e_key = e2e_key
201
+ _journal = journal
194
202
  _extension_paired.clear()
195
203
  HTTPServer.allow_reuse_address = True
196
204
  server = HTTPServer(("127.0.0.1", port), _Handler)
@@ -1028,6 +1028,7 @@ def cmd_start(args: argparse.Namespace) -> None:
1028
1028
  threads.append(threading.Thread(target=bridge.start, args=(
1029
1029
  sid, stop_event, 9877,
1030
1030
  cfg.get("token", ""), cfg.get("api_url", ""), cfg.get("e2e_key", ""),
1031
+ cfg.get("journal_mode", False),
1031
1032
  ), daemon=True))
1032
1033
  if capture.get("music", True):
1033
1034
  from methodproof.agents import music
@@ -79,7 +79,6 @@ JOURNAL_CONTENT_FIELDS: list[tuple[str, str]] = [
79
79
  # AI prompts — full prompt text
80
80
  ("llm_prompt", "prompt_text"),
81
81
  ("agent_prompt", "prompt_preview"),
82
- ("user_prompt", "prompt_preview"),
83
82
  # AI responses — full completion text
84
83
  ("llm_completion", "response_text"),
85
84
  ("agent_completion", "response_preview"),
@@ -105,8 +104,8 @@ JOURNAL_CONTENT_FIELDS: list[tuple[str, str]] = [
105
104
  ("browser_copy", "text_snippet"),
106
105
  ("browser_ai_chat", "detected_input"),
107
106
  ("browser_ai_chat", "url"),
108
- # Inline completions provider detail
109
- ("inline_completion_accepted", "text_length"),
107
+ # Taskssubject reveals intent
108
+ ("task_created", "subject"),
110
109
  ]
111
110
 
112
111
 
@@ -102,9 +102,10 @@ def push(session_id: str, token: str, api_url: str) -> str:
102
102
  event_hashes = store.get_event_hashes(session_id)
103
103
  hash_lookup = {h["event_id"]: h["hash"] for h in event_hashes}
104
104
  total = len(events)
105
+ batch_size = 500
105
106
  try:
106
- for i in range(0, total, 100):
107
- batch = events[i:i + 100]
107
+ for i in range(0, total, batch_size):
108
+ batch = events[i:i + batch_size]
108
109
  payload = [{"id": e["id"], "type": e["type"],
109
110
  "timestamp": _iso(e["timestamp"]),
110
111
  "timestamp_raw": e["timestamp"],
@@ -112,9 +113,18 @@ def push(session_id: str, token: str, api_url: str) -> str:
112
113
  "metadata": json.loads(e["metadata"]),
113
114
  "hash": hash_lookup.get(e["id"], "")}
114
115
  for e in batch]
115
- _request("POST", f"/sessions/{remote_id}/events", api_url, token,
116
- {"events": payload})
117
- done = min(i + 100, total)
116
+ for attempt in range(5):
117
+ try:
118
+ _request("POST", f"/sessions/{remote_id}/events", api_url, token,
119
+ {"events": payload})
120
+ break
121
+ except SystemExit as exc:
122
+ if "429" in str(exc) and attempt < 4:
123
+ import time
124
+ time.sleep(10 * (attempt + 1))
125
+ else:
126
+ raise
127
+ done = min(i + batch_size, total)
118
128
  print(f"\r Uploading: {done}/{total} events", end="", flush=True)
119
129
  print()
120
130
  except SystemExit:
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "methodproof"
3
- version = "0.5.3"
3
+ version = "0.6.0"
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"]
@@ -649,7 +649,7 @@ name = "importlib-metadata"
649
649
  version = "9.0.0"
650
650
  source = { registry = "https://pypi.org/simple" }
651
651
  dependencies = [
652
- { name = "zipp" },
652
+ { name = "zipp", marker = "python_full_version < '3.12'" },
653
653
  ]
654
654
  sdist = { url = "https://files.pythonhosted.org/packages/a9/01/15bb152d77b21318514a96f43af312635eb2500c96b55398d020c93d86ea/importlib_metadata-9.0.0.tar.gz", hash = "sha256:a4f57ab599e6a2e3016d7595cfd72eb4661a5106e787a95bcc90c7105b831efc", size = 56405, upload-time = "2026-03-20T06:42:56.999Z" }
655
655
  wheels = [
@@ -862,7 +862,7 @@ wheels = [
862
862
 
863
863
  [[package]]
864
864
  name = "methodproof"
865
- version = "0.4.5"
865
+ version = "0.5.5"
866
866
  source = { editable = "." }
867
867
  dependencies = [
868
868
  { name = "cryptography", version = "44.0.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" },
File without changes
File without changes
File without changes