epi-recorder 2.1.2__py3-none-any.whl → 2.1.3__py3-none-any.whl

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.
epi_cli/chat.py ADDED
@@ -0,0 +1,193 @@
1
+ """
2
+ EPI CLI Chat - Interactive evidence querying with AI.
3
+
4
+ Allows users to ask natural language questions about their .epi evidence files.
5
+ """
6
+
7
+ import json
8
+ import os
9
+ import warnings
10
+ from pathlib import Path
11
+ from typing import Optional
12
+
13
+ import typer
14
+ from rich.console import Console
15
+ from rich.markdown import Markdown
16
+ from rich.panel import Panel
17
+ from rich.prompt import Prompt
18
+ import google.api_core.exceptions
19
+
20
+ from epi_core.container import EPIContainer
21
+
22
+
23
+ console = Console()
24
+
25
+
26
+ def load_steps_from_epi(epi_path: Path) -> list:
27
+ """Load steps from an .epi file."""
28
+ import tempfile
29
+
30
+ temp_dir = Path(tempfile.mkdtemp())
31
+ extracted = EPIContainer.unpack(epi_path, temp_dir)
32
+
33
+ steps_file = extracted / "steps.jsonl"
34
+ if not steps_file.exists():
35
+ return []
36
+
37
+ steps = []
38
+ with open(steps_file, 'r', encoding='utf-8') as f:
39
+ for line in f:
40
+ if line.strip():
41
+ steps.append(json.loads(line))
42
+
43
+ return steps
44
+
45
+
46
+ def chat(
47
+ epi_file: Path = typer.Argument(..., help="Path to .epi file to chat with"),
48
+ model: str = typer.Option("gemini-2.0-flash", "--model", "-m", help="Gemini model to use")
49
+ ):
50
+ """
51
+ Chat with your evidence file using AI.
52
+
53
+ Ask natural language questions about what happened in your recording.
54
+
55
+ Example:
56
+ epi chat my_recording.epi
57
+ """
58
+ # Resolve path
59
+ if not epi_file.exists():
60
+ # Try epi-recordings directory
61
+ recordings_dir = Path("./epi-recordings")
62
+ potential_path = recordings_dir / f"{epi_file.stem}.epi"
63
+ if potential_path.exists():
64
+ epi_file = potential_path
65
+ else:
66
+ console.print(f"[red]Error:[/red] File not found: {epi_file}")
67
+ raise typer.Exit(1)
68
+
69
+ # Check for API key
70
+ api_key = os.environ.get("GOOGLE_API_KEY") or os.environ.get("GEMINI_API_KEY")
71
+ if not api_key:
72
+ console.print(Panel(
73
+ "[yellow]No API key found![/yellow]\n\n"
74
+ "Set your Google AI API key:\n"
75
+ " [cyan]set GOOGLE_API_KEY=your-key-here[/cyan] (Windows)\n"
76
+ " [cyan]export GOOGLE_API_KEY=your-key-here[/cyan] (Mac/Linux)\n\n"
77
+ "Get a free key at: [link]https://makersuite.google.com/app/apikey[/link]",
78
+ title="[!] API Key Required",
79
+ border_style="yellow"
80
+ ))
81
+ raise typer.Exit(1)
82
+
83
+ # Load the .epi file
84
+ console.print(f"\n[dim]Loading evidence from:[/dim] {epi_file}")
85
+
86
+ try:
87
+ manifest = EPIContainer.read_manifest(epi_file)
88
+ steps = load_steps_from_epi(epi_file)
89
+ except Exception as e:
90
+ console.print(f"[red]Error loading .epi file:[/red] {e}")
91
+ raise typer.Exit(1)
92
+
93
+ # Initialize Gemini
94
+ try:
95
+ import warnings
96
+ with warnings.catch_warnings():
97
+ warnings.simplefilter("ignore")
98
+ import google.generativeai as genai
99
+
100
+ genai.configure(api_key=api_key)
101
+ ai_model = genai.GenerativeModel(model)
102
+ except ImportError:
103
+ console.print(Panel(
104
+ "[red]Google Generative AI package not installed![/red]\n\n"
105
+ "Install it with:\n"
106
+ " [cyan]pip install google-generativeai[/cyan]",
107
+ title="[X] Missing Dependency",
108
+ border_style="red"
109
+ ))
110
+ raise typer.Exit(1)
111
+ except Exception as e:
112
+ console.print(f"[red]Error initializing Gemini:[/red] {e}")
113
+ raise typer.Exit(1)
114
+
115
+ # Build context
116
+ context = f"""You are an expert assistant analyzing an EPI evidence recording file.
117
+
118
+ The recording contains cryptographically signed, tamper-proof evidence of an AI workflow execution.
119
+
120
+ Recording metadata:
121
+ - Created: {manifest.created_at}
122
+ - Goal: {manifest.goal or 'Not specified'}
123
+ - Command: {manifest.cli_command or 'Not specified'}
124
+ - Workflow ID: {manifest.workflow_id}
125
+ - Total steps: {len(steps)}
126
+
127
+ Here are the recorded steps (this is the timeline of events):
128
+ {json.dumps(steps[:50], indent=2, default=str)[:8000]}
129
+
130
+ When answering questions:
131
+ 1. Be specific and cite step indices when relevant
132
+ 2. Distinguish between LLM requests, responses, and other events
133
+ 3. If asked about security, note that API keys are automatically redacted
134
+ 4. Keep answers concise but informative
135
+ """
136
+
137
+ # Start chat session
138
+ chat_session = ai_model.start_chat(history=[])
139
+
140
+ # Display header
141
+ console.print()
142
+ console.print(Panel(
143
+ f"[bold cyan]EPI Evidence Chat[/bold cyan]\n\n"
144
+ f"[dim]File:[/dim] {epi_file.name}\n"
145
+ f"[dim]Steps:[/dim] {len(steps)}\n"
146
+ f"[dim]Model:[/dim] {model}\n\n"
147
+ f"Ask questions about this evidence recording.\n"
148
+ f"Type [yellow]exit[/yellow] or [yellow]quit[/yellow] to end the session.",
149
+ border_style="cyan"
150
+ ))
151
+ console.print()
152
+
153
+ # Chat loop
154
+ while True:
155
+ try:
156
+ question = Prompt.ask("[bold cyan]You[/bold cyan]")
157
+ except (KeyboardInterrupt, EOFError):
158
+ console.print("\n[dim]Goodbye![/dim]")
159
+ break
160
+
161
+ if question.lower() in ('exit', 'quit', 'q'):
162
+ console.print("[dim]Goodbye![/dim]")
163
+ break
164
+
165
+ if not question.strip():
166
+ continue
167
+
168
+ # Send to Gemini with context
169
+ try:
170
+ full_prompt = f"{context}\n\nUser question: {question}"
171
+ response = chat_session.send_message(full_prompt)
172
+
173
+ console.print()
174
+ console.print("[bold green]AI:[/bold green]")
175
+ console.print(Markdown(response.text))
176
+ console.print()
177
+
178
+ except google.api_core.exceptions.ResourceExhausted:
179
+ console.print(Panel(
180
+ "[yellow]API Quota Exceeded[/yellow]\n\n"
181
+ "You have hit the rate limit for the Gemini API (free tier).\n"
182
+ "Please wait a minute before trying again.",
183
+ title="[!] Rate Limit",
184
+ border_style="yellow"
185
+ ))
186
+ except google.api_core.exceptions.NotFound:
187
+ console.print(f"[red]Error:[/red] The model '{model}' was not found. Try using a different model with --model.")
188
+ except google.api_core.exceptions.InvalidArgument as e:
189
+ console.print(f"[red]Error:[/red] Invalid argument: {e}")
190
+ except Exception as e:
191
+ console.print(f"[red]Error:[/red] {e}")
192
+ console.print("[dim]Try asking a different question.[/dim]")
193
+ console.print()
epi_cli/main.py CHANGED
@@ -12,7 +12,9 @@ from epi_cli.keys import generate_default_keypair_if_missing
12
12
  # Create Typer app
