htmlgraph 0.25.0__py3-none-any.whl → 0.26.2__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.
Files changed (41) hide show
  1. htmlgraph/.htmlgraph/.session-warning-state.json +6 -0
  2. htmlgraph/.htmlgraph/agents.json +72 -0
  3. htmlgraph/.htmlgraph/htmlgraph.db +0 -0
  4. htmlgraph/__init__.py +1 -1
  5. htmlgraph/api/main.py +252 -47
  6. htmlgraph/api/templates/dashboard.html +11 -0
  7. htmlgraph/api/templates/partials/activity-feed.html +517 -8
  8. htmlgraph/cli.py +1 -1
  9. htmlgraph/config.py +173 -96
  10. htmlgraph/dashboard.html +632 -7237
  11. htmlgraph/db/schema.py +258 -9
  12. htmlgraph/hooks/.htmlgraph/.session-warning-state.json +6 -0
  13. htmlgraph/hooks/.htmlgraph/agents.json +72 -0
  14. htmlgraph/hooks/.htmlgraph/index.sqlite +0 -0
  15. htmlgraph/hooks/cigs_pretool_enforcer.py +2 -2
  16. htmlgraph/hooks/concurrent_sessions.py +208 -0
  17. htmlgraph/hooks/context.py +88 -10
  18. htmlgraph/hooks/drift_handler.py +24 -20
  19. htmlgraph/hooks/event_tracker.py +264 -189
  20. htmlgraph/hooks/orchestrator.py +6 -4
  21. htmlgraph/hooks/orchestrator_reflector.py +4 -4
  22. htmlgraph/hooks/pretooluse.py +63 -36
  23. htmlgraph/hooks/prompt_analyzer.py +14 -25
  24. htmlgraph/hooks/session_handler.py +123 -69
  25. htmlgraph/hooks/state_manager.py +7 -4
  26. htmlgraph/hooks/subagent_stop.py +3 -2
  27. htmlgraph/hooks/validator.py +15 -11
  28. htmlgraph/operations/fastapi_server.py +2 -2
  29. htmlgraph/orchestration/headless_spawner.py +489 -16
  30. htmlgraph/orchestration/live_events.py +377 -0
  31. htmlgraph/server.py +100 -203
  32. htmlgraph-0.26.2.data/data/htmlgraph/dashboard.html +812 -0
  33. {htmlgraph-0.25.0.dist-info → htmlgraph-0.26.2.dist-info}/METADATA +1 -1
  34. {htmlgraph-0.25.0.dist-info → htmlgraph-0.26.2.dist-info}/RECORD +40 -32
  35. htmlgraph-0.25.0.data/data/htmlgraph/dashboard.html +0 -7417
  36. {htmlgraph-0.25.0.data → htmlgraph-0.26.2.data}/data/htmlgraph/styles.css +0 -0
  37. {htmlgraph-0.25.0.data → htmlgraph-0.26.2.data}/data/htmlgraph/templates/AGENTS.md.template +0 -0
  38. {htmlgraph-0.25.0.data → htmlgraph-0.26.2.data}/data/htmlgraph/templates/CLAUDE.md.template +0 -0
  39. {htmlgraph-0.25.0.data → htmlgraph-0.26.2.data}/data/htmlgraph/templates/GEMINI.md.template +0 -0
  40. {htmlgraph-0.25.0.dist-info → htmlgraph-0.26.2.dist-info}/WHEEL +0 -0
  41. {htmlgraph-0.25.0.dist-info → htmlgraph-0.26.2.dist-info}/entry_points.txt +0 -0
htmlgraph/config.py CHANGED
@@ -3,111 +3,188 @@ HtmlGraph Configuration Management.
3
3
 
4
4
  This module provides centralized configuration management using Pydantic Settings,
5
5
  allowing configuration from environment variables, .env files, and CLI arguments.
6
+
7
+ IMPORTANT: Database path functions (get_database_path, get_analytics_cache_path)
8
+ are lightweight and have NO dependencies. They can be imported anywhere.
6
9
  """
7
10
 
11
+ import os
8
12
  from pathlib import Path
9
13
  from typing import Any
10
14
 
11
- from pydantic_settings import BaseSettings
15
+ # =============================================================================
16
+ # LIGHTWEIGHT DATABASE PATH FUNCTIONS (NO DEPENDENCIES)
17
+ # These MUST come before any heavy imports so spawners can use them
18
+ # =============================================================================
12
19
 
20
+ # Database filenames (SINGLE SOURCE OF TRUTH)
21
+ DATABASE_FILENAME = "htmlgraph.db" # Unified event database
22
+ ANALYTICS_CACHE_FILENAME = "index.sqlite" # Analytics cache (rebuildable)
13
23
 
14
- class HtmlGraphConfig(BaseSettings):
15
- """Global HtmlGraph configuration using Pydantic Settings.
16
24
 
