dhee 3.2.0__tar.gz → 3.3.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.
- {dhee-3.2.0 → dhee-3.3.0}/PKG-INFO +44 -4
- {dhee-3.2.0 → dhee-3.3.0}/README.md +43 -3
- {dhee-3.2.0 → dhee-3.3.0}/dhee/__init__.py +1 -1
- {dhee-3.2.0 → dhee-3.3.0}/dhee/cli.py +68 -0
- dhee-3.3.0/dhee/hooks/claude_code/__init__.py +2 -0
- dhee-3.3.0/dhee/hooks/claude_code/__main__.py +256 -0
- dhee-3.3.0/dhee/hooks/claude_code/install.py +173 -0
- dhee-3.3.0/dhee/hooks/claude_code/privacy.py +34 -0
- dhee-3.3.0/dhee/hooks/claude_code/renderer.py +310 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee.egg-info/PKG-INFO +44 -4
- {dhee-3.2.0 → dhee-3.3.0}/dhee.egg-info/SOURCES.txt +7 -64
- {dhee-3.2.0 → dhee-3.3.0}/dhee.egg-info/top_level.txt +0 -3
- {dhee-3.2.0 → dhee-3.3.0}/pyproject.toml +1 -1
- dhee-3.3.0/tests/test_claude_code_hooks.py +388 -0
- dhee-3.2.0/engram-bridge/demo/demo-app/main.py +0 -65
- dhee-3.2.0/engram-bridge/demo/seed.py +0 -221
- dhee-3.2.0/engram-bridge/engram_bridge/__init__.py +0 -4
- dhee-3.2.0/engram-bridge/engram_bridge/agents/__init__.py +0 -6
- dhee-3.2.0/engram-bridge/engram_bridge/agents/base.py +0 -40
- dhee-3.2.0/engram-bridge/engram_bridge/agents/claude.py +0 -152
- dhee-3.2.0/engram-bridge/engram_bridge/agents/codex.py +0 -119
- dhee-3.2.0/engram-bridge/engram_bridge/agents/custom.py +0 -95
- dhee-3.2.0/engram-bridge/engram_bridge/bridge.py +0 -1856
- dhee-3.2.0/engram-bridge/engram_bridge/channels/__init__.py +0 -6
- dhee-3.2.0/engram-bridge/engram_bridge/channels/base.py +0 -44
- dhee-3.2.0/engram-bridge/engram_bridge/channels/telegram.py +0 -131
- dhee-3.2.0/engram-bridge/engram_bridge/channels/web.py +0 -1785
- dhee-3.2.0/engram-bridge/engram_bridge/config.py +0 -143
- dhee-3.2.0/engram-bridge/engram_bridge/coordination/__init__.py +0 -137
- dhee-3.2.0/engram-bridge/engram_bridge/utils.py +0 -43
- dhee-3.2.0/engram-enterprise/engram_enterprise/__init__.py +0 -20
- dhee-3.2.0/engram-enterprise/engram_enterprise/acceptance.py +0 -142
- dhee-3.2.0/engram-enterprise/engram_enterprise/active_memory.py +0 -406
- dhee-3.2.0/engram-enterprise/engram_enterprise/api/app.py +0 -1026
- dhee-3.2.0/engram-enterprise/engram_enterprise/api/auth.py +0 -76
- dhee-3.2.0/engram-enterprise/engram_enterprise/api/schemas.py +0 -170
- dhee-3.2.0/engram-enterprise/engram_enterprise/api/server.py +0 -34
- dhee-3.2.0/engram-enterprise/engram_enterprise/async_embedder.py +0 -125
- dhee-3.2.0/engram-enterprise/engram_enterprise/async_llm.py +0 -127
- dhee-3.2.0/engram-enterprise/engram_enterprise/async_memory.py +0 -481
- dhee-3.2.0/engram-enterprise/engram_enterprise/async_sqlite.py +0 -448
- dhee-3.2.0/engram-enterprise/engram_enterprise/cli.py +0 -547
- dhee-3.2.0/engram-enterprise/engram_enterprise/client.py +0 -418
- dhee-3.2.0/engram-enterprise/engram_enterprise/context_packer.py +0 -62
- dhee-3.2.0/engram-enterprise/engram_enterprise/dual_search.py +0 -168
- dhee-3.2.0/engram-enterprise/engram_enterprise/episodic_store.py +0 -290
- dhee-3.2.0/engram-enterprise/engram_enterprise/integrations/__init__.py +0 -0
- dhee-3.2.0/engram-enterprise/engram_enterprise/integrations/claude_code.py +0 -532
- dhee-3.2.0/engram-enterprise/engram_enterprise/integrations/openclaw.py +0 -177
- dhee-3.2.0/engram-enterprise/engram_enterprise/invariants.py +0 -110
- dhee-3.2.0/engram-enterprise/engram_enterprise/kernel.py +0 -1792
- dhee-3.2.0/engram-enterprise/engram_enterprise/main_cli.py +0 -455
- dhee-3.2.0/engram-enterprise/engram_enterprise/policy.py +0 -149
- dhee-3.2.0/engram-enterprise/engram_enterprise/provenance.py +0 -40
- dhee-3.2.0/engram-enterprise/engram_enterprise/refcounts.py +0 -45
- dhee-3.2.0/engram-enterprise/engram_enterprise/reranker.py +0 -76
- dhee-3.2.0/engram-enterprise/engram_enterprise/schema.py +0 -230
- dhee-3.2.0/engram-enterprise/engram_enterprise/staging_store.py +0 -97
- dhee-3.2.0/engram-enterprise/tests/test_enterprise.py +0 -117
- dhee-3.2.0/engram-metamemory/engram_metamemory/__init__.py +0 -19
- dhee-3.2.0/engram-metamemory/engram_metamemory/confidence.py +0 -162
- dhee-3.2.0/engram-metamemory/engram_metamemory/config.py +0 -51
- dhee-3.2.0/engram-metamemory/engram_metamemory/mcp_tools.py +0 -118
- dhee-3.2.0/engram-metamemory/engram_metamemory/metamemory.py +0 -346
- dhee-3.2.0/engram-router/engram_router/__init__.py +0 -22
- dhee-3.2.0/engram-router/engram_router/config.py +0 -15
- dhee-3.2.0/engram-router/engram_router/mcp_tools.py +0 -135
- dhee-3.2.0/engram-router/engram_router/registry.py +0 -196
- dhee-3.2.0/engram-router/engram_router/router.py +0 -310
- dhee-3.2.0/engram-warroom/engram_warroom/__init__.py +0 -18
- dhee-3.2.0/engram-warroom/engram_warroom/autopick.py +0 -99
- dhee-3.2.0/engram-warroom/engram_warroom/config.py +0 -17
- dhee-3.2.0/engram-warroom/engram_warroom/decision.py +0 -46
- dhee-3.2.0/engram-warroom/engram_warroom/failover.py +0 -120
- dhee-3.2.0/engram-warroom/engram_warroom/mcp_tools.py +0 -200
- dhee-3.2.0/engram-warroom/engram_warroom/monitor.py +0 -212
- dhee-3.2.0/engram-warroom/engram_warroom/warroom.py +0 -333
- {dhee-3.2.0 → dhee-3.3.0}/LICENSE +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/benchmarks/__init__.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/benchmarks/arc_agi.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/benchmarks/hippocamp.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/benchmarks/longmemeval.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/benchmarks/raw_extractors.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/checkpoint_runtime.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/cli_config.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/cli_mcp.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/cli_setup.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/configs/__init__.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/configs/active.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/configs/base.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/configs/presets.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/__init__.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/alaya.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/answer_orchestration.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/belief.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/buddhi.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/category.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/cognition.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/cognition_kernel.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/conflict.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/contrastive.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/decay.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/distillation.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/echo.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/engram.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/engram_extractor.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/enrichment.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/episode.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/episodic_index.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/evolution.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/forgetting.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/fusion.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/graph.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/heuristic.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/intent.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/intention.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/kernel.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/log_parser.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/meta_buddhi.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/pattern_detector.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/policy.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/profile.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/resolvers.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/retrieval.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/samskara.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/scene.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/session_tracker.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/strategy.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/task_state.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/traces.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/trigger.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/core/viveka.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/db/__init__.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/db/sqlite.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/db/sqlite_analytics.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/db/sqlite_common.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/db/sqlite_domains.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/debugger_api.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/embeddings/__init__.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/embeddings/base.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/embeddings/gemini.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/embeddings/nvidia.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/embeddings/ollama.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/embeddings/openai.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/embeddings/qwen.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/embeddings/simple.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/exceptions.py +0 -0
- {dhee-3.2.0/dhee/llms → dhee-3.3.0/dhee/hooks}/__init__.py +0 -0
- {dhee-3.2.0/dhee/utils → dhee-3.3.0/dhee/llms}/__init__.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/llms/base.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/llms/dhee.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/llms/gemini.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/llms/mock.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/llms/nvidia.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/llms/ollama.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/llms/openai.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/llms/teacher_logger.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/mcp_server.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/mcp_slim.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/memory/__init__.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/memory/base.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/memory/core.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/memory/cost.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/memory/episodic.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/memory/main.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/memory/orchestration.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/memory/parallel.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/memory/projects.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/memory/reranker.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/memory/retrieval_helpers.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/memory/scene_profile.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/memory/scoping.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/memory/search_pipeline.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/memory/smart.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/memory/tasks.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/memory/utils.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/memory/vectors.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/memory/write_pipeline.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/observability.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/plugin.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/simple.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/skills/__init__.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/skills/discovery.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/skills/executor.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/skills/hashing.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/skills/miner.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/skills/outcomes.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/skills/schema.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/skills/store.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/skills/structure.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/skills/trajectory.py +0 -0
- {dhee-3.2.0/dhee/vector_stores → dhee-3.3.0/dhee/utils}/__init__.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/utils/factory.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/utils/math.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/utils/prompts.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/utils/repo_identity.py +0 -0
- {dhee-3.2.0/engram-enterprise/engram_enterprise/api → dhee-3.3.0/dhee/vector_stores}/__init__.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/vector_stores/base.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/vector_stores/memory.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/vector_stores/sqlite_vec.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee/vector_stores/zvec_store.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee.egg-info/dependency_links.txt +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee.egg-info/entry_points.txt +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee.egg-info/requires.txt +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dheeModel/__init__.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dheeModel/client.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dheeModel/model/__init__.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dheeModel/model/dhee_model.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dheeModel/training/__init__.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dheeModel/training/data_formatter.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dheeModel/training/karma.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dheeModel/training/nididhyasana.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dheeModel/training/smrti.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dheeModel/training/train.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee_shared/__init__.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/dhee_shared/model_paths.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/engram/__init__.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/engram-bridge/demo/demo-app/demo_app_smoke.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/engram-bus/engram_bus/__init__.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/engram-bus/engram_bus/bus.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/engram-bus/engram_bus/pubsub.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/engram-bus/engram_bus/server.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/engram-bus/engram_bus/store.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/engram-bus/engram_bus/workspace.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/engram-bus/tests/test_bus.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/setup.cfg +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_accel.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_accel_benchmark.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_auto_lifecycle.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_backward_compat.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_batch.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_belief_debugger.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_cognition_evals.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_cognition_kernel.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_cognition_v3.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_core_memory.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_cosine_similarity.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_dedup.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_deferred_enrichment.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_dhee_model_paths.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_distillation.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_e2e_all_features.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_forgetting.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_hashing.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_hippocamp_benchmark.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_intent.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_locomo_plus_runner.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_log_parser.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_mcp_tools_slim.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_memory_types.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_migration.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_miner.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_openclaw.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_orchestration_core.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_parallel.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_power_packages.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_presets.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_profile.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_projects.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_query_cache.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_scene.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_session_tracker.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_simple_zero_config.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_skills.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_smart_memory.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_sqlite_connection_pool.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_sqlite_vec.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_structural.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_structured_resolution.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_tasks.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_traces.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_trajectory.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_unified_enrichment.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_vector_store_factory.py +0 -0
- {dhee-3.2.0 → dhee-3.3.0}/tests/test_zvec_store.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dhee
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.3.0
|
|
4
4
|
Summary: Cognition layer for AI agents — persistent memory, performance tracking, and insight synthesis
|
|
5
5
|
Author: Sankhya AI Labs
|
|
6
6
|
License: MIT
|
|
@@ -75,10 +75,10 @@ Requires-Dist: twine>=5.0.0; extra == "dev"
|
|
|
75
75
|
Dynamic: license-file
|
|
76
76
|
|
|
77
77
|
<p align="center">
|
|
78
|
-
<img src="docs/dhee-logo.png" alt="Dhee" width="80">
|
|
78
|
+
<img src="docs/dhee-logo.png" alt="Dhee" width="80"> <h1 align="center">Dhee</h1>
|
|
79
79
|
</p>
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
|
|
82
82
|
|
|
83
83
|
<h3 align="center">The cognition layer that turns your agent into a HyperAgent.</h3>
|
|
84
84
|
|
|
@@ -154,12 +154,42 @@ d.context("fixing auth bug")
|
|
|
154
154
|
d.checkpoint("Fixed it", what_worked="git blame first")
|
|
155
155
|
```
|
|
156
156
|
|
|
157
|
+
### Claude Code — Native Hooks (v3.3.0)
|
|
158
|
+
|
|
159
|
+
One command. Every Claude Code session becomes self-evolving.
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
dhee install
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
That's it. Dhee hooks into Claude Code's lifecycle — no CLAUDE.md bloat, no SKILL.md files, no markdown accumulation. Structured XML context injection, budgeted to ~630 tokens regardless of how much memory you have.
|
|
166
|
+
|
|
167
|
+
**What happens automatically:**
|
|
168
|
+
|
|
169
|
+
| Hook | When | What Dhee does |
|
|
170
|
+
|:-----|:-----|:---------------|
|
|
171
|
+
| `SessionStart` | Session opens | Injects last session, insights, performance trends, relevant memories |
|
|
172
|
+
| `UserPromptSubmit` | Every prompt | Surfaces memories relevant to what you just asked |
|
|
173
|
+
| `PostToolUse` | After Edit/Write/Bash | Captures what Claude did (secrets auto-stripped) |
|
|
174
|
+
| `PreCompact` | Before context compaction | Checkpoints state so nothing is lost |
|
|
175
|
+
| `Stop` | Session ends | Records outcomes — what worked, what failed, learnings |
|
|
176
|
+
|
|
177
|
+
Or start Claude Code directly with context:
|
|
178
|
+
|
|
179
|
+
```bash
|
|
180
|
+
dhee task "fix the flaky auth test"
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Why not CLAUDE.md?** Markdown files are static. After 6 months of accumulated knowledge, they rot — stale patterns sit at equal weight to current ones, no retrieval ranking, no forgetting. Dhee uses vector memory with strength-based decay. Relevant memories surface. Irrelevant ones fade. The context budget stays constant at ~630 tokens whether you have 50 memories or 50,000.
|
|
184
|
+
|
|
157
185
|
### CLI
|
|
158
186
|
|
|
159
187
|
```bash
|
|
160
188
|
dhee remember "User prefers Python"
|
|
161
189
|
dhee recall "programming language"
|
|
162
190
|
dhee checkpoint "Fixed auth bug" --what-worked "checked logs"
|
|
191
|
+
dhee install # install Claude Code hooks
|
|
192
|
+
dhee uninstall-hooks # remove them
|
|
163
193
|
```
|
|
164
194
|
|
|
165
195
|
### Docker
|
|
@@ -295,8 +325,18 @@ These are surfaced through `context()` and `checkpoint()` automatically when ena
|
|
|
295
325
|
## Architecture
|
|
296
326
|
|
|
297
327
|
```
|
|
298
|
-
|
|
328
|
+
Claude Code (or any agent)
|
|
299
329
|
│
|
|
330
|
+
├── SessionStart hook ──→ dhee.context() ──→ XML renderer ──→ system prompt injection
|
|
331
|
+
├── UserPromptSubmit ───→ dhee.recall() ──→ ranked memories ──→ per-turn context
|
|
332
|
+
├── PostToolUse ────────→ dhee.remember() ─→ privacy filter ──→ stored (0 LLM)
|
|
333
|
+
├── PreCompact ─────────→ dhee.checkpoint() + re-inject context
|
|
334
|
+
└── Stop ───────────────→ dhee.checkpoint(what_worked, what_failed, outcome_score)
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
The 4-operation API under the hooks:
|
|
338
|
+
|
|
339
|
+
```
|
|
300
340
|
├── remember(content) → Engram: embed + store (0 LLM)
|
|
301
341
|
├── recall(query) → Engram: embed + vector search (0 LLM)
|
|
302
342
|
├── context(task) → Buddhi: performance + insights + intentions + memories
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
<p align="center">
|
|
2
|
-
<img src="docs/dhee-logo.png" alt="Dhee" width="80">
|
|
2
|
+
<img src="docs/dhee-logo.png" alt="Dhee" width="80"> <h1 align="center">Dhee</h1>
|
|
3
3
|
</p>
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
|
|
7
7
|
<h3 align="center">The cognition layer that turns your agent into a HyperAgent.</h3>
|
|
8
8
|
|
|
@@ -78,12 +78,42 @@ d.context("fixing auth bug")
|
|
|
78
78
|
d.checkpoint("Fixed it", what_worked="git blame first")
|
|
79
79
|
```
|
|
80
80
|
|
|
81
|
+
### Claude Code — Native Hooks (v3.3.0)
|
|
82
|
+
|
|
83
|
+
One command. Every Claude Code session becomes self-evolving.
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
dhee install
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
That's it. Dhee hooks into Claude Code's lifecycle — no CLAUDE.md bloat, no SKILL.md files, no markdown accumulation. Structured XML context injection, budgeted to ~630 tokens regardless of how much memory you have.
|
|
90
|
+
|
|
91
|
+
**What happens automatically:**
|
|
92
|
+
|
|
93
|
+
| Hook | When | What Dhee does |
|
|
94
|
+
|:-----|:-----|:---------------|
|
|
95
|
+
| `SessionStart` | Session opens | Injects last session, insights, performance trends, relevant memories |
|
|
96
|
+
| `UserPromptSubmit` | Every prompt | Surfaces memories relevant to what you just asked |
|
|
97
|
+
| `PostToolUse` | After Edit/Write/Bash | Captures what Claude did (secrets auto-stripped) |
|
|
98
|
+
| `PreCompact` | Before context compaction | Checkpoints state so nothing is lost |
|
|
99
|
+
| `Stop` | Session ends | Records outcomes — what worked, what failed, learnings |
|
|
100
|
+
|
|
101
|
+
Or start Claude Code directly with context:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
dhee task "fix the flaky auth test"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**Why not CLAUDE.md?** Markdown files are static. After 6 months of accumulated knowledge, they rot — stale patterns sit at equal weight to current ones, no retrieval ranking, no forgetting. Dhee uses vector memory with strength-based decay. Relevant memories surface. Irrelevant ones fade. The context budget stays constant at ~630 tokens whether you have 50 memories or 50,000.
|
|
108
|
+
|
|
81
109
|
### CLI
|
|
82
110
|
|
|
83
111
|
```bash
|
|
84
112
|
dhee remember "User prefers Python"
|
|
85
113
|
dhee recall "programming language"
|
|
86
114
|
dhee checkpoint "Fixed auth bug" --what-worked "checked logs"
|
|
115
|
+
dhee install # install Claude Code hooks
|
|
116
|
+
dhee uninstall-hooks # remove them
|
|
87
117
|
```
|
|
88
118
|
|
|
89
119
|
### Docker
|
|
@@ -219,8 +249,18 @@ These are surfaced through `context()` and `checkpoint()` automatically when ena
|
|
|
219
249
|
## Architecture
|
|
220
250
|
|
|
221
251
|
```
|
|
222
|
-
|
|
252
|
+
Claude Code (or any agent)
|
|
223
253
|
│
|
|
254
|
+
├── SessionStart hook ──→ dhee.context() ──→ XML renderer ──→ system prompt injection
|
|
255
|
+
├── UserPromptSubmit ───→ dhee.recall() ──→ ranked memories ──→ per-turn context
|
|
256
|
+
├── PostToolUse ────────→ dhee.remember() ─→ privacy filter ──→ stored (0 LLM)
|
|
257
|
+
├── PreCompact ─────────→ dhee.checkpoint() + re-inject context
|
|
258
|
+
└── Stop ───────────────→ dhee.checkpoint(what_worked, what_failed, outcome_score)
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
The 4-operation API under the hooks:
|
|
262
|
+
|
|
263
|
+
```
|
|
224
264
|
├── remember(content) → Engram: embed + store (0 LLM)
|
|
225
265
|
├── recall(query) → Engram: embed + vector search (0 LLM)
|
|
226
266
|
├── context(task) → Buddhi: performance + insights + intentions + memories
|
|
@@ -318,6 +318,58 @@ def cmd_uninstall(args: argparse.Namespace) -> None:
|
|
|
318
318
|
print("Cancelled.")
|
|
319
319
|
|
|
320
320
|
|
|
321
|
+
def cmd_task(args: argparse.Namespace) -> None:
|
|
322
|
+
"""Start Claude Code with Dhee cognition hooks."""
|
|
323
|
+
from dhee.hooks.claude_code.install import ensure_installed
|
|
324
|
+
|
|
325
|
+
result = ensure_installed()
|
|
326
|
+
if result.already_installed:
|
|
327
|
+
pass # hooks already in place
|
|
328
|
+
elif result.created or result.updated:
|
|
329
|
+
print(f" Dhee hooks installed → {result.settings_path}")
|
|
330
|
+
|
|
331
|
+
# Find claude executable
|
|
332
|
+
claude_bin = shutil.which("claude")
|
|
333
|
+
if not claude_bin:
|
|
334
|
+
print("Error: 'claude' not found in PATH. Install Claude Code first.", file=sys.stderr)
|
|
335
|
+
sys.exit(1)
|
|
336
|
+
|
|
337
|
+
# Build command
|
|
338
|
+
cmd = [claude_bin]
|
|
339
|
+
if args.print_mode:
|
|
340
|
+
cmd.append("--print")
|
|
341
|
+
if args.description:
|
|
342
|
+
cmd.append(args.description)
|
|
343
|
+
|
|
344
|
+
# Replace current process with claude
|
|
345
|
+
os.execvp(claude_bin, cmd)
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
def cmd_install_hooks(args: argparse.Namespace) -> None:
|
|
349
|
+
"""Install Dhee hooks into Claude Code."""
|
|
350
|
+
from dhee.hooks.claude_code.install import install_hooks
|
|
351
|
+
|
|
352
|
+
result = install_hooks(force=args.force)
|
|
353
|
+
if result.already_installed and not args.force:
|
|
354
|
+
print(" Dhee hooks already installed.")
|
|
355
|
+
else:
|
|
356
|
+
action = "Created" if result.created else "Updated"
|
|
357
|
+
print(f" {action} {result.settings_path}")
|
|
358
|
+
print(f" Hooks: {', '.join(result.events)}")
|
|
359
|
+
if result.backed_up:
|
|
360
|
+
print(f" Backup: {result.backed_up}")
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
def cmd_uninstall_hooks(args: argparse.Namespace) -> None:
|
|
364
|
+
"""Remove Dhee hooks from Claude Code."""
|
|
365
|
+
from dhee.hooks.claude_code.install import uninstall_hooks
|
|
366
|
+
|
|
367
|
+
if uninstall_hooks():
|
|
368
|
+
print(" Dhee hooks removed.")
|
|
369
|
+
else:
|
|
370
|
+
print(" No Dhee hooks found.")
|
|
371
|
+
|
|
372
|
+
|
|
321
373
|
def cmd_benchmark(args: argparse.Namespace) -> None:
|
|
322
374
|
"""Run performance benchmarks."""
|
|
323
375
|
import time
|
|
@@ -458,6 +510,19 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
458
510
|
p_status = sub.add_parser("status", help="Show version, config, and agents")
|
|
459
511
|
p_status.add_argument("--json", action="store_true", help="JSON output")
|
|
460
512
|
|
|
513
|
+
# task
|
|
514
|
+
p_task = sub.add_parser("task", help="Start Claude Code with Dhee cognition")
|
|
515
|
+
p_task.add_argument("description", nargs="?", default="", help="Task description")
|
|
516
|
+
p_task.add_argument("--user-id", default="default", help="User ID")
|
|
517
|
+
p_task.add_argument("--print", dest="print_mode", action="store_true", help="One-shot mode")
|
|
518
|
+
|
|
519
|
+
# install (hooks)
|
|
520
|
+
p_install = sub.add_parser("install", help="Install Dhee hooks into Claude Code")
|
|
521
|
+
p_install.add_argument("--force", action="store_true", help="Overwrite existing hooks")
|
|
522
|
+
|
|
523
|
+
# uninstall-hooks
|
|
524
|
+
sub.add_parser("uninstall-hooks", help="Remove Dhee hooks from Claude Code")
|
|
525
|
+
|
|
461
526
|
# benchmark
|
|
462
527
|
sub.add_parser("benchmark", help="Run performance benchmarks")
|
|
463
528
|
|
|
@@ -481,6 +546,9 @@ COMMAND_MAP = {
|
|
|
481
546
|
"export": cmd_export,
|
|
482
547
|
"import": cmd_import,
|
|
483
548
|
"status": cmd_status,
|
|
549
|
+
"task": cmd_task,
|
|
550
|
+
"install": cmd_install_hooks,
|
|
551
|
+
"uninstall-hooks": cmd_uninstall_hooks,
|
|
484
552
|
"benchmark": cmd_benchmark,
|
|
485
553
|
"uninstall": cmd_uninstall,
|
|
486
554
|
}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
"""Dhee Claude Code hook dispatch.
|
|
2
|
+
|
|
3
|
+
Usage::
|
|
4
|
+
|
|
5
|
+
python -m dhee.hooks.claude_code <event_name>
|
|
6
|
+
|
|
7
|
+
Reads the Claude Code hook payload from stdin (JSON).
|
|
8
|
+
Writes JSON response to stdout.
|
|
9
|
+
On any error, outputs ``{}`` — never fails the host agent.
|
|
10
|
+
|
|
11
|
+
Events handled:
|
|
12
|
+
SessionStart — inject full Dhee context (session + memories + insights)
|
|
13
|
+
UserPromptSubmit — inject relevant memories for the current prompt
|
|
14
|
+
PostToolUse — capture tool outcomes into Dhee memory
|
|
15
|
+
PreCompact — checkpoint state, re-inject context to survive compaction
|
|
16
|
+
Stop / SessionEnd — checkpoint session with outcomes
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import json
|
|
22
|
+
import os
|
|
23
|
+
import sys
|
|
24
|
+
from typing import Any
|
|
25
|
+
|
|
26
|
+
_MAX_REMEMBER_CHARS = 2000
|
|
27
|
+
_MAX_QUERY_CHARS = 200
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _get_dhee():
|
|
31
|
+
from dhee import Dhee
|
|
32
|
+
|
|
33
|
+
return Dhee(
|
|
34
|
+
user_id=os.environ.get("DHEE_USER_ID", "default"),
|
|
35
|
+
auto_context=False,
|
|
36
|
+
auto_checkpoint=False,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _render(ctx: dict[str, Any], **kwargs: Any) -> str:
|
|
41
|
+
from dhee.hooks.claude_code.renderer import render_context
|
|
42
|
+
|
|
43
|
+
return render_context(ctx, **kwargs)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
# ---------------------------------------------------------------------------
|
|
47
|
+
# Handlers — each returns a dict for stdout JSON
|
|
48
|
+
# ---------------------------------------------------------------------------
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def handle_session_start(payload: dict[str, Any]) -> dict[str, Any]:
|
|
52
|
+
dhee = _get_dhee()
|
|
53
|
+
|
|
54
|
+
task_desc = (
|
|
55
|
+
payload.get("task_description")
|
|
56
|
+
or payload.get("initial_prompt")
|
|
57
|
+
or payload.get("prompt")
|
|
58
|
+
or ""
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
ctx = dhee.context(
|
|
62
|
+
task_description=task_desc or None,
|
|
63
|
+
user_id=os.environ.get("DHEE_USER_ID", "default"),
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
if not ctx:
|
|
67
|
+
return {}
|
|
68
|
+
|
|
69
|
+
has_content = (
|
|
70
|
+
ctx.get("memories")
|
|
71
|
+
or ctx.get("last_session")
|
|
72
|
+
or ctx.get("insights")
|
|
73
|
+
or ctx.get("intentions")
|
|
74
|
+
or ctx.get("performance")
|
|
75
|
+
)
|
|
76
|
+
if not has_content:
|
|
77
|
+
return {}
|
|
78
|
+
|
|
79
|
+
xml = _render(ctx, task_description=task_desc or None)
|
|
80
|
+
return {"systemMessage": xml}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def handle_user_prompt(payload: dict[str, Any]) -> dict[str, Any]:
|
|
84
|
+
if isinstance(payload, dict):
|
|
85
|
+
prompt = str(payload.get("prompt", payload.get("content", "")))
|
|
86
|
+
elif isinstance(payload, str):
|
|
87
|
+
prompt = payload
|
|
88
|
+
else:
|
|
89
|
+
prompt = str(payload)
|
|
90
|
+
|
|
91
|
+
if not prompt.strip():
|
|
92
|
+
return {}
|
|
93
|
+
|
|
94
|
+
dhee = _get_dhee()
|
|
95
|
+
results = dhee.recall(query=prompt[:_MAX_QUERY_CHARS], limit=5)
|
|
96
|
+
if not results:
|
|
97
|
+
return {}
|
|
98
|
+
|
|
99
|
+
xml = _render({"memories": results}, max_tokens=500)
|
|
100
|
+
return {"systemMessage": xml}
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def handle_post_tool(payload: dict[str, Any]) -> dict[str, Any]:
|
|
104
|
+
if not isinstance(payload, dict):
|
|
105
|
+
return {}
|
|
106
|
+
|
|
107
|
+
tool_name = payload.get("tool_name", "")
|
|
108
|
+
tool_input = payload.get("tool_input", {})
|
|
109
|
+
tool_result = payload.get("tool_result", "")
|
|
110
|
+
success = payload.get("success", True)
|
|
111
|
+
|
|
112
|
+
if not tool_name:
|
|
113
|
+
return {}
|
|
114
|
+
|
|
115
|
+
write_tools = {"Edit", "Write", "MultiEdit", "NotebookEdit"}
|
|
116
|
+
shell_tools = {"Bash", "BashOutput"}
|
|
117
|
+
if tool_name not in write_tools and tool_name not in shell_tools:
|
|
118
|
+
return {}
|
|
119
|
+
|
|
120
|
+
if tool_name in write_tools:
|
|
121
|
+
path = ""
|
|
122
|
+
if isinstance(tool_input, dict):
|
|
123
|
+
path = tool_input.get("file_path", tool_input.get("path", ""))
|
|
124
|
+
content = f"edited {path}" if path else f"used {tool_name}"
|
|
125
|
+
if not success:
|
|
126
|
+
content = f"failed to edit {path}: {str(tool_result)[:100]}"
|
|
127
|
+
else:
|
|
128
|
+
cmd = ""
|
|
129
|
+
if isinstance(tool_input, dict):
|
|
130
|
+
cmd = tool_input.get("command", "")[:150]
|
|
131
|
+
content = f"ran: {cmd}" if cmd else f"used {tool_name}"
|
|
132
|
+
if not success:
|
|
133
|
+
stderr = str(tool_result)[:200] if tool_result else "unknown error"
|
|
134
|
+
content = f"command failed: {cmd[:80]} — {stderr}"
|
|
135
|
+
|
|
136
|
+
from dhee.hooks.claude_code.privacy import filter_secrets
|
|
137
|
+
|
|
138
|
+
content = filter_secrets(content)
|
|
139
|
+
if len(content) < 10:
|
|
140
|
+
return {}
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
dhee = _get_dhee()
|
|
144
|
+
dhee.remember(
|
|
145
|
+
content=content[:_MAX_REMEMBER_CHARS],
|
|
146
|
+
metadata={"source": "claude_code_hook", "tool": tool_name, "success": success},
|
|
147
|
+
)
|
|
148
|
+
except Exception:
|
|
149
|
+
pass
|
|
150
|
+
|
|
151
|
+
return {}
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
def handle_pre_compact(payload: dict[str, Any]) -> dict[str, Any]:
|
|
155
|
+
dhee = _get_dhee()
|
|
156
|
+
|
|
157
|
+
summary = "session compacted"
|
|
158
|
+
if isinstance(payload, dict):
|
|
159
|
+
summary = payload.get("summary", summary)
|
|
160
|
+
|
|
161
|
+
try:
|
|
162
|
+
dhee.checkpoint(summary=summary, status="compacted")
|
|
163
|
+
except Exception:
|
|
164
|
+
pass
|
|
165
|
+
|
|
166
|
+
ctx = dhee.context(user_id=os.environ.get("DHEE_USER_ID", "default"))
|
|
167
|
+
if not ctx:
|
|
168
|
+
return {}
|
|
169
|
+
xml = _render(ctx)
|
|
170
|
+
return {"systemMessage": xml}
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def handle_stop(payload: dict[str, Any]) -> dict[str, Any]:
|
|
174
|
+
dhee = _get_dhee()
|
|
175
|
+
|
|
176
|
+
summary = "session ended"
|
|
177
|
+
task_type = None
|
|
178
|
+
outcome_score = None
|
|
179
|
+
what_worked = None
|
|
180
|
+
what_failed = None
|
|
181
|
+
|
|
182
|
+
if isinstance(payload, dict):
|
|
183
|
+
summary = payload.get("summary", payload.get("task_description", summary))
|
|
184
|
+
task_type = payload.get("task_type")
|
|
185
|
+
if payload.get("outcome_score") is not None:
|
|
186
|
+
try:
|
|
187
|
+
outcome_score = float(payload["outcome_score"])
|
|
188
|
+
except (TypeError, ValueError):
|
|
189
|
+
pass
|
|
190
|
+
what_worked = payload.get("what_worked")
|
|
191
|
+
what_failed = payload.get("what_failed")
|
|
192
|
+
|
|
193
|
+
try:
|
|
194
|
+
dhee.checkpoint(
|
|
195
|
+
summary=summary,
|
|
196
|
+
task_type=task_type,
|
|
197
|
+
outcome_score=outcome_score,
|
|
198
|
+
what_worked=what_worked,
|
|
199
|
+
what_failed=what_failed,
|
|
200
|
+
status="completed",
|
|
201
|
+
repo=os.getcwd(),
|
|
202
|
+
)
|
|
203
|
+
except Exception:
|
|
204
|
+
pass
|
|
205
|
+
|
|
206
|
+
return {}
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
# ---------------------------------------------------------------------------
|
|
210
|
+
# Dispatch
|
|
211
|
+
# ---------------------------------------------------------------------------
|
|
212
|
+
|
|
213
|
+
_HANDLERS = {
|
|
214
|
+
"SessionStart": handle_session_start,
|
|
215
|
+
"UserPromptSubmit": handle_user_prompt,
|
|
216
|
+
"PostToolUse": handle_post_tool,
|
|
217
|
+
"PreCompact": handle_pre_compact,
|
|
218
|
+
"Stop": handle_stop,
|
|
219
|
+
"SessionEnd": handle_stop,
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def main() -> int:
|
|
224
|
+
if len(sys.argv) < 2:
|
|
225
|
+
sys.stderr.write("usage: python -m dhee.hooks.claude_code <event>\n")
|
|
226
|
+
sys.stdout.write("{}\n")
|
|
227
|
+
return 1
|
|
228
|
+
|
|
229
|
+
event = sys.argv[1]
|
|
230
|
+
handler = _HANDLERS.get(event)
|
|
231
|
+
if not handler:
|
|
232
|
+
sys.stdout.write("{}\n")
|
|
233
|
+
return 0
|
|
234
|
+
|
|
235
|
+
try:
|
|
236
|
+
raw = sys.stdin.read() or "{}"
|
|
237
|
+
except Exception:
|
|
238
|
+
raw = "{}"
|
|
239
|
+
|
|
240
|
+
try:
|
|
241
|
+
payload = json.loads(raw)
|
|
242
|
+
except json.JSONDecodeError:
|
|
243
|
+
payload = {"prompt": raw, "raw": raw}
|
|
244
|
+
|
|
245
|
+
try:
|
|
246
|
+
result = handler(payload)
|
|
247
|
+
sys.stdout.write(json.dumps(result or {}) + "\n")
|
|
248
|
+
except Exception as exc:
|
|
249
|
+
sys.stderr.write(f"dhee hook {event}: {exc}\n")
|
|
250
|
+
sys.stdout.write("{}\n")
|
|
251
|
+
|
|
252
|
+
return 0
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
if __name__ == "__main__":
|
|
256
|
+
raise SystemExit(main())
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
"""Install Dhee hooks into Claude Code settings.
|
|
2
|
+
|
|
3
|
+
Writes hook entries into ``~/.claude/settings.json`` so that every Claude Code
|
|
4
|
+
session automatically gets Dhee cognition: memory injection on start, learning
|
|
5
|
+
on tool use, checkpoint on exit. No markdown files, no SKILL.md, no plugins
|
|
6
|
+
directory — just Python hooks in the agent's native lifecycle.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import json
|
|
12
|
+
import shutil
|
|
13
|
+
import sys
|
|
14
|
+
from dataclasses import dataclass, field
|
|
15
|
+
from pathlib import Path
|
|
16
|
+
from typing import Any
|
|
17
|
+
|
|
18
|
+
HOOK_EVENTS: tuple[str, ...] = (
|
|
19
|
+
"SessionStart",
|
|
20
|
+
"UserPromptSubmit",
|
|
21
|
+
"PostToolUse",
|
|
22
|
+
"PreCompact",
|
|
23
|
+
"Stop",
|
|
24
|
+
"SessionEnd",
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
TOOL_MATCHERS: dict[str, str] = {
|
|
28
|
+
"PostToolUse": "Edit|Write|MultiEdit|Bash",
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class InstallResult:
|
|
34
|
+
settings_path: Path
|
|
35
|
+
events: tuple[str, ...]
|
|
36
|
+
created: bool = False
|
|
37
|
+
updated: bool = False
|
|
38
|
+
already_installed: bool = False
|
|
39
|
+
backed_up: Path | None = None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _settings_path() -> Path:
|
|
43
|
+
return Path.home() / ".claude" / "settings.json"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _python_cmd() -> str:
|
|
47
|
+
return sys.executable or "python3"
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _build_entry(event: str) -> dict[str, Any]:
|
|
51
|
+
cmd = f"{_python_cmd()} -m dhee.hooks.claude_code {event}"
|
|
52
|
+
entry: dict[str, Any] = {
|
|
53
|
+
"hooks": [{"type": "command", "command": cmd, "timeout": 10}],
|
|
54
|
+
}
|
|
55
|
+
if event in TOOL_MATCHERS:
|
|
56
|
+
entry["matcher"] = TOOL_MATCHERS[event]
|
|
57
|
+
return entry
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _has_dhee_hook(entries: list[dict[str, Any]]) -> bool:
|
|
61
|
+
for entry in entries:
|
|
62
|
+
for hook in entry.get("hooks", []):
|
|
63
|
+
if "dhee.hooks.claude_code" in hook.get("command", ""):
|
|
64
|
+
return True
|
|
65
|
+
return False
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _all_installed(hooks: dict[str, Any], events: tuple[str, ...]) -> bool:
|
|
69
|
+
for event in events:
|
|
70
|
+
entries = hooks.get(event, [])
|
|
71
|
+
if not isinstance(entries, list) or not _has_dhee_hook(entries):
|
|
72
|
+
return False
|
|
73
|
+
return True
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def install_hooks(
|
|
77
|
+
*,
|
|
78
|
+
force: bool = False,
|
|
79
|
+
events: tuple[str, ...] = HOOK_EVENTS,
|
|
80
|
+
) -> InstallResult:
|
|
81
|
+
"""Install Dhee hooks into ``~/.claude/settings.json``."""
|
|
82
|
+
path = _settings_path()
|
|
83
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
84
|
+
|
|
85
|
+
settings: dict[str, Any] = {}
|
|
86
|
+
if path.exists():
|
|
87
|
+
try:
|
|
88
|
+
settings = json.loads(path.read_text(encoding="utf-8"))
|
|
89
|
+
except (json.JSONDecodeError, Exception):
|
|
90
|
+
settings = {}
|
|
91
|
+
|
|
92
|
+
existing_hooks = settings.get("hooks", {})
|
|
93
|
+
|
|
94
|
+
if not force and _all_installed(existing_hooks, events):
|
|
95
|
+
return InstallResult(
|
|
96
|
+
settings_path=path,
|
|
97
|
+
events=events,
|
|
98
|
+
already_installed=True,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
backed_up = None
|
|
102
|
+
if path.exists():
|
|
103
|
+
backup = path.with_suffix(".json.dhee-backup")
|
|
104
|
+
shutil.copy2(path, backup)
|
|
105
|
+
backed_up = backup
|
|
106
|
+
|
|
107
|
+
hooks = dict(existing_hooks)
|
|
108
|
+
for event in events:
|
|
109
|
+
our_entry = _build_entry(event)
|
|
110
|
+
if event in hooks and not force:
|
|
111
|
+
existing = hooks[event]
|
|
112
|
+
if isinstance(existing, list) and _has_dhee_hook(existing):
|
|
113
|
+
continue
|
|
114
|
+
if isinstance(existing, list):
|
|
115
|
+
existing.append(our_entry)
|
|
116
|
+
else:
|
|
117
|
+
hooks[event] = [our_entry]
|
|
118
|
+
else:
|
|
119
|
+
hooks[event] = [our_entry]
|
|
120
|
+
|
|
121
|
+
settings["hooks"] = hooks
|
|
122
|
+
|
|
123
|
+
created = not path.exists()
|
|
124
|
+
path.write_text(json.dumps(settings, indent=2) + "\n", encoding="utf-8")
|
|
125
|
+
|
|
126
|
+
return InstallResult(
|
|
127
|
+
settings_path=path,
|
|
128
|
+
events=events,
|
|
129
|
+
created=created,
|
|
130
|
+
updated=not created,
|
|
131
|
+
backed_up=backed_up,
|
|
132
|
+
)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def ensure_installed() -> InstallResult:
|
|
136
|
+
"""Install hooks if not already present."""
|
|
137
|
+
return install_hooks()
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def uninstall_hooks() -> bool:
|
|
141
|
+
"""Remove Dhee hooks from settings.json."""
|
|
142
|
+
path = _settings_path()
|
|
143
|
+
if not path.exists():
|
|
144
|
+
return False
|
|
145
|
+
|
|
146
|
+
try:
|
|
147
|
+
settings = json.loads(path.read_text(encoding="utf-8"))
|
|
148
|
+
except Exception:
|
|
149
|
+
return False
|
|
150
|
+
|
|
151
|
+
hooks = settings.get("hooks", {})
|
|
152
|
+
changed = False
|
|
153
|
+
|
|
154
|
+
for event in list(hooks.keys()):
|
|
155
|
+
entries = hooks[event]
|
|
156
|
+
if not isinstance(entries, list):
|
|
157
|
+
continue
|
|
158
|
+
filtered = [
|
|
159
|
+
e for e in entries
|
|
160
|
+
if not any("dhee.hooks.claude_code" in h.get("command", "") for h in e.get("hooks", []))
|
|
161
|
+
]
|
|
162
|
+
if len(filtered) != len(entries):
|
|
163
|
+
changed = True
|
|
164
|
+
if filtered:
|
|
165
|
+
hooks[event] = filtered
|
|
166
|
+
else:
|
|
167
|
+
del hooks[event]
|
|
168
|
+
|
|
169
|
+
if changed:
|
|
170
|
+
settings["hooks"] = hooks
|
|
171
|
+
path.write_text(json.dumps(settings, indent=2) + "\n", encoding="utf-8")
|
|
172
|
+
|
|
173
|
+
return changed
|