13
13
  app = typer.Typer(
14
14
  name="epi",
15
- help="""EPI - Evidence Packaged Infrastructure for AI workflows
15
+ help="""EPI - The PDF for AI Evidence.
16
+
17
+ Cryptographic proof of what Autonomous AI Systems actually did.
16
18
 
17
19
  Commands:
18
20
  run <script.py> Record, auto-verify and open viewer. (Zero-config)
@@ -120,6 +122,10 @@ app.add_typer(view_app, name="view", help="Open recording in browser (name resol
120
122
  from epi_cli.ls import ls as ls_command
121
123
  app.command(name="ls", help="List local recordings (./epi-recordings/)")(ls_command)
122
124
 
125
+ # NEW: chat command (v2.1.3 - AI-powered evidence querying)
126
+ from epi_cli.chat import chat as chat_command
127
+ app.command(name="chat", help="Chat with your evidence file using AI")(chat_command)
128
+
123
129
  # Phase 1: keys command (for manual key management)
124
130
  @app.command()
125
131
  def keys(
epi_core/__init__.py CHANGED
@@ -2,7 +2,7 @@
2
2
  EPI Core - Core data structures, serialization, and container management.
3
3
  """
4
4
 
5
- __version__ = "2.1.1"
5
+ __version__ = "2.1.3"
6
6
 
7
7
  from epi_core.schemas import ManifestModel, StepModel
8
8
  from epi_core.serialize import get_canonical_hash
epi_recorder/__init__.py CHANGED
@@ -4,7 +4,7 @@ EPI Recorder - Runtime interception and workflow capture.
4
4
  Python API for recording AI workflows with cryptographic verification.
5
5
  """
6
6
 
7
- __version__ = "2.1.1"
7
+ __version__ = "2.1.3"
8
8
 
9
9
  # Export Python API
10
10
  from epi_recorder.api import (
epi_recorder/patcher.py CHANGED
@@ -325,7 +325,113 @@ def _patch_openai_legacy() -> bool:
325
325
  return False
326
326
 
327
327
 
328
- return results
328
+ # ==================== Google Gemini Patcher ====================
329
+
330
+ def patch_gemini() -> bool:
331
+ """
332
+ Patch Google Generative AI library to intercept Gemini API calls.
333
+
334
+ Returns:
335
+ bool: True if patching succeeded, False otherwise
336
+ """
337
+ try:
338
+ import warnings
339
+ with warnings.catch_warnings():
340
+ warnings.simplefilter("ignore")
341
+ import google.generativeai as genai
342
+ from google.generativeai.types import GenerateContentResponse
343
+
344
+ # Get the GenerativeModel class
345
+ GenerativeModel = genai.GenerativeModel
346
+
347
+ # Store original method
348
+ original_generate_content = GenerativeModel.generate_content
349
+
350
+ @wraps(original_generate_content)
351
+ def wrapped_generate_content(self, *args, **kwargs):
352
+ """Wrapped Gemini generate_content with recording."""
353
+
354
+ # Only record if context is active
355
+ if not is_recording():
356
+ return original_generate_content(self, *args, **kwargs)
357
+
358
+ context = get_recording_context()
359
+ start_time = time.time()
360
+
361
+ # Extract prompt from args/kwargs
362
+ contents = args[0] if args else kwargs.get("contents", "")
363
+
364
+ # Capture request
365
+ request_data = {
366
+ "provider": "google",
367
+ "method": "GenerativeModel.generate_content",
368
+ "model": getattr(self, '_model_name', getattr(self, 'model_name', 'gemini')),
369
+ "contents": str(contents)[:2000], # Truncate long prompts
370
+ "generation_config": str(kwargs.get("generation_config", {})),
371
+ }
372
+
373
+ # Log request step
374
+ context.add_step("llm.request", request_data)
375
+
376
+ # Execute original call
377
+ try:
378
+ response = original_generate_content(self, *args, **kwargs)
379
+ elapsed = time.time() - start_time
380
+
381
+ # Capture response
382
+ response_text = ""
383
+ try:
384
+ if hasattr(response, 'text'):
385
+ response_text = response.text[:2000] # Truncate long responses
386
+ elif hasattr(response, 'parts'):
387
+ response_text = str(response.parts)[:2000]
388
+ except Exception:
389
+ response_text = "[Response text extraction failed]"
390
+
391
+ response_data = {
392
+ "provider": "google",
393
+ "model": getattr(self, '_model_name', getattr(self, 'model_name', 'gemini')),
394
+ "response": response_text,
395
+ "latency_seconds": round(elapsed, 3)
396
+ }
397
+
398
+ # Try to get usage info if available
399
+ try:
400
+ if hasattr(response, 'usage_metadata'):
401
+ usage = response.usage_metadata
402
+ response_data["usage"] = {
403
+ "prompt_tokens": getattr(usage, 'prompt_token_count', None),
404
+ "completion_tokens": getattr(usage, 'candidates_token_count', None),
405
+ "total_tokens": getattr(usage, 'total_token_count', None)
406
+ }
407
+ except Exception:
408
+ pass
409
+
410
+ # Log response step
411
+ context.add_step("llm.response", response_data)
412
+
413
+ return response
414
+
415
+ except Exception as e:
416
+ # Log error step
417
+ context.add_step("llm.error", {
418
+ "provider": "google",
419
+ "error": str(e),
420
+ "error_type": type(e).__name__
421
+ })
422
+ raise
423
+
424
+ # Apply patch
425
+ GenerativeModel.generate_content = wrapped_generate_content
426
+
427
+ return True
428
+
429
+ except ImportError:
430
+ # google-generativeai not installed
431
+ return False
432
+ except Exception as e:
433
+ print(f"Warning: Failed to patch Gemini: {e}")
434
+ return False
329
435
 
330
436
 
331
437
  def patch_requests() -> bool:
@@ -419,6 +525,9 @@ def patch_all() -> Dict[str, bool]:
419
525
  # Patch OpenAI
420
526
  results["openai"] = patch_openai()
421
527
 
528
+ # Patch Google Gemini
529
+ results["gemini"] = patch_gemini()
530
+
422
531
  # Patch generic requests (covers LangChain, Anthropic, etc.)
423
532
  results["requests"] = patch_requests()
424
533
 
@@ -1,15 +1,15 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: epi-recorder
3
- Version: 2.1.2
4
- Summary: Evidence Packaged Infrastructure (.epi) for AI Evidence - Record, Verify, and Replay AI runs with automatic PATH setup
3
+ Version: 2.1.3
4
+ Summary: The PDF for AI Evidence - Cryptographic proof of what Autonomous AI Systems actually did.
5
5
  Author-email: Mohd Ibrahim Afridi <epitechforworld@outlook.com>
6
6
  Maintainer-email: Mohd Ibrahim Afridi <epitechforworld@outlook.com>
7
7
  License: Apache-2.0
8
- Project-URL: Homepage, https://github.com/mohdibrahimaiml/EPI-V2.1.2
9
- Project-URL: Documentation, https://github.com/mohdibrahimaiml/EPI-V2.1.2#readme
10
- Project-URL: Repository, https://github.com/mohdibrahimaiml/EPI-V2.1.2
11
- Project-URL: Issues, https://github.com/mohdibrahimaiml/EPI-V2.1.2/issues
12
- Keywords: ai,reproducibility,verification,llm,evidence,openai,cryptography,workflow,audit
8
+ Project-URL: Homepage, https://github.com/mohdibrahimaiml/EPI-V2.1.3
9
+ Project-URL: Documentation, https://github.com/mohdibrahimaiml/EPI-V2.1.3#readme
10
+ Project-URL: Repository, https://github.com/mohdibrahimaiml/EPI-V2.1.3
11
+ Project-URL: Issues, https://github.com/mohdibrahimaiml/EPI-V2.1.3/issues
12
+ Keywords: ai,reproducibility,verification,llm,evidence,openai,gemini,cryptography,workflow,audit
13
13
  Classifier: Development Status :: 4 - Beta
14
14
  Classifier: Intended Audience :: Developers
15
15
  Classifier: Intended Audience :: Science/Research
@@ -29,6 +29,7 @@ Requires-Dist: cryptography>=41.0.0
29
29
  Requires-Dist: cbor2>=5.6.0
30
30
  Requires-Dist: typer[all]>=0.12.0
31
31
  Requires-Dist: rich>=13.0.0
32
+ Requires-Dist: google-generativeai>=0.4.0
32
33
  Provides-Extra: dev
33
34
  Requires-Dist: pytest>=8.0.0; extra == "dev"
34
35
  Requires-Dist: pytest-asyncio>=0.23.0; extra == "dev"
@@ -43,18 +44,18 @@ Dynamic: license-file
43
44
 
44
45
  # EPI Recorder
45
46
 
46
- ### The PDF for AI Evidence
47
+ ### The PDF for AI Evidence
47
48
 
48
- **Record. Verify. Trust.**
49
+ **Cryptographic proof of what Autonomous AI Systems actually did.**
49
50
 
50
- [![PyPI](https://img.shields.io/pypi/v/epi-recorder?color=blue&label=PyPI&logo=pypi&logoColor=white)](https://pypi.org/project/epi-recorder/)
51
- [![Python](https://img.shields.io/badge/Python-3.11+-3776AB?logo=python&logoColor=white)](https://www.python.org)
52
- [![License](https://img.shields.io/badge/License-Apache%202.0-green.svg)](LICENSE)
53
- [![Status](https://img.shields.io/badge/Status-MVP-orange.svg)](https://github.com/mohdibrahimaiml/EPI-V2.0.0)
54
- [![Downloads](https://img.shields.io/pypi/dm/epi-recorder?color=blue&label=Downloads)](https://pypi.org/project/epi-recorder/)
55
- [![Stars](https://img.shields.io/github/stars/mohdibrahimaiml/EPI-V2.0.0?style=social)](https://github.com/mohdibrahimaiml/EPI-V2.0.0)
51
+ [![PyPI](https://img.shields.io/badge/PyPI-v2.1.3-blue?style=flat&logo=pypi&logoColor=white)](https://pypi.org/project/epi-recorder/)
52
+ [![Python](https://img.shields.io/badge/Python-3.11+-3776AB?style=flat&logo=python&logoColor=white)](https://www.python.org)
53
+ [![License](https://img.shields.io/badge/License-Apache%202.0-green.svg?style=flat)](LICENSE)
54
+ [![Status](https://img.shields.io/badge/Status-v2.1.3-blue?style=flat)](https://github.com/mohdibrahimaiml/EPI-V2.1.3)
55
+ [![Downloads](https://img.shields.io/badge/Downloads-3.8k-blue?style=flat)](https://pypi.org/project/epi-recorder/)
56
+ [![Stars](https://img.shields.io/badge/Stars-16-ea4aaa?style=social&logo=github)](https://github.com/mohdibrahimaiml/EPI-V2.1.3)
56
57
 
57
- [**🚀 Quick Start**](#-quick-start-30-seconds) • [**📖 Docs**](https://epilabs.org/docs) • [**💬 Community**](https://github.com/mohdibrahimaiml/EPI-V2.0.0/discussions) • [**🎥 Demo**](https://colab.research.google.com/github/mohdibrahimaiml/EPI-V2.1.2/blob/main/colab_demo.ipynb)
58
+ [**🚀 Quick Start**](#-quick-start-30-seconds) • [**📖 Docs**](https://epilabs.org/docs) • [**💬 Community**](https://github.com/mohdibrahimaiml/EPI-V2.1.3/discussions) • [**🎥 Demo**](https://colab.research.google.com/github/mohdibrahimaiml/EPI-V2.1.3/blob/main/colab_demo.ipynb)
58
59
 
59
60
  </div>
60
61
 
@@ -73,12 +74,12 @@ Dynamic: license-file
73
74
 
74
75
  **Unix/Mac:**
75
76
  ```bash
76
- curl -sSL https://raw.githubusercontent.com/mohdibrahimaiml/EPI-V2.1.2/main/scripts/install.sh | sh
77
+ curl -sSL https://raw.githubusercontent.com/mohdibrahimaiml/EPI-V2.1.3/main/scripts/install.sh | sh
77
78
  ```
78
79
 
79
80
  **Windows:**
80
81
  ```powershell
81
- iwr https://raw.githubusercontent.com/mohdibrahimaiml/EPI-V2.1.2/main/scripts/install.ps1 -useb | iex
82
+ iwr https://raw.githubusercontent.com/mohdibrahimaiml/EPI-V2.1.3/main/scripts/install.ps1 -useb | iex
82
83
  ```
83
84
 
84
85
  **Manual (pip):**
@@ -476,21 +477,23 @@ Use `python -m epi_cli` instead (always works). Or run `python -m epi_cli doctor
476
477
 
477
478
  ---
478
479
 
479
- ## 🆕 What's New in v2.1.2
480
+ ## 🆕 What's New in v2.1.3
480
481
 
481
482
  > [!IMPORTANT]
482
- > **Critical Security Update:** Implemented client-side Ed25519 signature verification in the embedded viewer. The viewer now cryptographically verifies that the standard signature matches the content and the embedded public key, preventing potential tamper attacks.
483
+ > **Gemini Native:** EPI now natively supports Google Gemini. Just run your script, and Gemini calls are captured automatically. Plus, talk to your evidence with `epi chat`.
483
484
 
484
- ### 🛡️ Security & Integrity
485
+ ### 🤖 Gemini Integration
486
+ - **Automatic Patcher:** Intercepts `google.generativeai` calls without code changes. Logs prompts, responses, and token usage.
487
+ - **Evidence Chat:** New command `epi chat` allows you to query your `.epi` files using Gemini AI. "What happened in this run?"
488
+ - **Error Capture:** Automatically records API errors like Quota Exceeded (429) or Blocked Content.
489
+
490
+ ### 🛡️ Security & Integrity (v2.1.2)
485
491
  - **Client-Side Verification:** The HTML viewer now includes a bundled crypto library to verify signatures offline.
486
- - **Spec Update (v1.1-json):** Manifests now use Canonical JSON hashing and include the `public_key` for self-contained proof.
487
492
  - **Trust Badges:** UI now explicitly shows "Verified" (Green), "Unsigned" (Yellow), or "Tampered" (Red).
488
493
 
489
- ### ✨ Enhanced CLI Reliability (v2.1.1)
490
-
491
- **1. Python Module Fallback**
492
- - `python -m epi_cli` now works as a 100% reliable alternative
493
- - Perfect for restricted environments
494
+ ### ✨ Enhanced CLI Reliability
495
+ - **Windows Compatibility:** Fixed Unicode issues in CLI for legacy terminals.
496
+ - **Python Module Fallback:** `python -m epi_cli` works reliably everywhere.
494
497
 
495
498
  **2. Automatic PATH Configuration**
496
499
  - Post-install script auto-fixes PATH on Windows
@@ -1,33 +1,34 @@
1
1
  epi_postinstall.py,sha256=9MVuFeA8S25jAp9VMZrAE0M1k2QHC1PeJxful7jcMd8,7066
2
2
  epi_cli/__init__.py,sha256=SSpuDlDqVBbPvR21CCRcNOB61EyB8jAUzNd8XISADa8,98
3
3
  epi_cli/__main__.py,sha256=wQWpc9XXhXnPyy2hw-WQFGaPM1qNhpKiel2jQm7MhKQ,296
4
+ epi_cli/chat.py,sha256=Y3FinP-Cg1DawBpM7mqWj1BnYh6Hkl3OTKdXi-0QvuE,6693
4
5
  epi_cli/keys.py,sha256=bHR6knfGR4g7uGuR2cu5VTcGXVyvtZzVtnRBbgPSaTE,9111
5
6
  epi_cli/ls.py,sha256=Ip6OyubkXb_Ba9S7p-U1seWMcWpFeiV-fHhl9ocUy9k,5015
6
- epi_cli/main.py,sha256=2HiIBkq0AFricMV5vLBzWyYVKLTnbIUDQ15u7UAs-mw,11923
7
+ epi_cli/main.py,sha256=x_sIFkgGKvHN3XQIuCYHlReqL6xVFsOzZJGdPf8eXf8,12165
7
8
  epi_cli/record.py,sha256=QtDrjr-7WbfcYXwPRrDDujrubUNrHhp062EcW8DZPNk,7321
8
9
  epi_cli/run.py,sha256=dM_AYC3LzDBc_DzVKlb8obZBE52sAe3wYAnce0PLGT4,14101
9
10
  epi_cli/verify.py,sha256=Rq34rw-zM_vZmYDsfg8cLlvW76_wJ99Pu-arjGRE9bw,8238
10
11
  epi_cli/view.py,sha256=YZYohgT66Z2UYfN37d5VTPxipNiwSMacD4zHYaNypiU,4021
11
- epi_core/__init__.py,sha256=P-R2yvbm3MVYwz_5l0dOzuv4Y1EgdrQfYtb4EL9cR08,303
12
+ epi_core/__init__.py,sha256=AM-2ThtcXElMi1HpKmabjRUk365TdSLHva22eqLBfcM,303
12
13
  epi_core/container.py,sha256=ZRRAWBoGGLkoqXQVEwfHHXtPE6D0Nqr1fBZpBFyXnKk,12687
13
14
  epi_core/redactor.py,sha256=mYVZrIsKJdIJBY2XHE0U_CYqgY4Z2vGRvLW-19_c0WE,9886
14
15
  epi_core/schemas.py,sha256=flrPiTN92fbJS0U0wDfzxJvv4MGpUXEoWeu6kxoelRQ,4728
15
16
  epi_core/serialize.py,sha256=2zl0SiDqUzk05HYca57Xmfj3x59LBbqEkJYE5TcCCz8,5685
16
17
  epi_core/trust.py,sha256=3uy6MGl0-5nDa2ZB_Wj2j25EDmChRWi8ZboketdSXkE,7964
17
- epi_recorder/__init__.py,sha256=5UPUcvQuHJ8zzZl1wHgTXLPFq6CXvQItML8cOaugpcM,396
18
+ epi_recorder/__init__.py,sha256=sRrsvbq8yGOKMp0ViutZ9HjurvQgi0rDoWc4DKSXSkY,396
18
19
  epi_recorder/api.py,sha256=EZtMF2MVIk8KR1GPJBSxDlEh57nsIc-B2Ok0_j3hZ4U,21561
19
20
  epi_recorder/bootstrap.py,sha256=yE1y0rjQ-1D-ZhWFipX_6qXFTA2BPlEm8Ft4Z0iex88,1845
20
21
  epi_recorder/environment.py,sha256=NCz_Pckc6GU1kQsYF3oXDsN46k5LVuYWbMEhTj1FRXo,6598
21
- epi_recorder/patcher.py,sha256=tEAlDfH_rz3TblASn9xvMsadXgobvrenQe2Pq1M_xvA,14570
22
+ epi_recorder/patcher.py,sha256=d7yAdoC7rotugkq-lMU0kV6x9rTRVtq5xtC1mXbHsOs,18924
22
23
  epi_recorder/test_import.py,sha256=Dhjkj8qYZR4d4w-bshClV6S-naCcS5srW7wsp7jW-cM,459
23
24
  epi_recorder/test_script.py,sha256=4uUheXOfqC28NYICyaAxm3gnhfrkdDZtaXnwfjG-qhQ,92
24
- epi_recorder-2.1.2.dist-info/licenses/LICENSE,sha256=aUgjAzBUkmKIZy3AZ_XAZWoh3kzkRlkOc3JHLVfyF-A,11540
25
+ epi_recorder-2.1.3.dist-info/licenses/LICENSE,sha256=aUgjAzBUkmKIZy3AZ_XAZWoh3kzkRlkOc3JHLVfyF-A,11540
25
26
  epi_viewer_static/app.js,sha256=qxOiqj4UBGCzxddctt8XbTeND8m2mwotDnvC7emayfs,14723
26
27
  epi_viewer_static/crypto.js,sha256=hjoIrGljQ0Yrg-KplT1zHccK1b82_Y_SfDZ8Gw_UjBc,19078
27
28
  epi_viewer_static/index.html,sha256=JxdsgzjJ5nGeDD1ROXI00w8rwsD7wXXOwitizxe8AWs,3298
28
29
  epi_viewer_static/viewer_lite.css,sha256=oCEiEYbvdlaMwz-MPlrk3LoTVOad-bDLlP-X49Yw0o0,4691
29
- epi_recorder-2.1.2.dist-info/METADATA,sha256=XLs2r57PfV6-SzWr3P7x9F5cuvUJ-UMEK-gATrSlAs4,15991
30
- epi_recorder-2.1.2.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
31
- epi_recorder-2.1.2.dist-info/entry_points.txt,sha256=MfMwqVRx_yMGbuPpiyjz2f8fQp8TUbHmRC1H_bupoyM,41
32
- epi_recorder-2.1.2.dist-info/top_level.txt,sha256=kvGAjj3uNol1hxRi29Ec-B4HuYK6t-MD7wflkENQA6g,64
33
- epi_recorder-2.1.2.dist-info/RECORD,,
30
+ epi_recorder-2.1.3.dist-info/METADATA,sha256=BjvScqRYo2TUl_PYAeBz1MpEObF5u-hc7nmBV2t5Eqo,16246
31
+ epi_recorder-2.1.3.dist-info/WHEEL,sha256=qELbo2s1Yzl39ZmrAibXA2jjPLUYfnVhUNTlyF1rq0Y,92
32
+ epi_recorder-2.1.3.dist-info/entry_points.txt,sha256=MfMwqVRx_yMGbuPpiyjz2f8fQp8TUbHmRC1H_bupoyM,41
33
+ epi_recorder-2.1.3.dist-info/top_level.txt,sha256=kvGAjj3uNol1hxRi29Ec-B4HuYK6t-MD7wflkENQA6g,64
34
+ epi_recorder-2.1.3.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: setuptools (80.9.0)
2
+ Generator: setuptools (80.10.1)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5