17
- Configuration can be provided via:
18
- 1. Environment variables (prefix: HTMLGRAPH_)
19
- 2. .env file
20
- 3. Direct instantiation with parameters
21
- 4. CLI argument overrides
25
+ def get_database_path(project_root: Path | str | None = None) -> Path:
22
26
  """
27
+ Get the unified database path for event tracking.
28
+
29
+ This is the SINGLE source of truth for database location.
30
+ All hooks, agents, and spawners MUST use this function.
31
+
32
+ Args:
33
+ project_root: Optional project root path. If None, uses HTMLGRAPH_PROJECT_ROOT
34
+ env var or current working directory.
35
+
36
+ Returns:
37
+ Path to htmlgraph.db (the unified event database)
38
+ """
39
+ if project_root is None:
40
+ project_root = Path(os.environ.get("HTMLGRAPH_PROJECT_ROOT", os.getcwd()))
41
+ else:
42
+ project_root = Path(project_root)
43
+
44
+ return project_root / ".htmlgraph" / DATABASE_FILENAME
23
45
 
24
- # Core paths
25
- graph_dir: Path = Path.home() / ".htmlgraph"
26
-
27
- # Feature tracking
28
- features_dir: Path | None = None
29
- sessions_dir: Path | None = None
30
- spikes_dir: Path | None = None
31
- tracks_dir: Path | None = None
32
- archives_dir: Path | None = None
33
-
34
- # CLI behavior
35
- debug: bool = False
36
- verbose: bool = False
37
- auto_sync: bool = True
38
- color_output: bool = True
39
-
40
- # Session management
41
- max_sessions: int = 100
42
- session_retention_days: int = 30
43
- auto_archive_sessions: bool = True
44
-
45
- # Performance
46
- max_query_results: int = 1000
47
- cache_enabled: bool = True
48
- cache_ttl_seconds: int = 3600
49
-
50
- # Logging
51
- log_level: str = "INFO"
52
- log_file: Path | None = None
53
-
54
- model_config = {
55
- "env_prefix": "HTMLGRAPH_",
56
- "env_file": ".env",
57
- "case_sensitive": False,
58
- }
59
-
60
- def __init__(self, **data: Any) -> None:
61
- """Initialize config and compute derived paths."""
62
- super().__init__(**data)
63
- # Compute derived paths if not explicitly set
64
- if self.features_dir is None:
65
- self.features_dir = self.graph_dir / "features"
66
- if self.sessions_dir is None:
67
- self.sessions_dir = self.graph_dir / "sessions"
68
- if self.spikes_dir is None:
69
- self.spikes_dir = self.graph_dir / "spikes"
70
- if self.tracks_dir is None:
71
- self.tracks_dir = self.graph_dir / "tracks"
72
- if self.archives_dir is None:
73
- self.archives_dir = self.graph_dir / "archives"
74
-
75
- def ensure_directories(self) -> None:
76
- """Create all configured directories if they don't exist."""
77
- for directory in [
78
- self.graph_dir,
79
- self.features_dir,
80
- self.sessions_dir,
81
- self.spikes_dir,
82
- self.tracks_dir,
83
- self.archives_dir,
84
- ]:
85
- if directory:
86
- directory.mkdir(parents=True, exist_ok=True)
87
-
88
- def get_config_dict(self) -> dict[str, Any]:
89
- """Get configuration as dictionary."""
90
- return {
91
- "graph_dir": str(self.graph_dir),
92
- "features_dir": str(self.features_dir),
93
- "sessions_dir": str(self.sessions_dir),
94
- "spikes_dir": str(self.spikes_dir),
95
- "tracks_dir": str(self.tracks_dir),
96
- "archives_dir": str(self.archives_dir),
97
- "debug": self.debug,
98
- "verbose": self.verbose,
99
- "auto_sync": self.auto_sync,
100
- "color_output": self.color_output,
101
- "max_sessions": self.max_sessions,
102
- "session_retention_days": self.session_retention_days,
103
- "auto_archive_sessions": self.auto_archive_sessions,
104
- "max_query_results": self.max_query_results,
105
- "cache_enabled": self.cache_enabled,
106
- "cache_ttl_seconds": self.cache_ttl_seconds,
107
- "log_level": self.log_level,
108
- "log_file": str(self.log_file) if self.log_file else None,
109
- }
110
46
 
