htmlgraph 0.24.2__py3-none-any.whl → 0.26.1__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 (112) hide show
  1. htmlgraph/__init__.py +20 -1
  2. htmlgraph/agent_detection.py +26 -10
  3. htmlgraph/analytics/cross_session.py +4 -3
  4. htmlgraph/analytics/work_type.py +52 -16
  5. htmlgraph/analytics_index.py +51 -19
  6. htmlgraph/api/__init__.py +3 -0
  7. htmlgraph/api/main.py +2263 -0
  8. htmlgraph/api/static/htmx.min.js +1 -0
  9. htmlgraph/api/static/style-redesign.css +1344 -0
  10. htmlgraph/api/static/style.css +1079 -0
  11. htmlgraph/api/templates/dashboard-redesign.html +812 -0
  12. htmlgraph/api/templates/dashboard.html +794 -0
  13. htmlgraph/api/templates/partials/activity-feed-hierarchical.html +326 -0
  14. htmlgraph/api/templates/partials/activity-feed.html +1020 -0
  15. htmlgraph/api/templates/partials/agents-redesign.html +317 -0
  16. htmlgraph/api/templates/partials/agents.html +317 -0
  17. htmlgraph/api/templates/partials/event-traces.html +373 -0
  18. htmlgraph/api/templates/partials/features-kanban-redesign.html +509 -0
  19. htmlgraph/api/templates/partials/features.html +509 -0
  20. htmlgraph/api/templates/partials/metrics-redesign.html +346 -0
  21. htmlgraph/api/templates/partials/metrics.html +346 -0
  22. htmlgraph/api/templates/partials/orchestration-redesign.html +443 -0
  23. htmlgraph/api/templates/partials/orchestration.html +163 -0
  24. htmlgraph/api/templates/partials/spawners.html +375 -0
  25. htmlgraph/atomic_ops.py +560 -0
  26. htmlgraph/builders/base.py +55 -1
  27. htmlgraph/builders/bug.py +17 -2
  28. htmlgraph/builders/chore.py +17 -2
  29. htmlgraph/builders/epic.py +17 -2
  30. htmlgraph/builders/feature.py +25 -2
  31. htmlgraph/builders/phase.py +17 -2
  32. htmlgraph/builders/spike.py +27 -2
  33. htmlgraph/builders/track.py +14 -0
  34. htmlgraph/cigs/__init__.py +4 -0
  35. htmlgraph/cigs/reporter.py +818 -0
  36. htmlgraph/cli.py +1427 -401
  37. htmlgraph/cli_commands/__init__.py +1 -0
  38. htmlgraph/cli_commands/feature.py +195 -0
  39. htmlgraph/cli_framework.py +115 -0
  40. htmlgraph/collections/__init__.py +2 -0
  41. htmlgraph/collections/base.py +21 -0
  42. htmlgraph/collections/session.py +189 -0
  43. htmlgraph/collections/spike.py +7 -1
  44. htmlgraph/collections/task_delegation.py +236 -0
  45. htmlgraph/collections/traces.py +482 -0
  46. htmlgraph/config.py +113 -0
  47. htmlgraph/converter.py +41 -0
  48. htmlgraph/cost_analysis/__init__.py +5 -0
  49. htmlgraph/cost_analysis/analyzer.py +438 -0
  50. htmlgraph/dashboard.html +3356 -492
  51. htmlgraph-0.24.2.data/data/htmlgraph/dashboard.html → htmlgraph/dashboard.html.backup +2246 -248
  52. htmlgraph/dashboard.html.bak +7181 -0
  53. htmlgraph/dashboard.html.bak2 +7231 -0
  54. htmlgraph/dashboard.html.bak3 +7232 -0
  55. htmlgraph/db/__init__.py +38 -0
  56. htmlgraph/db/queries.py +790 -0
  57. htmlgraph/db/schema.py +1584 -0
  58. htmlgraph/deploy.py +26 -27
  59. htmlgraph/docs/API_REFERENCE.md +841 -0
  60. htmlgraph/docs/HTTP_API.md +750 -0
  61. htmlgraph/docs/INTEGRATION_GUIDE.md +752 -0
  62. htmlgraph/docs/ORCHESTRATION_PATTERNS.md +710 -0
  63. htmlgraph/docs/README.md +533 -0
  64. htmlgraph/docs/version_check.py +3 -1
  65. htmlgraph/error_handler.py +544 -0
  66. htmlgraph/event_log.py +2 -0
  67. htmlgraph/hooks/.htmlgraph/.session-warning-state.json +6 -0
  68. htmlgraph/hooks/.htmlgraph/agents.json +72 -0
  69. htmlgraph/hooks/.htmlgraph/index.sqlite +0 -0
  70. htmlgraph/hooks/__init__.py +8 -0
  71. htmlgraph/hooks/bootstrap.py +169 -0
  72. htmlgraph/hooks/cigs_pretool_enforcer.py +2 -2
  73. htmlgraph/hooks/concurrent_sessions.py +208 -0
  74. htmlgraph/hooks/context.py +318 -0
  75. htmlgraph/hooks/drift_handler.py +525 -0
  76. htmlgraph/hooks/event_tracker.py +496 -79
  77. htmlgraph/hooks/orchestrator.py +6 -4
  78. htmlgraph/hooks/orchestrator_reflector.py +4 -4
  79. htmlgraph/hooks/post_tool_use_handler.py +257 -0
  80. htmlgraph/hooks/pretooluse.py +473 -6
  81. htmlgraph/hooks/prompt_analyzer.py +637 -0
  82. htmlgraph/hooks/session_handler.py +637 -0
  83. htmlgraph/hooks/state_manager.py +504 -0
  84. htmlgraph/hooks/subagent_stop.py +309 -0
  85. htmlgraph/hooks/task_enforcer.py +39 -0
  86. htmlgraph/hooks/validator.py +15 -11
  87. htmlgraph/models.py +111 -15
  88. htmlgraph/operations/fastapi_server.py +230 -0
  89. htmlgraph/orchestration/headless_spawner.py +344 -29
  90. htmlgraph/orchestration/live_events.py +377 -0
  91. htmlgraph/pydantic_models.py +476 -0
  92. htmlgraph/quality_gates.py +350 -0
  93. htmlgraph/repo_hash.py +511 -0
  94. htmlgraph/sdk.py +348 -10
  95. htmlgraph/server.py +194 -0
  96. htmlgraph/session_hooks.py +300 -0
  97. htmlgraph/session_manager.py +131 -1
  98. htmlgraph/session_registry.py +587 -0
  99. htmlgraph/session_state.py +436 -0
  100. htmlgraph/system_prompts.py +449 -0
  101. htmlgraph/templates/orchestration-view.html +350 -0
  102. htmlgraph/track_builder.py +19 -0
  103. htmlgraph/validation.py +115 -0
  104. htmlgraph-0.26.1.data/data/htmlgraph/dashboard.html +7458 -0
  105. {htmlgraph-0.24.2.dist-info → htmlgraph-0.26.1.dist-info}/METADATA +91 -64
  106. {htmlgraph-0.24.2.dist-info → htmlgraph-0.26.1.dist-info}/RECORD +112 -46
  107. {htmlgraph-0.24.2.data → htmlgraph-0.26.1.data}/data/htmlgraph/styles.css +0 -0
  108. {htmlgraph-0.24.2.data → htmlgraph-0.26.1.data}/data/htmlgraph/templates/AGENTS.md.template +0 -0
  109. {htmlgraph-0.24.2.data → htmlgraph-0.26.1.data}/data/htmlgraph/templates/CLAUDE.md.template +0 -0
  110. {htmlgraph-0.24.2.data → htmlgraph-0.26.1.data}/data/htmlgraph/templates/GEMINI.md.template +0 -0
  111. {htmlgraph-0.24.2.dist-info → htmlgraph-0.26.1.dist-info}/WHEEL +0 -0
  112. {htmlgraph-0.24.2.dist-info → htmlgraph-0.26.1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,230 @@
1
+ """FastAPI-based server for HtmlGraph dashboard with real-time observability."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import logging
6
+ from dataclasses import dataclass
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ from htmlgraph.mcp_server import _resolve_project_dir
11
+
12
+ logger = logging.getLogger(__name__)
13
+
14
+
15
+ @dataclass(frozen=True)
16
+ class FastAPIServerHandle:
17
+ """Handle to a running FastAPI server."""
18
+
19
+ url: str
20
+ port: int
21
+ host: str
22
+ server: Any | None = None
23
+
24
+
25
+ @dataclass(frozen=True)
26
+ class FastAPIServerStartResult:
27
+ """Result of starting FastAPI server."""
28
+
29
+ handle: FastAPIServerHandle
30
+ warnings: list[str]
31
+ config_used: dict[str, Any]
32
+
33
+
34
+ class FastAPIServerError(RuntimeError):
35
+ """FastAPI server error."""
36
+
37
+ pass
38
+
39
+
40
+ class PortInUseError(FastAPIServerError):
41
+ """Requested port is already in use."""
42
+
43
+ pass
44
+
45
+
46
+ def start_fastapi_server(
47
+ *,
48
+ port: int = 8000,
49
+ host: str = "127.0.0.1",
50
+ db_path: str | None = None,
51
+ auto_port: bool = False,
52
+ reload: bool = False,
53
+ ) -> FastAPIServerStartResult:
54
+ """
55
+ Start FastAPI-based HtmlGraph dashboard server.
56
+
57
+ Args:
58
+ port: Port to listen on (default: 8000)
59
+ host: Host to bind to (default: 127.0.0.1)
60
+ db_path: Path to SQLite database file
61
+ auto_port: Automatically find available port if in use
62
+ reload: Enable auto-reload on file changes (development mode)
63
+
64
+ Returns:
65
+ FastAPIServerStartResult with handle, warnings, and config used
66
+
67
+ Raises:
68
+ PortInUseError: If port is in use and auto_port=False
69
+ FastAPIServerError: If server fails to start
70
+ """
71
+ import uvicorn
72
+
73
+ from htmlgraph.api.main import create_app
74
+
75
+ warnings: list[str] = []
76
+ original_port = port
77
+
78
+ # Default database path - prefer project-local database if available
79
+ if db_path is None:
80
+ # Check for project-local database first
81
+ project_dir = _resolve_project_dir()
82
+ project_db = Path(project_dir) / ".htmlgraph" / "index.sqlite"
83
+ if project_db.exists():
84
+ db_path = str(project_db) # Use project-local database
85
+ else:
86
+ db_path = str(
87
+ Path.home() / ".htmlgraph" / "index.sqlite"
88
+ ) # Fall back to home
89
+
90
+ # Ensure database exists
91
+ db_path_obj = Path(db_path)
92
+ db_path_obj.parent.mkdir(parents=True, exist_ok=True)
93
+
94
+ # Handle auto-port selection
95
+ if auto_port and _check_port_in_use(port, host):
96
+ port = _find_available_port(port + 1)
97
+ warnings.append(f"Port {original_port} is in use, using {port} instead")
98
+
99
+ # Check if port is in use
100
+ if not auto_port and _check_port_in_use(port, host):
101
+ raise PortInUseError(
102
+ f"Port {port} is already in use. Use auto_port=True or choose a different port."
103
+ )
104
+
105
+ # Create FastAPI app
106
+ app = create_app(db_path=db_path)
107
+
108
+ # Create server config
109
+ config = uvicorn.Config(
110
+ app,
111
+ host=host,
112
+ port=port,
113
+ log_level="info",
114
+ reload=reload,
115
+ reload_dirs=None, # Disable file watching for now
116
+ )
117
+
118
+ # Create server instance
119
+ server = uvicorn.Server(config)
120
+
121
+ # Create handle
122
+ handle = FastAPIServerHandle(
123
+ url=f"http://{host}:{port}",
124
+ port=port,
125
+ host=host,
126
+ server=server,
127
+ )
128
+
129
+ # Configuration used
130
+ config_used = {
131
+ "port": port,
132
+ "original_port": original_port,
133
+ "host": host,
134
+ "db_path": db_path,
135
+ "auto_port": auto_port,
136
+ "reload": reload,
137
+ }
138
+
139
+ return FastAPIServerStartResult(
140
+ handle=handle,
141
+ warnings=warnings,
142
+ config_used=config_used,
143
+ )
144
+
145
+
146
+ async def run_fastapi_server(handle: FastAPIServerHandle) -> None:
147
+ """
148
+ Run FastAPI server (async).
149
+
150
+ Args:
151
+ handle: FastAPIServerHandle from start_fastapi_server()
152
+
153
+ Raises:
154
+ FastAPIServerError: If server fails
155
+ """
156
+ if handle.server is None:
157
+ raise FastAPIServerError("Invalid server handle")
158
+
159
+ try:
160
+ await handle.server.serve()
161
+ except Exception as e:
162
+ raise FastAPIServerError(f"Server error: {e}") from e
163
+
164
+
165
+ def stop_fastapi_server(handle: FastAPIServerHandle) -> None:
166
+ """
167
+ Stop FastAPI server.
168
+
169
+ Args:
170
+ handle: FastAPIServerHandle from start_fastapi_server()
171
+
172
+ Raises:
173
+ FastAPIServerError: If shutdown fails
174
+ """
175
+ if handle.server is None:
176
+ return
177
+
178
+ try:
179
+ handle.server.should_exit = True
180
+ except Exception as e:
181
+ raise FastAPIServerError(f"Failed to stop server: {e}") from e
182
+
183
+
184
+ def _check_port_in_use(port: int, host: str = "localhost") -> bool:
185
+ """
186
+ Check if a port is already in use.
187
+
188
+ Args:
189
+ port: Port number to check
190
+ host: Host to check on
191
+
192
+ Returns:
193
+ True if port is in use, False otherwise
194
+ """
195
+ import socket
196
+
197
+ try:
198
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
199
+ s.bind((host, port))
200
+ return False
201
+ except OSError:
202
+ return True
203
+
204
+
205
+ def _find_available_port(start_port: int = 8000, max_attempts: int = 10) -> int:
206
+ """
207
+ Find an available port starting from start_port.
208
+
209
+ Args:
210
+ start_port: Port to start searching from
211
+ max_attempts: Maximum number of ports to try
212
+
213
+ Returns:
214
+ Available port number
215
+
216
+ Raises:
217
+ FastAPIServerError: If no available port found
218
+ """
219
+ import socket
220
+
221
+ for port in range(start_port, start_port + max_attempts):
222
+ try:
223
+ with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
224
+ s.bind(("", port))
225
+ return port
226
+ except OSError:
227
+ continue
228
+ raise FastAPIServerError(
229
+ f"No available ports found in range {start_port}-{start_port + max_attempts}"
230
+ )