empathy-framework 3.3.0__py3-none-any.whl → 3.3.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.
- {empathy_framework-3.3.0.dist-info → empathy_framework-3.3.3.dist-info}/METADATA +18 -5
- {empathy_framework-3.3.0.dist-info → empathy_framework-3.3.3.dist-info}/RECORD +14 -11
- empathy_llm_toolkit/htmlcov/status.json +1 -0
- empathy_llm_toolkit/security/htmlcov/status.json +1 -0
- empathy_os/__init__.py +51 -51
- empathy_os/cli.py +12 -8
- empathy_os/config.py +30 -6
- empathy_os/platform_utils.py +262 -0
- empathy_os/workflow_commands.py +2 -2
- empathy_software_plugin/cli.py +3 -1
- {empathy_framework-3.3.0.dist-info → empathy_framework-3.3.3.dist-info}/WHEEL +0 -0
- {empathy_framework-3.3.0.dist-info → empathy_framework-3.3.3.dist-info}/entry_points.txt +0 -0
- {empathy_framework-3.3.0.dist-info → empathy_framework-3.3.3.dist-info}/licenses/LICENSE +0 -0
- {empathy_framework-3.3.0.dist-info → empathy_framework-3.3.3.dist-info}/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: empathy-framework
|
|
3
|
-
Version: 3.3.
|
|
3
|
+
Version: 3.3.3
|
|
4
4
|
Summary: AI collaboration framework with persistent memory, anticipatory intelligence, code inspection, and multi-agent orchestration
|
|
5
5
|
Author-email: Patrick Roebuck <patrick.roebuck@smartAImemory.com>
|
|
6
6
|
Maintainer-email: Smart-AI-Memory <patrick.roebuck@smartAImemory.com>
|
|
@@ -271,7 +271,7 @@ Dynamic: license-file
|
|
|
271
271
|
**The AI collaboration framework that predicts problems before they happen.**
|
|
272
272
|
|
|
273
273
|
[](https://pypi.org/project/empathy-framework/)
|
|
274
|
-
[](https://github.com/Smart-AI-Memory/empathy-framework/actions)
|
|
275
275
|
[](https://github.com/Smart-AI-Memory/empathy-framework)
|
|
276
276
|
[](LICENSE)
|
|
277
277
|
[](https://www.python.org)
|
|
@@ -368,17 +368,21 @@ print(result.prevention_steps) # How to prevent it
|
|
|
368
368
|
## Become a Power User
|
|
369
369
|
|
|
370
370
|
### Level 1: Basic Usage
|
|
371
|
+
|
|
371
372
|
```bash
|
|
372
373
|
pip install empathy-framework
|
|
373
374
|
```
|
|
375
|
+
|
|
374
376
|
- Works out of the box with sensible defaults
|
|
375
377
|
- Auto-detects your API keys
|
|
376
378
|
|
|
377
379
|
### Level 2: Cost Optimization
|
|
380
|
+
|
|
378
381
|
```bash
|
|
379
382
|
# Enable hybrid mode for 80-96% cost savings
|
|
380
383
|
python -m empathy_os.models.cli provider --set hybrid
|
|
381
384
|
```
|
|
385
|
+
|
|
382
386
|
| Tier | Model | Use Case | Cost |
|
|
383
387
|
|------|-------|----------|------|
|
|
384
388
|
| Cheap | GPT-4o-mini / Haiku | Summarization, simple tasks | $0.15-0.25/M |
|
|
@@ -386,6 +390,7 @@ python -m empathy_os.models.cli provider --set hybrid
|
|
|
386
390
|
| Premium | o1 / Opus | Architecture, complex decisions | $15/M |
|
|
387
391
|
|
|
388
392
|
### Level 3: Multi-Model Workflows
|
|
393
|
+
|
|
389
394
|
```python
|
|
390
395
|
from empathy_llm_toolkit import EmpathyLLM
|
|
391
396
|
|
|
@@ -398,13 +403,16 @@ await llm.interact(user_id="dev", user_input="Design system", task_type="coordin
|
|
|
398
403
|
```
|
|
399
404
|
|
|
400
405
|
### Level 4: VSCode Integration
|
|
406
|
+
|
|
401
407
|
Install the Empathy VSCode extension for:
|
|
408
|
+
|
|
402
409
|
- **Real-time Dashboard** — Health score, costs, patterns
|
|
403
410
|
- **One-Click Workflows** — Research, code review, debugging
|
|
404
411
|
- **Visual Cost Tracking** — See savings in real-time
|
|
405
|
-
|
|
412
|
+
- See also: `docs/dashboard-costs-by-tier.md` for interpreting the **By tier (7 days)** cost breakdown.
|
|
406
413
|
|
|
407
414
|
### Level 5: Custom Agents
|
|
415
|
+
|
|
408
416
|
```python
|
|
409
417
|
from empathy_os.agents import AgentFactory
|
|
410
418
|
|
|
@@ -421,6 +429,7 @@ security_agent = AgentFactory.create(
|
|
|
421
429
|
## CLI Reference
|
|
422
430
|
|
|
423
431
|
### Provider Configuration
|
|
432
|
+
|
|
424
433
|
```bash
|
|
425
434
|
python -m empathy_os.models.cli provider # Show current config
|
|
426
435
|
python -m empathy_os.models.cli provider --set anthropic # Single provider
|
|
@@ -430,6 +439,7 @@ python -m empathy_os.models.cli provider -f json # JSON output
|
|
|
430
439
|
```
|
|
431
440
|
|
|
432
441
|
### Model Registry
|
|
442
|
+
|
|
433
443
|
```bash
|
|
434
444
|
python -m empathy_os.models.cli registry # Show all models
|
|
435
445
|
python -m empathy_os.models.cli registry --provider openai # Filter by provider
|
|
@@ -437,6 +447,7 @@ python -m empathy_os.models.cli costs --input-tokens 50000 # Estimate costs
|
|
|
437
447
|
```
|
|
438
448
|
|
|
439
449
|
### Telemetry & Analytics
|
|
450
|
+
|
|
440
451
|
```bash
|
|
441
452
|
python -m empathy_os.models.cli telemetry # Summary
|
|
442
453
|
python -m empathy_os.models.cli telemetry --costs # Cost savings report
|
|
@@ -445,6 +456,7 @@ python -m empathy_os.models.cli telemetry --fallbacks # Fallback stats
|
|
|
445
456
|
```
|
|
446
457
|
|
|
447
458
|
### Memory Control
|
|
459
|
+
|
|
448
460
|
```bash
|
|
449
461
|
empathy-memory serve # Start Redis + API server
|
|
450
462
|
empathy-memory status # Check system status
|
|
@@ -453,6 +465,7 @@ empathy-memory patterns # List stored patterns
|
|
|
453
465
|
```
|
|
454
466
|
|
|
455
467
|
### Code Inspection
|
|
468
|
+
|
|
456
469
|
```bash
|
|
457
470
|
empathy-inspect . # Run full inspection
|
|
458
471
|
empathy-inspect . --format sarif # GitHub Actions format
|
|
@@ -726,8 +739,8 @@ cd empathy-framework && pip install -e .[dev]
|
|
|
726
739
|
|
|
727
740
|
```bash
|
|
728
741
|
# Required: At least one provider
|
|
729
|
-
export ANTHROPIC_API_KEY="sk-ant-..." # For Claude models
|
|
730
|
-
export OPENAI_API_KEY="sk-..." # For GPT models
|
|
742
|
+
export ANTHROPIC_API_KEY="sk-ant-..." # For Claude models # pragma: allowlist secret
|
|
743
|
+
export OPENAI_API_KEY="sk-..." # For GPT models # pragma: allowlist secret
|
|
731
744
|
|
|
732
745
|
# Optional: Redis for memory
|
|
733
746
|
export REDIS_URL="redis://localhost:6379"
|
|
@@ -32,7 +32,7 @@ coach_wizards/refactoring_wizard.py,sha256=1AuRyX45KI63n_-fvvbRXamqvPbrB-O1B7TPP
|
|
|
32
32
|
coach_wizards/scaling_wizard.py,sha256=yLULCkflLoBKS4hOSBPQuKKGBGHgKExnuEp5WLTIY-8,2596
|
|
33
33
|
coach_wizards/security_wizard.py,sha256=tr1iq0egAMLCM-wOFhTDN5dHQRFuhSshXSkv17Jm7eM,2603
|
|
34
34
|
coach_wizards/testing_wizard.py,sha256=M2RtaTa1WHsk42svJAEZpLySU3PXJJZn2jigouMJrG0,2561
|
|
35
|
-
empathy_framework-3.3.
|
|
35
|
+
empathy_framework-3.3.3.dist-info/licenses/LICENSE,sha256=IJ9eeI5KSrD5P7alsn7sI_6_1bDihxBA5S4Sen4jf2k,4937
|
|
36
36
|
empathy_healthcare_plugin/__init__.py,sha256=FvVcD7WQTlmCCLgSPfM-FPT2l-ma1oAACBZWhtYFAUA,296
|
|
37
37
|
empathy_healthcare_plugin/protocols/cardiac.json,sha256=uShOvI2RQJYLZacLT2R_aHfsjvJdyCu_gYfpMfK3N74,2088
|
|
38
38
|
empathy_healthcare_plugin/protocols/post_operative.json,sha256=nqh3ydPY8FNSLv-Q3QmH8Dsyc1c4LvQxUSP84B8W6xk,2021
|
|
@@ -52,10 +52,12 @@ empathy_llm_toolkit/pattern_summary.py,sha256=q3gPMZtk5TIG9hs61mEZzaBtpry0qVfbu2
|
|
|
52
52
|
empathy_llm_toolkit/providers.py,sha256=M_DrZr7Yq5c2edEoUGH20LUI9nmi9KOkqDvTku2dhBw,13958
|
|
53
53
|
empathy_llm_toolkit/session_status.py,sha256=pJwqHwbVwR2Q6coRkB_34CWRCMoF-r4-YBtQWEO1Mj8,25724
|
|
54
54
|
empathy_llm_toolkit/state.py,sha256=oi8bPqUHkmfgkfT4_4eD1ndIGH_THyLQDYlIWZLUx5s,8051
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
empathy_llm_toolkit/htmlcov/status.json,sha256=emOFm_dTJcNl_Bw_lh62qNbnU6yzhne8TWlQkrPVdrk,8544
|
|
56
|
+
empathy_llm_toolkit/security/htmlcov/status.json,sha256=ELS9bn59azqfEyyokI-nV4gQLPQh4bVwHsmhVbdrKYI,4402
|
|
57
|
+
empathy_os/__init__.py,sha256=4WGijLjIQ6xHlSWxl5hb9FxTU-EJB1-Kel7gf3LcQMI,7069
|
|
58
|
+
empathy_os/cli.py,sha256=k3r_0as7mtOPnLyp3cNKRQiLSKYJqFlmYuRuhdiRrwM,87001
|
|
57
59
|
empathy_os/cli_unified.py,sha256=TvfsheONim8ETegZo3KJA2vBtFD0fn0rRikUz83w1Dg,14021
|
|
58
|
-
empathy_os/config.py,sha256=
|
|
60
|
+
empathy_os/config.py,sha256=tPM9gsVE0y8DsC_cxfZxyngq2cKiWN1F6ezKGKON5jI,13709
|
|
59
61
|
empathy_os/coordination.py,sha256=0jKt2DzzJmFjpXJs4pMXBcUktCFHsa9i3rkXzXxykGk,28656
|
|
60
62
|
empathy_os/core.py,sha256=kL_37DajqIV1_b0ldee8rGG0xUTrSzAqYuQ4dowSxuw,53229
|
|
61
63
|
empathy_os/cost_tracker.py,sha256=VwjkyKEm-gbmyO7wQ88t82RNZfc-LCp0vpK699Giqp0,12575
|
|
@@ -69,14 +71,15 @@ empathy_os/logging_config.py,sha256=U_MylJblr2jMfYmsK6z4WKd9Z6ZZ1G0kxzq9cNPGLEk,
|
|
|
69
71
|
empathy_os/monitoring.py,sha256=76Fiwqd8prqi6H_mMX79_yEPbfbPdx58E9ZfLld6fvw,13434
|
|
70
72
|
empathy_os/pattern_library.py,sha256=jUeWRnRHbhB05Rm9kL-OFdMajRCOqOzOb9ow_23JdY0,14040
|
|
71
73
|
empathy_os/persistence.py,sha256=2jNqPmW6TrCH2quYph2SVMQnAnhBDDVk9DqNuEhLhGE,17637
|
|
74
|
+
empathy_os/platform_utils.py,sha256=8R35nql5f1cuMwWz9JKM_Nx_Gf9rGhCiAleEmIk8WVY,7343
|
|
72
75
|
empathy_os/redis_config.py,sha256=L8KoHFwhl-_twSswMfELUgOmANOTPRB9Yj8VXuxfSb4,5947
|
|
73
76
|
empathy_os/redis_memory.py,sha256=lWS_F4FeDkmEI-jIgkPTzs3D8TTDB0627WsOxYMT-XM,23276
|
|
74
77
|
empathy_os/templates.py,sha256=ap4u9i5O9KA83wWLfoUCS7phDHKb6wj8M1Zcm218lN0,17069
|
|
75
78
|
empathy_os/trust_building.py,sha256=8ZvNwJmeDyKeUIkk_331M9jwKcqrsn6K43gnGtnIXbM,18790
|
|
76
|
-
empathy_os/workflow_commands.py,sha256=
|
|
79
|
+
empathy_os/workflow_commands.py,sha256=ZfACBQKjaAfEZER4yRRsFVw9IfGhhPVGwQyBjD1HUAk,21904
|
|
77
80
|
empathy_software_plugin/SOFTWARE_PLUGIN_README.md,sha256=RXIOB9Mt-8JrfGAA3ZUuRPT34sThubrwUgg5iNcSKIc,22591
|
|
78
81
|
empathy_software_plugin/__init__.py,sha256=Ylyj95pSsoN9Zasam96DH61uBHoMJh3kbhO7k_VaCWo,310
|
|
79
|
-
empathy_software_plugin/cli.py,sha256=
|
|
82
|
+
empathy_software_plugin/cli.py,sha256=N48zwVs4EfGX-69PqhiMJ77H5TS_BpCbLVJ6JTTkypw,22414
|
|
80
83
|
empathy_software_plugin/plugin.py,sha256=NNZTILE5Npo4SahA4F_3awIizLHI32_wWTFAutvmsqQ,6700
|
|
81
84
|
wizards/__init__.py,sha256=5JJ6rtS5mwJtuZIgO2sYHZlCy0XJP2eyyCK5zMD6ZAc,2452
|
|
82
85
|
wizards/admission_assessment_wizard.py,sha256=-Th9bwu6Sd6V2jA4fciK35QpoFc40U1quZHDMdOH93U,23609
|
|
@@ -95,8 +98,8 @@ wizards/sbar_wizard.py,sha256=CJ63JAXwcfBf6C3aYyxY2LODbARP9GPl0ZGJWLbx88E,21790
|
|
|
95
98
|
wizards/shift_handoff_wizard.py,sha256=SkoNB0nLQGg92yz4j1j3NBR2mGVe_rw1pTjOFDy-JH0,19092
|
|
96
99
|
wizards/soap_note_wizard.py,sha256=DBzuuuOvIONhwdfn8jaE4PCuGeKsFwM65XTb6gKFIy4,23572
|
|
97
100
|
wizards/treatment_plan.py,sha256=t2Qk5eCa1gobEUaBztnwem_p9OuJK5BKqJ-Po8vXuns,512
|
|
98
|
-
empathy_framework-3.3.
|
|
99
|
-
empathy_framework-3.3.
|
|
100
|
-
empathy_framework-3.3.
|
|
101
|
-
empathy_framework-3.3.
|
|
102
|
-
empathy_framework-3.3.
|
|
101
|
+
empathy_framework-3.3.3.dist-info/METADATA,sha256=RyG6jGb_KTSrLrIT5ueZ5tckAWXXSTToyR37ePnVPh8,28781
|
|
102
|
+
empathy_framework-3.3.3.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
103
|
+
empathy_framework-3.3.3.dist-info/entry_points.txt,sha256=zMu7sKCiLndbEEXjTecltS-1P_JZoEUKrifuRBBbroc,1268
|
|
104
|
+
empathy_framework-3.3.3.dist-info/top_level.txt,sha256=8zHB-_f0MI2K55LIEjCeaFNcog3_KgLBa_dDfzE8ESI,110
|
|
105
|
+
empathy_framework-3.3.3.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"note":"This file is an internal implementation detail to speed up HTML report generation. Its format can change at any time. You might be looking for the JSON report: https://coverage.rtfd.io/cmd.html#cmd-json","format":5,"version":"7.11.2","globals":"1647e1602d568c377a9cb0dc3296bc7b","files":{"__init___py":{"hash":"1e943cec927dee34f9523b2eb67d8922","index":{"url":"__init___py.html","file":"__init__.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":6,"n_excluded":0,"n_missing":0,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"claude_memory_py":{"hash":"25f8fe4e69f6b1e4091924c070803e8a","index":{"url":"claude_memory_py.html","file":"claude_memory.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":169,"n_excluded":0,"n_missing":169,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"code_health_py":{"hash":"a78753eaebd08c9c2cb5f1cd5a14f723","index":{"url":"code_health_py.html","file":"code_health.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":503,"n_excluded":0,"n_missing":503,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"contextual_patterns_py":{"hash":"12004dba086f2def1d9e65bbf68a88f8","index":{"url":"contextual_patterns_py.html","file":"contextual_patterns.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":171,"n_excluded":0,"n_missing":171,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"core_py":{"hash":"aa25b266741f161b0fa2500af1db03da","index":{"url":"core_py.html","file":"core.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":177,"n_excluded":0,"n_missing":151,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"git_pattern_extractor_py":{"hash":"88e57b53ff683a92613ae343a55ad1bb","index":{"url":"git_pattern_extractor_py.html","file":"git_pattern_extractor.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":164,"n_excluded":0,"n_missing":164,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"levels_py":{"hash":"ef211f0c742ccdab452cbe36ac205815","index":{"url":"levels_py.html","file":"levels.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":33,"n_excluded":0,"n_missing":12,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"pattern_confidence_py":{"hash":"1806d001ef22f2f9c4f5cc24faa5724d","index":{"url":"pattern_confidence_py.html","file":"pattern_confidence.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":196,"n_excluded":0,"n_missing":196,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"pattern_resolver_py":{"hash":"af2687d544197eb576abe872270157a5","index":{"url":"pattern_resolver_py.html","file":"pattern_resolver.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":121,"n_excluded":0,"n_missing":121,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"pattern_summary_py":{"hash":"51c42611c0d7a57f4e5c9f487f3b0882","index":{"url":"pattern_summary_py.html","file":"pattern_summary.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":178,"n_excluded":0,"n_missing":178,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"providers_py":{"hash":"8b779f9132bea067bec66007bd492b45","index":{"url":"providers_py.html","file":"providers.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":106,"n_excluded":0,"n_missing":76,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_10414145323772df___init___py":{"hash":"dec456df46eda04d5d3381b09af05c36","index":{"url":"z_10414145323772df___init___py.html","file":"security/__init__.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":3,"n_excluded":0,"n_missing":0,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_10414145323772df_audit_logger_py":{"hash":"9197b939a93f6b8dd8549ab6b73f0887","index":{"url":"z_10414145323772df_audit_logger_py.html","file":"security/audit_logger.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":247,"n_excluded":0,"n_missing":247,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_10414145323772df_audit_logger_example_py":{"hash":"ecc80543a0cac77b9b5a52d9d8451793","index":{"url":"z_10414145323772df_audit_logger_example_py.html","file":"security/audit_logger_example.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":59,"n_excluded":0,"n_missing":59,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_10414145323772df_pii_scrubber_py":{"hash":"0254532a873c529be428a4d88663e917","index":{"url":"z_10414145323772df_pii_scrubber_py.html","file":"security/pii_scrubber.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":140,"n_excluded":0,"n_missing":140,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_10414145323772df_secrets_detector_py":{"hash":"b160d5903a118f959559e32f7535d7e2","index":{"url":"z_10414145323772df_secrets_detector_py.html","file":"security/secrets_detector.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":199,"n_excluded":0,"n_missing":199,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_10414145323772df_secrets_detector_example_py":{"hash":"ba9b9af2e80e78ec21a15712e06dd279","index":{"url":"z_10414145323772df_secrets_detector_example_py.html","file":"security/secrets_detector_example.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":145,"n_excluded":0,"n_missing":145,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_10414145323772df_secure_memdocs_py":{"hash":"47c339d82b66068fb9a831fffb58bc8a","index":{"url":"z_10414145323772df_secure_memdocs_py.html","file":"security/secure_memdocs.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":350,"n_excluded":0,"n_missing":350,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_10414145323772df_secure_memdocs_example_py":{"hash":"3fd076ca92a0a84002c57d80cfed902f","index":{"url":"z_10414145323772df_secure_memdocs_example_py.html","file":"security/secure_memdocs_example.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":106,"n_excluded":0,"n_missing":106,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"session_status_py":{"hash":"4c8d6be4bbdac24bc27d0c27890532a6","index":{"url":"session_status_py.html","file":"session_status.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":312,"n_excluded":0,"n_missing":312,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"state_py":{"hash":"724ab29020a3a3870ac6b9c94c71127d","index":{"url":"state_py.html","file":"state.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":87,"n_excluded":0,"n_missing":40,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_984ef1e268fea449___init___py":{"hash":"10fa30f44c3688eb2de5302412aa33d6","index":{"url":"z_984ef1e268fea449___init___py.html","file":"wizards/__init__.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":5,"n_excluded":0,"n_missing":5,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_984ef1e268fea449_base_wizard_py":{"hash":"590f2d248a77ea3e621b9f3c4ded2397","index":{"url":"z_984ef1e268fea449_base_wizard_py.html","file":"wizards/base_wizard.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":56,"n_excluded":0,"n_missing":56,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_984ef1e268fea449_customer_support_wizard_py":{"hash":"f92a98bbbec12fad579ac19787971b08","index":{"url":"z_984ef1e268fea449_customer_support_wizard_py.html","file":"wizards/customer_support_wizard.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":17,"n_excluded":0,"n_missing":17,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_984ef1e268fea449_healthcare_wizard_py":{"hash":"96977dfa18d691fdd84424311686d23a","index":{"url":"z_984ef1e268fea449_healthcare_wizard_py.html","file":"wizards/healthcare_wizard.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":57,"n_excluded":0,"n_missing":57,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_984ef1e268fea449_technology_wizard_py":{"hash":"6998c841130aa6e0982dc586006a5640","index":{"url":"z_984ef1e268fea449_technology_wizard_py.html","file":"wizards/technology_wizard.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":19,"n_excluded":0,"n_missing":19,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}}}}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"note":"This file is an internal implementation detail to speed up HTML report generation. Its format can change at any time. You might be looking for the JSON report: https://coverage.rtfd.io/cmd.html#cmd-json","format":5,"version":"7.11.2","globals":"93e0a98f3da7f95e5ae873f233acfe8f","files":{"z_0da0bc3caf3df21d___init___py":{"hash":"678b97c61cc7e540c9ecbd0485aef62e","index":{"url":"z_0da0bc3caf3df21d___init___py.html","file":"/Users/patrickroebuck/empathy_11_6_2025/Empathy-framework/empathy_llm_toolkit/__init__.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":6,"n_excluded":0,"n_missing":0,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_0da0bc3caf3df21d_claude_memory_py":{"hash":"9e1a909857359093b60c8b3641b9686f","index":{"url":"z_0da0bc3caf3df21d_claude_memory_py.html","file":"/Users/patrickroebuck/empathy_11_6_2025/Empathy-framework/empathy_llm_toolkit/claude_memory.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":169,"n_excluded":0,"n_missing":132,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_0da0bc3caf3df21d_core_py":{"hash":"45f6bf0d1f0f9b193700d313f3999f0a","index":{"url":"z_0da0bc3caf3df21d_core_py.html","file":"/Users/patrickroebuck/empathy_11_6_2025/Empathy-framework/empathy_llm_toolkit/core.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":124,"n_excluded":0,"n_missing":100,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_0da0bc3caf3df21d_levels_py":{"hash":"029cd19bbfaefe72a2df6fb26fafbb07","index":{"url":"z_0da0bc3caf3df21d_levels_py.html","file":"/Users/patrickroebuck/empathy_11_6_2025/Empathy-framework/empathy_llm_toolkit/levels.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":33,"n_excluded":0,"n_missing":12,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_0da0bc3caf3df21d_providers_py":{"hash":"8a61e565ded340098a9717471cb139cc","index":{"url":"z_0da0bc3caf3df21d_providers_py.html","file":"/Users/patrickroebuck/empathy_11_6_2025/Empathy-framework/empathy_llm_toolkit/providers.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":104,"n_excluded":0,"n_missing":74,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"__init___py":{"hash":"bc61a9c102480a73e01fb8f507fe604c","index":{"url":"__init___py.html","file":"__init__.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":3,"n_excluded":0,"n_missing":0,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"audit_logger_py":{"hash":"288003e820abd1edb81b099a12e58af5","index":{"url":"audit_logger_py.html","file":"audit_logger.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":244,"n_excluded":0,"n_missing":72,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"audit_logger_example_py":{"hash":"8c491197716328c7faed6badacb3a68b","index":{"url":"audit_logger_example_py.html","file":"audit_logger_example.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":60,"n_excluded":0,"n_missing":60,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"pii_scrubber_py":{"hash":"9768c14c0e1e90619f7d80f059ca4395","index":{"url":"pii_scrubber_py.html","file":"pii_scrubber.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":140,"n_excluded":0,"n_missing":107,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"secrets_detector_py":{"hash":"36cd068d345d0328e6959132de4ade69","index":{"url":"secrets_detector_py.html","file":"secrets_detector.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":199,"n_excluded":0,"n_missing":199,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"test_audit_logger_py":{"hash":"a5a92daff7da2027470aca6a728adbb8","index":{"url":"test_audit_logger_py.html","file":"test_audit_logger.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":185,"n_excluded":0,"n_missing":1,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}},"z_0da0bc3caf3df21d_state_py":{"hash":"3ed61e7760d5e588d4d6743dffa9094f","index":{"url":"z_0da0bc3caf3df21d_state_py.html","file":"/Users/patrickroebuck/empathy_11_6_2025/Empathy-framework/empathy_llm_toolkit/state.py","description":"","nums":{"precision":0,"n_files":1,"n_statements":87,"n_excluded":0,"n_missing":40,"n_branches":0,"n_partial_branches":0,"n_missing_branches":0}}}}}
|
empathy_os/__init__.py
CHANGED
|
@@ -62,26 +62,26 @@ __email__ = "hello@deepstudy.ai"
|
|
|
62
62
|
|
|
63
63
|
from .config import EmpathyConfig, load_config
|
|
64
64
|
from .coordination import (
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
65
|
+
AgentCoordinator,
|
|
66
|
+
AgentTask,
|
|
67
|
+
ConflictResolver,
|
|
68
|
+
ResolutionResult,
|
|
69
|
+
ResolutionStrategy,
|
|
70
|
+
TeamPriorities,
|
|
71
|
+
TeamSession,
|
|
72
72
|
)
|
|
73
73
|
from .core import EmpathyOS
|
|
74
74
|
from .emergence import EmergenceDetector
|
|
75
75
|
from .exceptions import (
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
76
|
+
CollaborationStateError,
|
|
77
|
+
ConfidenceThresholdError,
|
|
78
|
+
EmpathyFrameworkError,
|
|
79
|
+
EmpathyLevelError,
|
|
80
|
+
FeedbackLoopError,
|
|
81
|
+
LeveragePointError,
|
|
82
|
+
PatternNotFoundError,
|
|
83
|
+
TrustThresholdError,
|
|
84
|
+
ValidationError,
|
|
85
85
|
)
|
|
86
86
|
from .feedback_loops import FeedbackLoopDetector
|
|
87
87
|
from .levels import Level1Reactive, Level2Guided, Level3Proactive, Level4Anticipatory, Level5Systems
|
|
@@ -90,41 +90,41 @@ from .logging_config import LoggingConfig, get_logger
|
|
|
90
90
|
|
|
91
91
|
# Memory module (unified short-term + long-term + security)
|
|
92
92
|
from .memory import (
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
93
|
+
AccessTier,
|
|
94
|
+
AgentCredentials, # Memory module imports
|
|
95
|
+
AuditEvent,
|
|
96
|
+
AuditLogger,
|
|
97
|
+
Classification,
|
|
98
|
+
ClassificationRules,
|
|
99
|
+
ClaudeMemoryConfig,
|
|
100
|
+
ClaudeMemoryLoader,
|
|
101
|
+
ConflictContext,
|
|
102
|
+
EncryptionManager,
|
|
103
|
+
Environment,
|
|
104
|
+
MemDocsStorage,
|
|
105
|
+
MemoryConfig,
|
|
106
|
+
MemoryPermissionError,
|
|
107
|
+
PatternMetadata,
|
|
108
|
+
PIIDetection,
|
|
109
|
+
PIIPattern,
|
|
110
|
+
PIIScrubber,
|
|
111
|
+
RedisShortTermMemory,
|
|
112
|
+
SecretDetection,
|
|
113
|
+
SecretsDetector,
|
|
114
|
+
SecretType,
|
|
115
|
+
SecureMemDocsIntegration,
|
|
116
|
+
SecurePattern,
|
|
117
|
+
SecurityError,
|
|
118
|
+
SecurityViolation,
|
|
119
|
+
Severity,
|
|
120
|
+
StagedPattern,
|
|
121
|
+
TTLStrategy,
|
|
122
|
+
UnifiedMemory,
|
|
123
|
+
check_redis_connection,
|
|
124
|
+
detect_secrets,
|
|
125
|
+
get_railway_redis,
|
|
126
|
+
get_redis_config,
|
|
127
|
+
get_redis_memory,
|
|
128
128
|
)
|
|
129
129
|
from .monitoring import AgentMetrics, AgentMonitor, TeamMetrics
|
|
130
130
|
from .pattern_library import Pattern, PatternLibrary, PatternMatch
|
empathy_os/cli.py
CHANGED
|
@@ -25,6 +25,7 @@ from empathy_os.discovery import show_tip_if_available
|
|
|
25
25
|
from empathy_os.logging_config import get_logger
|
|
26
26
|
from empathy_os.pattern_library import PatternLibrary
|
|
27
27
|
from empathy_os.persistence import MetricsCollector, PatternPersistence, StateManager
|
|
28
|
+
from empathy_os.platform_utils import setup_asyncio_policy
|
|
28
29
|
from empathy_os.templates import cmd_new
|
|
29
30
|
from empathy_os.workflows import (
|
|
30
31
|
WorkflowConfig,
|
|
@@ -1796,10 +1797,15 @@ def cmd_workflow(args):
|
|
|
1796
1797
|
if duration_ms is None and hasattr(result, "duration_seconds"):
|
|
1797
1798
|
duration_ms = int(result.duration_seconds * 1000)
|
|
1798
1799
|
|
|
1799
|
-
# Get cost info if available
|
|
1800
|
+
# Get cost info if available (check cost_report first, then direct cost attribute)
|
|
1800
1801
|
cost_report = getattr(result, "cost_report", None)
|
|
1801
|
-
|
|
1802
|
-
|
|
1802
|
+
if cost_report and hasattr(cost_report, "total_cost"):
|
|
1803
|
+
total_cost = cost_report.total_cost
|
|
1804
|
+
savings = getattr(cost_report, "savings", 0.0)
|
|
1805
|
+
else:
|
|
1806
|
+
# Fall back to direct cost attribute (e.g., CodeReviewPipelineResult)
|
|
1807
|
+
total_cost = getattr(result, "cost", 0.0)
|
|
1808
|
+
savings = 0.0
|
|
1803
1809
|
|
|
1804
1810
|
if args.json:
|
|
1805
1811
|
# Extract error from various result types
|
|
@@ -1829,11 +1835,6 @@ def cmd_workflow(args):
|
|
|
1829
1835
|
print(f"\n{output_content}\n")
|
|
1830
1836
|
else:
|
|
1831
1837
|
print("\n✓ Workflow completed successfully.\n")
|
|
1832
|
-
|
|
1833
|
-
# Brief footer with timing (detailed costs available via 'empathy costs')
|
|
1834
|
-
print("-" * 50)
|
|
1835
|
-
ms = duration_ms or 0
|
|
1836
|
-
print(f"Completed in {ms}ms | Cost: ${total_cost:.4f} (saved ${savings:.4f})")
|
|
1837
1838
|
else:
|
|
1838
1839
|
# Extract error from various result types
|
|
1839
1840
|
error_msg = getattr(result, "error", None)
|
|
@@ -1980,6 +1981,9 @@ def cmd_frameworks(args):
|
|
|
1980
1981
|
|
|
1981
1982
|
def main():
|
|
1982
1983
|
"""Main CLI entry point"""
|
|
1984
|
+
# Configure Windows-compatible asyncio event loop policy
|
|
1985
|
+
setup_asyncio_policy()
|
|
1986
|
+
|
|
1983
1987
|
parser = argparse.ArgumentParser(
|
|
1984
1988
|
prog="empathy",
|
|
1985
1989
|
description="Empathy - Build AI systems with 5 levels of empathy",
|
empathy_os/config.py
CHANGED
|
@@ -95,6 +95,12 @@ class EmpathyConfig:
|
|
|
95
95
|
Example:
|
|
96
96
|
>>> config = EmpathyConfig.from_yaml("empathy.config.yml")
|
|
97
97
|
>>> empathy = EmpathyOS(config=config)
|
|
98
|
+
|
|
99
|
+
Note:
|
|
100
|
+
Unknown fields in the YAML file are silently ignored.
|
|
101
|
+
This allows config files to contain settings for other
|
|
102
|
+
components (e.g., model_preferences, workflows) without
|
|
103
|
+
breaking EmpathyConfig loading.
|
|
98
104
|
"""
|
|
99
105
|
if not YAML_AVAILABLE:
|
|
100
106
|
raise ImportError(
|
|
@@ -104,7 +110,14 @@ class EmpathyConfig:
|
|
|
104
110
|
with open(filepath) as f:
|
|
105
111
|
data = yaml.safe_load(f)
|
|
106
112
|
|
|
107
|
-
|
|
113
|
+
# Filter to only known fields (gracefully ignore unknown fields like
|
|
114
|
+
# 'provider', 'model_preferences', 'workflows', etc.)
|
|
115
|
+
from dataclasses import fields as dataclass_fields
|
|
116
|
+
|
|
117
|
+
valid_fields = {f.name for f in dataclass_fields(cls)}
|
|
118
|
+
filtered_data = {k: v for k, v in data.items() if k in valid_fields}
|
|
119
|
+
|
|
120
|
+
return cls(**filtered_data)
|
|
108
121
|
|
|
109
122
|
@classmethod
|
|
110
123
|
def from_json(cls, filepath: str) -> "EmpathyConfig":
|
|
@@ -120,11 +133,20 @@ class EmpathyConfig:
|
|
|
120
133
|
Example:
|
|
121
134
|
>>> config = EmpathyConfig.from_json("empathy.config.json")
|
|
122
135
|
>>> empathy = EmpathyOS(config=config)
|
|
136
|
+
|
|
137
|
+
Note:
|
|
138
|
+
Unknown fields in the JSON file are silently ignored.
|
|
123
139
|
"""
|
|
124
140
|
with open(filepath) as f:
|
|
125
141
|
data = json.load(f)
|
|
126
142
|
|
|
127
|
-
|
|
143
|
+
# Filter to only known fields (gracefully ignore unknown fields)
|
|
144
|
+
from dataclasses import fields as dataclass_fields
|
|
145
|
+
|
|
146
|
+
valid_fields = {f.name for f in dataclass_fields(cls)}
|
|
147
|
+
filtered_data = {k: v for k, v in data.items() if k in valid_fields}
|
|
148
|
+
|
|
149
|
+
return cls(**filtered_data)
|
|
128
150
|
|
|
129
151
|
@classmethod
|
|
130
152
|
def from_env(cls, prefix: str = "EMPATHY_") -> "EmpathyConfig":
|
|
@@ -343,12 +365,14 @@ class EmpathyConfig:
|
|
|
343
365
|
)
|
|
344
366
|
|
|
345
367
|
if not 0.0 <= self.pattern_confidence_threshold <= 1.0:
|
|
346
|
-
|
|
347
|
-
raise ValueError(f"pattern_confidence_threshold must be 0.0-1.0, got {
|
|
368
|
+
threshold_val = self.pattern_confidence_threshold
|
|
369
|
+
raise ValueError(f"pattern_confidence_threshold must be 0.0-1.0, got {threshold_val}")
|
|
348
370
|
|
|
349
371
|
if self.persistence_backend not in ("sqlite", "json", "none"):
|
|
350
|
-
|
|
351
|
-
raise ValueError(
|
|
372
|
+
backend_val = self.persistence_backend
|
|
373
|
+
raise ValueError(
|
|
374
|
+
f"persistence_backend must be 'sqlite', 'json', or 'none', got {backend_val}"
|
|
375
|
+
)
|
|
352
376
|
|
|
353
377
|
return True
|
|
354
378
|
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Cross-Platform Utilities for Empathy Framework
|
|
3
|
+
|
|
4
|
+
Provides platform-independent utilities for:
|
|
5
|
+
- File paths and directories
|
|
6
|
+
- File encoding
|
|
7
|
+
- Asyncio event loop handling
|
|
8
|
+
- Environment detection
|
|
9
|
+
|
|
10
|
+
Copyright 2025 Smart-AI-Memory
|
|
11
|
+
Licensed under Fair Source License 0.9
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import asyncio
|
|
15
|
+
import os
|
|
16
|
+
import platform
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def is_windows() -> bool:
|
|
22
|
+
"""Check if running on Windows."""
|
|
23
|
+
return platform.system() == "Windows"
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def is_macos() -> bool:
|
|
27
|
+
"""Check if running on macOS."""
|
|
28
|
+
return platform.system() == "Darwin"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def is_linux() -> bool:
|
|
32
|
+
"""Check if running on Linux."""
|
|
33
|
+
return platform.system() == "Linux"
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def get_default_log_dir() -> Path:
|
|
37
|
+
"""
|
|
38
|
+
Get the default log directory for the current platform.
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
Path: Platform-appropriate log directory
|
|
42
|
+
- Windows: %APPDATA%/empathy/logs
|
|
43
|
+
- macOS: ~/Library/Logs/empathy
|
|
44
|
+
- Linux: /var/log/empathy (if writable) or ~/.local/share/empathy/logs
|
|
45
|
+
"""
|
|
46
|
+
if is_windows():
|
|
47
|
+
appdata = os.environ.get("APPDATA", os.path.expanduser("~"))
|
|
48
|
+
return Path(appdata) / "empathy" / "logs"
|
|
49
|
+
elif is_macos():
|
|
50
|
+
return Path.home() / "Library" / "Logs" / "empathy"
|
|
51
|
+
else: # Linux and other Unix
|
|
52
|
+
var_log = Path("/var/log/empathy")
|
|
53
|
+
if var_log.exists() or (var_log.parent.exists() and os.access(var_log.parent, os.W_OK)):
|
|
54
|
+
return var_log
|
|
55
|
+
# Fallback to user directory
|
|
56
|
+
return Path.home() / ".local" / "share" / "empathy" / "logs"
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def get_default_data_dir() -> Path:
|
|
60
|
+
"""
|
|
61
|
+
Get the default data directory for the current platform.
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
Path: Platform-appropriate data directory
|
|
65
|
+
- Windows: %APPDATA%/empathy
|
|
66
|
+
- macOS: ~/Library/Application Support/empathy
|
|
67
|
+
- Linux: ~/.local/share/empathy
|
|
68
|
+
"""
|
|
69
|
+
if is_windows():
|
|
70
|
+
appdata = os.environ.get("APPDATA", os.path.expanduser("~"))
|
|
71
|
+
return Path(appdata) / "empathy"
|
|
72
|
+
elif is_macos():
|
|
73
|
+
return Path.home() / "Library" / "Application Support" / "empathy"
|
|
74
|
+
else: # Linux and other Unix
|
|
75
|
+
xdg_data = os.environ.get("XDG_DATA_HOME", str(Path.home() / ".local" / "share"))
|
|
76
|
+
return Path(xdg_data) / "empathy"
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def get_default_config_dir() -> Path:
|
|
80
|
+
"""
|
|
81
|
+
Get the default configuration directory for the current platform.
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
Path: Platform-appropriate config directory
|
|
85
|
+
- Windows: %APPDATA%/empathy
|
|
86
|
+
- macOS: ~/Library/Preferences/empathy
|
|
87
|
+
- Linux: ~/.config/empathy
|
|
88
|
+
"""
|
|
89
|
+
if is_windows():
|
|
90
|
+
appdata = os.environ.get("APPDATA", os.path.expanduser("~"))
|
|
91
|
+
return Path(appdata) / "empathy"
|
|
92
|
+
elif is_macos():
|
|
93
|
+
return Path.home() / "Library" / "Preferences" / "empathy"
|
|
94
|
+
else: # Linux and other Unix
|
|
95
|
+
xdg_config = os.environ.get("XDG_CONFIG_HOME", str(Path.home() / ".config"))
|
|
96
|
+
return Path(xdg_config) / "empathy"
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def get_default_cache_dir() -> Path:
|
|
100
|
+
"""
|
|
101
|
+
Get the default cache directory for the current platform.
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
Path: Platform-appropriate cache directory
|
|
105
|
+
- Windows: %LOCALAPPDATA%/empathy/cache
|
|
106
|
+
- macOS: ~/Library/Caches/empathy
|
|
107
|
+
- Linux: ~/.cache/empathy
|
|
108
|
+
"""
|
|
109
|
+
if is_windows():
|
|
110
|
+
localappdata = os.environ.get(
|
|
111
|
+
"LOCALAPPDATA", os.environ.get("APPDATA", os.path.expanduser("~"))
|
|
112
|
+
)
|
|
113
|
+
return Path(localappdata) / "empathy" / "cache"
|
|
114
|
+
elif is_macos():
|
|
115
|
+
return Path.home() / "Library" / "Caches" / "empathy"
|
|
116
|
+
else: # Linux and other Unix
|
|
117
|
+
xdg_cache = os.environ.get("XDG_CACHE_HOME", str(Path.home() / ".cache"))
|
|
118
|
+
return Path(xdg_cache) / "empathy"
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def setup_asyncio_policy() -> None:
|
|
122
|
+
"""
|
|
123
|
+
Configure asyncio event loop policy for the current platform.
|
|
124
|
+
|
|
125
|
+
On Windows, this uses WindowsSelectorEventLoopPolicy to avoid issues
|
|
126
|
+
with the default ProactorEventLoop, particularly with subprocesses
|
|
127
|
+
and certain network operations.
|
|
128
|
+
|
|
129
|
+
This should be called early in the application startup, before
|
|
130
|
+
any asyncio.run() calls.
|
|
131
|
+
"""
|
|
132
|
+
if is_windows():
|
|
133
|
+
# Windows requires WindowsSelectorEventLoopPolicy for compatibility
|
|
134
|
+
# with many libraries and subprocess operations
|
|
135
|
+
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def safe_run_async(coro: Any, debug: bool = False) -> Any:
|
|
139
|
+
"""
|
|
140
|
+
Run an async coroutine with platform-appropriate event loop handling.
|
|
141
|
+
|
|
142
|
+
This is a cross-platform wrapper for asyncio.run() that handles
|
|
143
|
+
Windows-specific event loop requirements.
|
|
144
|
+
|
|
145
|
+
Args:
|
|
146
|
+
coro: Coroutine to run
|
|
147
|
+
debug: Enable asyncio debug mode
|
|
148
|
+
|
|
149
|
+
Returns:
|
|
150
|
+
Result of the coroutine
|
|
151
|
+
"""
|
|
152
|
+
setup_asyncio_policy()
|
|
153
|
+
return asyncio.run(coro, debug=debug)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def open_text_file(path: str | Path, mode: str = "r", **kwargs: Any):
|
|
157
|
+
"""
|
|
158
|
+
Open a text file with UTF-8 encoding by default.
|
|
159
|
+
|
|
160
|
+
This ensures consistent encoding across platforms, as Windows
|
|
161
|
+
defaults to cp1252 while Unix defaults to UTF-8.
|
|
162
|
+
|
|
163
|
+
Args:
|
|
164
|
+
path: File path to open
|
|
165
|
+
mode: File mode (r, w, a, etc.)
|
|
166
|
+
**kwargs: Additional arguments passed to open()
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
File object
|
|
170
|
+
"""
|
|
171
|
+
kwargs.setdefault("encoding", "utf-8")
|
|
172
|
+
return open(path, mode, **kwargs)
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
def read_text_file(path: str | Path, encoding: str = "utf-8") -> str:
|
|
176
|
+
"""
|
|
177
|
+
Read a text file with UTF-8 encoding by default.
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
path: File path to read
|
|
181
|
+
encoding: File encoding (default: utf-8)
|
|
182
|
+
|
|
183
|
+
Returns:
|
|
184
|
+
File contents as string
|
|
185
|
+
"""
|
|
186
|
+
return Path(path).read_text(encoding=encoding)
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def write_text_file(path: str | Path, content: str, encoding: str = "utf-8") -> int:
|
|
190
|
+
"""
|
|
191
|
+
Write content to a text file with UTF-8 encoding by default.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
path: File path to write
|
|
195
|
+
content: Content to write
|
|
196
|
+
encoding: File encoding (default: utf-8)
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
Number of characters written
|
|
200
|
+
"""
|
|
201
|
+
return Path(path).write_text(content, encoding=encoding)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def normalize_path(path: str | Path) -> Path:
|
|
205
|
+
"""
|
|
206
|
+
Normalize a path for the current platform.
|
|
207
|
+
|
|
208
|
+
Converts forward slashes to backslashes on Windows and
|
|
209
|
+
resolves any relative path components.
|
|
210
|
+
|
|
211
|
+
Args:
|
|
212
|
+
path: Path to normalize
|
|
213
|
+
|
|
214
|
+
Returns:
|
|
215
|
+
Normalized Path object
|
|
216
|
+
"""
|
|
217
|
+
return Path(path).resolve()
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
def get_temp_dir() -> Path:
|
|
221
|
+
"""
|
|
222
|
+
Get the system temporary directory.
|
|
223
|
+
|
|
224
|
+
Returns:
|
|
225
|
+
Path to the system temp directory
|
|
226
|
+
"""
|
|
227
|
+
import tempfile
|
|
228
|
+
|
|
229
|
+
return Path(tempfile.gettempdir())
|
|
230
|
+
|
|
231
|
+
|
|
232
|
+
def ensure_dir(path: str | Path) -> Path:
|
|
233
|
+
"""
|
|
234
|
+
Ensure a directory exists, creating it if necessary.
|
|
235
|
+
|
|
236
|
+
Args:
|
|
237
|
+
path: Directory path to ensure
|
|
238
|
+
|
|
239
|
+
Returns:
|
|
240
|
+
Path object for the directory
|
|
241
|
+
"""
|
|
242
|
+
dir_path = Path(path)
|
|
243
|
+
dir_path.mkdir(parents=True, exist_ok=True)
|
|
244
|
+
return dir_path
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
# Platform information for diagnostics
|
|
248
|
+
PLATFORM_INFO = {
|
|
249
|
+
"system": platform.system(),
|
|
250
|
+
"release": platform.release(),
|
|
251
|
+
"version": platform.version(),
|
|
252
|
+
"machine": platform.machine(),
|
|
253
|
+
"python_version": platform.python_version(),
|
|
254
|
+
"is_windows": is_windows(),
|
|
255
|
+
"is_macos": is_macos(),
|
|
256
|
+
"is_linux": is_linux(),
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def get_platform_info() -> dict:
|
|
261
|
+
"""Get platform information for diagnostics."""
|
|
262
|
+
return PLATFORM_INFO.copy()
|
empathy_os/workflow_commands.py
CHANGED
|
@@ -347,8 +347,8 @@ def ship_workflow(
|
|
|
347
347
|
# Import here to avoid circular imports
|
|
348
348
|
try:
|
|
349
349
|
from empathy_llm_toolkit.cli.sync_claude import (
|
|
350
|
-
sync_patterns_to_claude,
|
|
351
|
-
)
|
|
350
|
+
sync_patterns_to_claude, # type: ignore[attr-defined]
|
|
351
|
+
)
|
|
352
352
|
|
|
353
353
|
result = sync_patterns_to_claude(
|
|
354
354
|
patterns_dir=patterns_dir, output_dir=".claude/rules/empathy"
|
empathy_software_plugin/cli.py
CHANGED
|
@@ -655,7 +655,9 @@ def scan_command():
|
|
|
655
655
|
severity_icon = (
|
|
656
656
|
"🔴"
|
|
657
657
|
if issue.severity == "high"
|
|
658
|
-
else "🟡"
|
|
658
|
+
else "🟡"
|
|
659
|
+
if issue.severity == "medium"
|
|
660
|
+
else "🔵"
|
|
659
661
|
)
|
|
660
662
|
print(f" {severity_icon} Line {issue.line_number}: {issue.message}")
|
|
661
663
|
if len(result.issues) > 3:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|