47
+ def get_analytics_cache_path(project_root: Path | str | None = None) -> Path:
48
+ """
49
+ Get the analytics cache database path.
50
+
51
+ This is for read-only analytics queries (rebuildable from events).
52
+ NOT for event tracking - use get_database_path() for that.
53
+
54
+ Args:
55
+ project_root: Optional project root path. If None, uses HTMLGRAPH_PROJECT_ROOT
56
+ env var or current working directory.
57
+
58
+ Returns:
59
+ Path to index.sqlite (analytics cache, gitignored)
60
+ """
61
+ if project_root is None:
62
+ project_root = Path(os.environ.get("HTMLGRAPH_PROJECT_ROOT", os.getcwd()))
63
+ else:
64
+ project_root = Path(project_root)
65
+
66
+ return project_root / ".htmlgraph" / ANALYTICS_CACHE_FILENAME
67
+
68
+
69
+ # =============================================================================
70
+ # PYDANTIC CONFIGURATION (Heavy imports below - spawners don't need this)
71
+ # =============================================================================
72
+
73
+ try:
74
+ from pydantic_settings import BaseSettings
75
+
76
+ _PYDANTIC_AVAILABLE = True
77
+ except ImportError:
78
+ _PYDANTIC_AVAILABLE = False
79
+ BaseSettings = object # type: ignore
80
+
81
+
82
+ if _PYDANTIC_AVAILABLE:
83
+
84
+ class HtmlGraphConfig(BaseSettings):
85
+ """Global HtmlGraph configuration using Pydantic Settings.
86
+
87
+ Configuration can be provided via:
88
+ 1. Environment variables (prefix: HTMLGRAPH_)
89
+ 2. .env file
90
+ 3. Direct instantiation with parameters
91
+ 4. CLI argument overrides
92
+ """
93
+
94
+ # Core paths
95
+ graph_dir: Path = Path.home() / ".htmlgraph"
96
+
97
+ # Database paths (SINGLE SOURCE OF TRUTH)
98
+ # All hooks, agents, and spawners MUST use these via get_database_path()
99
+ database_filename: str = "htmlgraph.db" # Unified event database
100
+ analytics_cache_filename: str = "index.sqlite" # Analytics cache (rebuildable)
101
+
102
+ # Feature tracking
103
+ features_dir: Path | None = None
104
+ sessions_dir: Path | None = None
105
+ spikes_dir: Path | None = None
106
+ tracks_dir: Path | None = None
107
+ archives_dir: Path | None = None
108
+
109
+ # CLI behavior
110
+ debug: bool = False
111
+ verbose: bool = False
112
+ auto_sync: bool = True
113
+ color_output: bool = True
114
+
115
+ # Session management
116
+ max_sessions: int = 100
117
+ session_retention_days: int = 30
118
+ auto_archive_sessions: bool = True
119
+
120
+ # Performance
121
+ max_query_results: int = 1000
122
+ cache_enabled: bool = True
123
+ cache_ttl_seconds: int = 3600
124
+
125
+ # Logging
126
+ log_level: str = "INFO"
127
+ log_file: Path | None = None
128
+
129
+ model_config = {
130
+ "env_prefix": "HTMLGRAPH_",
131
+ "env_file": ".env",
132
+ "case_sensitive": False,
133
+ }
111
134
 
112
- # Global configuration instance
113
- config: HtmlGraphConfig = HtmlGraphConfig()
135
+ def __init__(self, **data: Any) -> None:
136
+ """Initialize config and compute derived paths."""
137
+ super().__init__(**data)
138
+ # Compute derived paths if not explicitly set
139
+ if self.features_dir is None:
140
+ self.features_dir = self.graph_dir / "features"
141
+ if self.sessions_dir is None:
142
+ self.sessions_dir = self.graph_dir / "sessions"
143
+ if self.spikes_dir is None:
144
+ self.spikes_dir = self.graph_dir / "spikes"
145
+ if self.tracks_dir is None:
146
+ self.tracks_dir = self.graph_dir / "tracks"
147
+ if self.archives_dir is None:
148
+ self.archives_dir = self.graph_dir / "archives"
149
+
150
+ def ensure_directories(self) -> None:
151
+ """Create all configured directories if they don't exist."""
152
+ for directory in [
153
+ self.graph_dir,
154
+ self.features_dir,
155
+ self.sessions_dir,
156
+ self.spikes_dir,
157
+ self.tracks_dir,
158
+ self.archives_dir,
159
+ ]:
160
+ if directory:
161
+ directory.mkdir(parents=True, exist_ok=True)
162
+
163
+ def get_config_dict(self) -> dict[str, Any]:
164
+ """Get configuration as dictionary."""
165
+ return {
166
+ "graph_dir": str(self.graph_dir),
167
+ "features_dir": str(self.features_dir),
168
+ "sessions_dir": str(self.sessions_dir),
169
+ "spikes_dir": str(self.spikes_dir),
170
+ "tracks_dir": str(self.tracks_dir),
171
+ "archives_dir": str(self.archives_dir),
172
+ "debug": self.debug,
173
+ "verbose": self.verbose,
174
+ "auto_sync": self.auto_sync,
175
+ "color_output": self.color_output,
176
+ "max_sessions": self.max_sessions,
177
+ "session_retention_days": self.session_retention_days,
178
+ "auto_archive_sessions": self.auto_archive_sessions,
179
+ "max_query_results": self.max_query_results,
180
+ "cache_enabled": self.cache_enabled,
181
+ "cache_ttl_seconds": self.cache_ttl_seconds,
182
+ "log_level": self.log_level,
183
+ "log_file": str(self.log_file) if self.log_file else None,
184
+ }
185
+
186
+ # Global configuration instance
187
+ config: HtmlGraphConfig = HtmlGraphConfig()
188
+ else:
189
+ # Pydantic not available - config object won't work but database functions will
190
+ config = None # type: ignore