htmlgraph 0.9.3__py3-none-any.whl → 0.27.5__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 (331) 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 +173 -17
  5. htmlgraph/__init__.pyi +123 -0
  6. htmlgraph/agent_detection.py +127 -0
  7. htmlgraph/agent_registry.py +45 -30
  8. htmlgraph/agents.py +160 -107
  9. htmlgraph/analytics/__init__.py +9 -2
  10. htmlgraph/analytics/cli.py +190 -51
  11. htmlgraph/analytics/cost_analyzer.py +391 -0
  12. htmlgraph/analytics/cost_monitor.py +664 -0
  13. htmlgraph/analytics/cost_reporter.py +675 -0
  14. htmlgraph/analytics/cross_session.py +617 -0
  15. htmlgraph/analytics/dependency.py +192 -100
  16. htmlgraph/analytics/pattern_learning.py +771 -0
  17. htmlgraph/analytics/session_graph.py +707 -0
  18. htmlgraph/analytics/strategic/__init__.py +80 -0
  19. htmlgraph/analytics/strategic/cost_optimizer.py +611 -0
  20. htmlgraph/analytics/strategic/pattern_detector.py +876 -0
  21. htmlgraph/analytics/strategic/preference_manager.py +709 -0
  22. htmlgraph/analytics/strategic/suggestion_engine.py +747 -0
  23. htmlgraph/analytics/work_type.py +190 -14
  24. htmlgraph/analytics_index.py +135 -51
  25. htmlgraph/api/__init__.py +3 -0
  26. htmlgraph/api/cost_alerts_websocket.py +416 -0
  27. htmlgraph/api/main.py +2498 -0
  28. htmlgraph/api/static/htmx.min.js +1 -0
  29. htmlgraph/api/static/style-redesign.css +1344 -0
  30. htmlgraph/api/static/style.css +1079 -0
  31. htmlgraph/api/templates/dashboard-redesign.html +1366 -0
  32. htmlgraph/api/templates/dashboard.html +794 -0
  33. htmlgraph/api/templates/partials/activity-feed-hierarchical.html +326 -0
  34. htmlgraph/api/templates/partials/activity-feed.html +1100 -0
  35. htmlgraph/api/templates/partials/agents-redesign.html +317 -0
  36. htmlgraph/api/templates/partials/agents.html +317 -0
  37. htmlgraph/api/templates/partials/event-traces.html +373 -0
  38. htmlgraph/api/templates/partials/features-kanban-redesign.html +509 -0
  39. htmlgraph/api/templates/partials/features.html +578 -0
  40. htmlgraph/api/templates/partials/metrics-redesign.html +346 -0
  41. htmlgraph/api/templates/partials/metrics.html +346 -0
  42. htmlgraph/api/templates/partials/orchestration-redesign.html +443 -0
  43. htmlgraph/api/templates/partials/orchestration.html +198 -0
  44. htmlgraph/api/templates/partials/spawners.html +375 -0
  45. htmlgraph/api/templates/partials/work-items.html +613 -0
  46. htmlgraph/api/websocket.py +538 -0
  47. htmlgraph/archive/__init__.py +24 -0
  48. htmlgraph/archive/bloom.py +234 -0
  49. htmlgraph/archive/fts.py +297 -0
  50. htmlgraph/archive/manager.py +583 -0
  51. htmlgraph/archive/search.py +244 -0
  52. htmlgraph/atomic_ops.py +560 -0
  53. htmlgraph/attribute_index.py +208 -0
  54. htmlgraph/bounded_paths.py +539 -0
  55. htmlgraph/builders/__init__.py +14 -0
  56. htmlgraph/builders/base.py +118 -29
  57. htmlgraph/builders/bug.py +150 -0
  58. htmlgraph/builders/chore.py +119 -0
  59. htmlgraph/builders/epic.py +150 -0
  60. htmlgraph/builders/feature.py +31 -6
  61. htmlgraph/builders/insight.py +195 -0
  62. htmlgraph/builders/metric.py +217 -0
  63. htmlgraph/builders/pattern.py +202 -0
  64. htmlgraph/builders/phase.py +162 -0
  65. htmlgraph/builders/spike.py +52 -19
  66. htmlgraph/builders/track.py +148 -72
  67. htmlgraph/cigs/__init__.py +81 -0
  68. htmlgraph/cigs/autonomy.py +385 -0
  69. htmlgraph/cigs/cost.py +475 -0
  70. htmlgraph/cigs/messages_basic.py +472 -0
  71. htmlgraph/cigs/messaging.py +365 -0
  72. htmlgraph/cigs/models.py +771 -0
  73. htmlgraph/cigs/pattern_storage.py +427 -0
  74. htmlgraph/cigs/patterns.py +503 -0
  75. htmlgraph/cigs/posttool_analyzer.py +234 -0
  76. htmlgraph/cigs/reporter.py +818 -0
  77. htmlgraph/cigs/tracker.py +317 -0
  78. htmlgraph/cli/.htmlgraph/.session-warning-state.json +6 -0
  79. htmlgraph/cli/.htmlgraph/agents.json +72 -0
  80. htmlgraph/cli/.htmlgraph/htmlgraph.db +0 -0
  81. htmlgraph/cli/__init__.py +42 -0
  82. htmlgraph/cli/__main__.py +6 -0
  83. htmlgraph/cli/analytics.py +1424 -0
  84. htmlgraph/cli/base.py +685 -0
  85. htmlgraph/cli/constants.py +206 -0
  86. htmlgraph/cli/core.py +954 -0
  87. htmlgraph/cli/main.py +147 -0
  88. htmlgraph/cli/models.py +475 -0
  89. htmlgraph/cli/templates/__init__.py +1 -0
  90. htmlgraph/cli/templates/cost_dashboard.py +399 -0
  91. htmlgraph/cli/work/__init__.py +239 -0
  92. htmlgraph/cli/work/browse.py +115 -0
  93. htmlgraph/cli/work/features.py +568 -0
  94. htmlgraph/cli/work/orchestration.py +676 -0
  95. htmlgraph/cli/work/report.py +728 -0
  96. htmlgraph/cli/work/sessions.py +466 -0
  97. htmlgraph/cli/work/snapshot.py +559 -0
  98. htmlgraph/cli/work/tracks.py +486 -0
  99. htmlgraph/cli_commands/__init__.py +1 -0
  100. htmlgraph/cli_commands/feature.py +195 -0
  101. htmlgraph/cli_framework.py +115 -0
  102. htmlgraph/collections/__init__.py +18 -0
  103. htmlgraph/collections/base.py +415 -98
  104. htmlgraph/collections/bug.py +53 -0
  105. htmlgraph/collections/chore.py +53 -0
  106. htmlgraph/collections/epic.py +53 -0
  107. htmlgraph/collections/feature.py +12 -26
  108. htmlgraph/collections/insight.py +100 -0
  109. htmlgraph/collections/metric.py +92 -0
  110. htmlgraph/collections/pattern.py +97 -0
  111. htmlgraph/collections/phase.py +53 -0
  112. htmlgraph/collections/session.py +194 -0
  113. htmlgraph/collections/spike.py +56 -16
  114. htmlgraph/collections/task_delegation.py +241 -0
  115. htmlgraph/collections/todo.py +511 -0
  116. htmlgraph/collections/traces.py +487 -0
  117. htmlgraph/config/cost_models.json +56 -0
  118. htmlgraph/config.py +190 -0
  119. htmlgraph/context_analytics.py +344 -0
  120. htmlgraph/converter.py +216 -28
  121. htmlgraph/cost_analysis/__init__.py +5 -0
  122. htmlgraph/cost_analysis/analyzer.py +438 -0
  123. htmlgraph/dashboard.html +2406 -307
  124. htmlgraph/dashboard.html.backup +6592 -0
  125. htmlgraph/dashboard.html.bak +7181 -0
  126. htmlgraph/dashboard.html.bak2 +7231 -0
  127. htmlgraph/dashboard.html.bak3 +7232 -0
  128. htmlgraph/db/__init__.py +38 -0
  129. htmlgraph/db/queries.py +790 -0
  130. htmlgraph/db/schema.py +1788 -0
  131. htmlgraph/decorators.py +317 -0
  132. htmlgraph/dependency_models.py +19 -2
  133. htmlgraph/deploy.py +142 -125
  134. htmlgraph/deployment_models.py +474 -0
  135. htmlgraph/docs/API_REFERENCE.md +841 -0
  136. htmlgraph/docs/HTTP_API.md +750 -0
  137. htmlgraph/docs/INTEGRATION_GUIDE.md +752 -0
  138. htmlgraph/docs/ORCHESTRATION_PATTERNS.md +717 -0
  139. htmlgraph/docs/README.md +532 -0
  140. htmlgraph/docs/__init__.py +77 -0
  141. htmlgraph/docs/docs_version.py +55 -0
  142. htmlgraph/docs/metadata.py +93 -0
  143. htmlgraph/docs/migrations.py +232 -0
  144. htmlgraph/docs/template_engine.py +143 -0
  145. htmlgraph/docs/templates/_sections/cli_reference.md.j2 +52 -0
  146. htmlgraph/docs/templates/_sections/core_concepts.md.j2 +29 -0
  147. htmlgraph/docs/templates/_sections/sdk_basics.md.j2 +69 -0
  148. htmlgraph/docs/templates/base_agents.md.j2 +78 -0
  149. htmlgraph/docs/templates/example_user_override.md.j2 +47 -0
  150. htmlgraph/docs/version_check.py +163 -0
  151. htmlgraph/edge_index.py +182 -27
  152. htmlgraph/error_handler.py +544 -0
  153. htmlgraph/event_log.py +100 -52
  154. htmlgraph/event_migration.py +13 -4
  155. htmlgraph/exceptions.py +49 -0
  156. htmlgraph/file_watcher.py +101 -28
  157. htmlgraph/find_api.py +75 -63
  158. htmlgraph/git_events.py +145 -63
  159. htmlgraph/graph.py +1122 -106
  160. htmlgraph/hooks/.htmlgraph/.session-warning-state.json +6 -0
  161. htmlgraph/hooks/.htmlgraph/agents.json +72 -0
  162. htmlgraph/hooks/.htmlgraph/index.sqlite +0 -0
  163. htmlgraph/hooks/__init__.py +45 -0
  164. htmlgraph/hooks/bootstrap.py +169 -0
  165. htmlgraph/hooks/cigs_pretool_enforcer.py +354 -0
  166. htmlgraph/hooks/concurrent_sessions.py +208 -0
  167. htmlgraph/hooks/context.py +350 -0
  168. htmlgraph/hooks/drift_handler.py +525 -0
  169. htmlgraph/hooks/event_tracker.py +1314 -0
  170. htmlgraph/hooks/git_commands.py +175 -0
  171. htmlgraph/hooks/hooks-config.example.json +12 -0
  172. htmlgraph/hooks/installer.py +343 -0
  173. htmlgraph/hooks/orchestrator.py +674 -0
  174. htmlgraph/hooks/orchestrator_reflector.py +223 -0
  175. htmlgraph/hooks/post-checkout.sh +28 -0
  176. htmlgraph/hooks/post-commit.sh +24 -0
  177. htmlgraph/hooks/post-merge.sh +26 -0
  178. htmlgraph/hooks/post_tool_use_failure.py +273 -0
  179. htmlgraph/hooks/post_tool_use_handler.py +257 -0
  180. htmlgraph/hooks/posttooluse.py +408 -0
  181. htmlgraph/hooks/pre-commit.sh +94 -0
  182. htmlgraph/hooks/pre-push.sh +28 -0
  183. htmlgraph/hooks/pretooluse.py +819 -0
  184. htmlgraph/hooks/prompt_analyzer.py +637 -0
  185. htmlgraph/hooks/session_handler.py +668 -0
  186. htmlgraph/hooks/session_summary.py +395 -0
  187. htmlgraph/hooks/state_manager.py +504 -0
  188. htmlgraph/hooks/subagent_detection.py +202 -0
  189. htmlgraph/hooks/subagent_stop.py +369 -0
  190. htmlgraph/hooks/task_enforcer.py +255 -0
  191. htmlgraph/hooks/task_validator.py +177 -0
  192. htmlgraph/hooks/validator.py +628 -0
  193. htmlgraph/ids.py +41 -27
  194. htmlgraph/index.d.ts +286 -0
  195. htmlgraph/learning.py +767 -0
  196. htmlgraph/mcp_server.py +69 -23
  197. htmlgraph/models.py +1586 -87
  198. htmlgraph/operations/README.md +62 -0
  199. htmlgraph/operations/__init__.py +79 -0
  200. htmlgraph/operations/analytics.py +339 -0
  201. htmlgraph/operations/bootstrap.py +289 -0
  202. htmlgraph/operations/events.py +244 -0
  203. htmlgraph/operations/fastapi_server.py +231 -0
  204. htmlgraph/operations/hooks.py +350 -0
  205. htmlgraph/operations/initialization.py +597 -0
  206. htmlgraph/operations/initialization.py.backup +228 -0
  207. htmlgraph/operations/server.py +303 -0
  208. htmlgraph/orchestration/__init__.py +58 -0
  209. htmlgraph/orchestration/claude_launcher.py +179 -0
  210. htmlgraph/orchestration/command_builder.py +72 -0
  211. htmlgraph/orchestration/headless_spawner.py +281 -0
  212. htmlgraph/orchestration/live_events.py +377 -0
  213. htmlgraph/orchestration/model_selection.py +327 -0
  214. htmlgraph/orchestration/plugin_manager.py +140 -0
  215. htmlgraph/orchestration/prompts.py +137 -0
  216. htmlgraph/orchestration/spawner_event_tracker.py +383 -0
  217. htmlgraph/orchestration/spawners/__init__.py +16 -0
  218. htmlgraph/orchestration/spawners/base.py +194 -0
  219. htmlgraph/orchestration/spawners/claude.py +173 -0
  220. htmlgraph/orchestration/spawners/codex.py +435 -0
  221. htmlgraph/orchestration/spawners/copilot.py +294 -0
  222. htmlgraph/orchestration/spawners/gemini.py +471 -0
  223. htmlgraph/orchestration/subprocess_runner.py +36 -0
  224. htmlgraph/orchestration/task_coordination.py +343 -0
  225. htmlgraph/orchestration.md +563 -0
  226. htmlgraph/orchestrator-system-prompt-optimized.txt +863 -0
  227. htmlgraph/orchestrator.py +669 -0
  228. htmlgraph/orchestrator_config.py +357 -0
  229. htmlgraph/orchestrator_mode.py +328 -0
  230. htmlgraph/orchestrator_validator.py +133 -0
  231. htmlgraph/parallel.py +646 -0
  232. htmlgraph/parser.py +160 -35
  233. htmlgraph/path_query.py +608 -0
  234. htmlgraph/pattern_matcher.py +636 -0
  235. htmlgraph/planning.py +147 -52
  236. htmlgraph/pydantic_models.py +476 -0
  237. htmlgraph/quality_gates.py +350 -0
  238. htmlgraph/query_builder.py +109 -72
  239. htmlgraph/query_composer.py +509 -0
  240. htmlgraph/reflection.py +443 -0
  241. htmlgraph/refs.py +344 -0
  242. htmlgraph/repo_hash.py +512 -0
  243. htmlgraph/repositories/__init__.py +292 -0
  244. htmlgraph/repositories/analytics_repository.py +455 -0
  245. htmlgraph/repositories/analytics_repository_standard.py +628 -0
  246. htmlgraph/repositories/feature_repository.py +581 -0
  247. htmlgraph/repositories/feature_repository_htmlfile.py +668 -0
  248. htmlgraph/repositories/feature_repository_memory.py +607 -0
  249. htmlgraph/repositories/feature_repository_sqlite.py +858 -0
  250. htmlgraph/repositories/filter_service.py +620 -0
  251. htmlgraph/repositories/filter_service_standard.py +445 -0
  252. htmlgraph/repositories/shared_cache.py +621 -0
  253. htmlgraph/repositories/shared_cache_memory.py +395 -0
  254. htmlgraph/repositories/track_repository.py +552 -0
  255. htmlgraph/repositories/track_repository_htmlfile.py +619 -0
  256. htmlgraph/repositories/track_repository_memory.py +508 -0
  257. htmlgraph/repositories/track_repository_sqlite.py +711 -0
  258. htmlgraph/routing.py +8 -19
  259. htmlgraph/scripts/deploy.py +1 -2
  260. htmlgraph/sdk/__init__.py +398 -0
  261. htmlgraph/sdk/__init__.pyi +14 -0
  262. htmlgraph/sdk/analytics/__init__.py +19 -0
  263. htmlgraph/sdk/analytics/engine.py +155 -0
  264. htmlgraph/sdk/analytics/helpers.py +178 -0
  265. htmlgraph/sdk/analytics/registry.py +109 -0
  266. htmlgraph/sdk/base.py +484 -0
  267. htmlgraph/sdk/constants.py +216 -0
  268. htmlgraph/sdk/core.pyi +308 -0
  269. htmlgraph/sdk/discovery.py +120 -0
  270. htmlgraph/sdk/help/__init__.py +12 -0
  271. htmlgraph/sdk/help/mixin.py +699 -0
  272. htmlgraph/sdk/mixins/__init__.py +15 -0
  273. htmlgraph/sdk/mixins/attribution.py +113 -0
  274. htmlgraph/sdk/mixins/mixin.py +410 -0
  275. htmlgraph/sdk/operations/__init__.py +12 -0
  276. htmlgraph/sdk/operations/mixin.py +427 -0
  277. htmlgraph/sdk/orchestration/__init__.py +17 -0
  278. htmlgraph/sdk/orchestration/coordinator.py +203 -0
  279. htmlgraph/sdk/orchestration/spawner.py +204 -0
  280. htmlgraph/sdk/planning/__init__.py +19 -0
  281. htmlgraph/sdk/planning/bottlenecks.py +93 -0
  282. htmlgraph/sdk/planning/mixin.py +211 -0
  283. htmlgraph/sdk/planning/parallel.py +186 -0
  284. htmlgraph/sdk/planning/queue.py +210 -0
  285. htmlgraph/sdk/planning/recommendations.py +87 -0
  286. htmlgraph/sdk/planning/smart_planning.py +319 -0
  287. htmlgraph/sdk/session/__init__.py +19 -0
  288. htmlgraph/sdk/session/continuity.py +57 -0
  289. htmlgraph/sdk/session/handoff.py +110 -0
  290. htmlgraph/sdk/session/info.py +309 -0
  291. htmlgraph/sdk/session/manager.py +103 -0
  292. htmlgraph/sdk/strategic/__init__.py +26 -0
  293. htmlgraph/sdk/strategic/mixin.py +563 -0
  294. htmlgraph/server.py +685 -180
  295. htmlgraph/services/__init__.py +10 -0
  296. htmlgraph/services/claiming.py +199 -0
  297. htmlgraph/session_hooks.py +300 -0
  298. htmlgraph/session_manager.py +1392 -175
  299. htmlgraph/session_registry.py +587 -0
  300. htmlgraph/session_state.py +436 -0
  301. htmlgraph/session_warning.py +201 -0
  302. htmlgraph/sessions/__init__.py +23 -0
  303. htmlgraph/sessions/handoff.py +756 -0
  304. htmlgraph/setup.py +34 -17
  305. htmlgraph/spike_index.py +143 -0
  306. htmlgraph/sync_docs.py +12 -15
  307. htmlgraph/system_prompts.py +450 -0
  308. htmlgraph/templates/AGENTS.md.template +366 -0
  309. htmlgraph/templates/CLAUDE.md.template +97 -0
  310. htmlgraph/templates/GEMINI.md.template +87 -0
  311. htmlgraph/templates/orchestration-view.html +350 -0
  312. htmlgraph/track_builder.py +146 -15
  313. htmlgraph/track_manager.py +69 -21
  314. htmlgraph/transcript.py +890 -0
  315. htmlgraph/transcript_analytics.py +699 -0
  316. htmlgraph/types.py +323 -0
  317. htmlgraph/validation.py +115 -0
  318. htmlgraph/watch.py +8 -5
  319. htmlgraph/work_type_utils.py +3 -2
  320. {htmlgraph-0.9.3.data → htmlgraph-0.27.5.data}/data/htmlgraph/dashboard.html +2406 -307
  321. htmlgraph-0.27.5.data/data/htmlgraph/templates/AGENTS.md.template +366 -0
  322. htmlgraph-0.27.5.data/data/htmlgraph/templates/CLAUDE.md.template +97 -0
  323. htmlgraph-0.27.5.data/data/htmlgraph/templates/GEMINI.md.template +87 -0
  324. {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/METADATA +97 -64
  325. htmlgraph-0.27.5.dist-info/RECORD +337 -0
  326. {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/entry_points.txt +1 -1
  327. htmlgraph/cli.py +0 -2688
  328. htmlgraph/sdk.py +0 -709
  329. htmlgraph-0.9.3.dist-info/RECORD +0 -61
  330. {htmlgraph-0.9.3.data → htmlgraph-0.27.5.data}/data/htmlgraph/styles.css +0 -0
  331. {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/WHEEL +0 -0
@@ -0,0 +1,62 @@
1
+ # HtmlGraph Operations Layer
2
+
3
+ This module defines a shared, backend operations layer for HtmlGraph. The CLI and SDK
4
+ should call these operations rather than duplicating logic. The operations layer is
5
+ pure Python, stateless, and returns structured data instead of printing.
6
+
7
+ ## Design Principles
8
+
9
+ - Stateless: all inputs passed explicitly; no global CLI state.
10
+ - Typed: full type hints, dataclasses for results.
11
+ - Structured results: return data, warnings, and metadata; no printing.
12
+ - Exceptions for errors: no sys.exit.
13
+ - Path-first: accept Path objects for filesystem inputs.
14
+ - Reusable: callable from CLI, SDK, and tests.
15
+
16
+ ## Module Structure
17
+
18
+ - `operations/server.py` Server startup and lifecycle helpers
19
+ - `operations/hooks.py` Git hook installation and configuration
20
+ - `operations/events.py` Event export, index rebuild, event queries
21
+ - `operations/analytics.py` Analytics summaries and report generation
22
+
23
+ ## Example Signature
24
+
25
+ ```python
26
+ from dataclasses import dataclass
27
+ from pathlib import Path
28
+ from typing import Any
29
+
30
+ @dataclass
31
+ class ServerHandle:
32
+ url: str
33
+ port: int
34
+ host: str
35
+
36
+ @dataclass
37
+ class ServerStartResult:
38
+ handle: ServerHandle
39
+ warnings: list[str]
40
+ config_used: dict[str, Any]
41
+
42
+ class ServerStartError(RuntimeError):
43
+ pass
44
+
45
+
46
+ def start_server(
47
+ *,
48
+ port: int,
49
+ graph_dir: Path,
50
+ host: str = "localhost",
51
+ watch: bool = True,
52
+ auto_port: bool = False,
53
+ ) -> ServerStartResult:
54
+ """Start HtmlGraph server with validated config."""
55
+ raise NotImplementedError
56
+ ```
57
+
58
+ ## Conventions
59
+
60
+ - Functions should avoid any CLI-specific formatting.
61
+ - Results should be serializable for JSON output.
62
+ - Keep modules focused on a single domain (server, hooks, events, analytics).
@@ -0,0 +1,79 @@
1
+ """Shared operations layer for HtmlGraph CLI and SDK."""
2
+
3
+ from .analytics import (
4
+ AnalyticsProjectResult,
5
+ AnalyticsSessionResult,
6
+ analyze_project,
7
+ analyze_session,
8
+ )
9
+ from .events import (
10
+ EventExportResult,
11
+ EventQueryResult,
12
+ EventRebuildResult,
13
+ EventStats,
14
+ export_sessions,
15
+ get_event_stats,
16
+ query_events,
17
+ rebuild_index,
18
+ )
19
+ from .hooks import (
20
+ HookInstallResult,
21
+ HookListResult,
22
+ HookValidationResult,
23
+ install_hooks,
24
+ list_hooks,
25
+ validate_hook_config,
26
+ )
27
+ from .initialization import (
28
+ create_analytics_index,
29
+ create_config_files,
30
+ create_database,
31
+ create_directory_structure,
32
+ initialize_htmlgraph,
33
+ install_git_hooks,
34
+ update_gitignore,
35
+ validate_directory,
36
+ )
37
+ from .server import (
38
+ ServerHandle,
39
+ ServerStartResult,
40
+ ServerStatus,
41
+ get_server_status,
42
+ start_server,
43
+ stop_server,
44
+ )
45
+
46
+ __all__ = [
47
+ "AnalyticsProjectResult",
48
+ "AnalyticsSessionResult",
49
+ "analyze_project",
50
+ "analyze_session",
51
+ "EventExportResult",
52
+ "EventQueryResult",
53
+ "EventRebuildResult",
54
+ "EventStats",
55
+ "export_sessions",
56
+ "get_event_stats",
57
+ "query_events",
58
+ "rebuild_index",
59
+ "HookInstallResult",
60
+ "HookListResult",
61
+ "HookValidationResult",
62
+ "install_hooks",
63
+ "list_hooks",
64
+ "validate_hook_config",
65
+ "ServerHandle",
66
+ "ServerStartResult",
67
+ "ServerStatus",
68
+ "start_server",
69
+ "stop_server",
70
+ "get_server_status",
71
+ "initialize_htmlgraph",
72
+ "validate_directory",
73
+ "create_directory_structure",
74
+ "create_database",
75
+ "create_analytics_index",
76
+ "create_config_files",
77
+ "update_gitignore",
78
+ "install_git_hooks",
79
+ ]
@@ -0,0 +1,339 @@
1
+ from __future__ import annotations
2
+
3
+ """Analytics operations for HtmlGraph."""
4
+
5
+
6
+ from dataclasses import dataclass
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ from htmlgraph import SDK
11
+ from htmlgraph.converter import html_to_session
12
+
13
+
14
+ @dataclass(frozen=True)
15
+ class AnalyticsSessionResult:
16
+ """Result of analyzing a single session."""
17
+
18
+ session_id: str
19
+ metrics: dict[str, Any]
20
+ warnings: list[str]
21
+
22
+
23
+ @dataclass(frozen=True)
24
+ class AnalyticsProjectResult:
25
+ """Result of analyzing project-wide analytics."""
26
+
27
+ metrics: dict[str, Any]
28
+ warnings: list[str]
29
+
30
+
31
+ @dataclass(frozen=True)
32
+ class RecommendationsResult:
33
+ """Result of getting work recommendations."""
34
+
35
+ recommendations: list[dict[str, Any]]
36
+ reasoning: dict[str, Any]
37
+ warnings: list[str]
38
+
39
+
40
+ class AnalyticsOperationError(RuntimeError):
41
+ """Base error for analytics operations."""
42
+
43
+
44
+ def analyze_session(*, graph_dir: Path, session_id: str) -> AnalyticsSessionResult:
45
+ """
46
+ Compute analytics for a single session.
47
+
48
+ Args:
49
+ graph_dir: Path to .htmlgraph directory
50
+ session_id: ID of the session to analyze
51
+
52
+ Returns:
53
+ AnalyticsSessionResult with session metrics and warnings
54
+
55
+ Raises:
56
+ AnalyticsOperationError: If session cannot be analyzed
57
+ """
58
+ warnings: list[str] = []
59
+
60
+ # Validate inputs
61
+ if not graph_dir.exists():
62
+ raise AnalyticsOperationError(f"Graph directory does not exist: {graph_dir}")
63
+
64
+ session_path = graph_dir / "sessions" / f"{session_id}.html"
65
+ if not session_path.exists():
66
+ raise AnalyticsOperationError(f"Session not found: {session_id}")
67
+
68
+ try:
69
+ # Load session
70
+ session = html_to_session(session_path)
71
+ except Exception as e:
72
+ raise AnalyticsOperationError(f"Failed to load session {session_id}: {e}")
73
+
74
+ try:
75
+ # Initialize SDK with minimal agent
76
+ sdk = SDK(directory=str(graph_dir), agent="analytics-ops")
77
+
78
+ # Compute metrics
79
+ metrics: dict[str, Any] = {}
80
+
81
+ # Work distribution
82
+ try:
83
+ work_dist = sdk.analytics.work_type_distribution(session_id=session_id)
84
+ metrics["work_distribution"] = work_dist
85
+ except Exception as e:
86
+ warnings.append(f"Failed to compute work distribution: {e}")
87
+ metrics["work_distribution"] = {}
88
+
89
+ # Spike-to-feature ratio
90
+ try:
91
+ spike_ratio = sdk.analytics.spike_to_feature_ratio(session_id=session_id)
92
+ metrics["spike_to_feature_ratio"] = spike_ratio
93
+ except Exception as e:
94
+ warnings.append(f"Failed to compute spike ratio: {e}")
95
+ metrics["spike_to_feature_ratio"] = 0.0
96
+
97
+ # Maintenance burden
98
+ try:
99
+ maintenance = sdk.analytics.maintenance_burden(session_id=session_id)
100
+ metrics["maintenance_burden"] = maintenance
101
+ except Exception as e:
102
+ warnings.append(f"Failed to compute maintenance burden: {e}")
103
+ metrics["maintenance_burden"] = 0.0
104
+
105
+ # Primary work type
106
+ try:
107
+ primary = sdk.analytics.calculate_session_primary_work_type(session_id)
108
+ metrics["primary_work_type"] = primary
109
+ except Exception as e:
110
+ warnings.append(f"Failed to compute primary work type: {e}")
111
+ metrics["primary_work_type"] = None
112
+
113
+ # Work breakdown (event counts)
114
+ try:
115
+ breakdown = sdk.analytics.calculate_session_work_breakdown(session_id)
116
+ metrics["work_breakdown"] = breakdown
117
+ metrics["total_events"] = sum(breakdown.values()) if breakdown else 0
118
+ except Exception as e:
119
+ warnings.append(f"Failed to compute work breakdown: {e}")
120
+ metrics["work_breakdown"] = {}
121
+ metrics["total_events"] = session.event_count
122
+
123
+ # Transition time metrics
124
+ try:
125
+ transition = sdk.analytics.transition_time_metrics(session_id=session_id)
126
+ metrics["transition_metrics"] = transition
127
+ except Exception as e:
128
+ warnings.append(f"Failed to compute transition metrics: {e}")
129
+ metrics["transition_metrics"] = {}
130
+
131
+ # Session metadata
132
+ metrics["session_id"] = session.id
133
+ metrics["agent"] = session.agent
134
+ metrics["status"] = session.status
135
+ metrics["started_at"] = session.started_at.isoformat()
136
+ if session.ended_at:
137
+ metrics["ended_at"] = session.ended_at.isoformat()
138
+
139
+ return AnalyticsSessionResult(
140
+ session_id=session_id, metrics=metrics, warnings=warnings
141
+ )
142
+
143
+ except AnalyticsOperationError:
144
+ raise
145
+ except Exception as e:
146
+ raise AnalyticsOperationError(f"Failed to analyze session {session_id}: {e}")
147
+
148
+
149
+ def analyze_project(*, graph_dir: Path) -> AnalyticsProjectResult:
150
+ """
151
+ Compute analytics for the project.
152
+
153
+ Args:
154
+ graph_dir: Path to .htmlgraph directory
155
+
156
+ Returns:
157
+ AnalyticsProjectResult with project metrics and warnings
158
+
159
+ Raises:
160
+ AnalyticsOperationError: If project cannot be analyzed
161
+ """
162
+ warnings: list[str] = []
163
+
164
+ # Validate inputs
165
+ if not graph_dir.exists():
166
+ raise AnalyticsOperationError(f"Graph directory does not exist: {graph_dir}")
167
+
168
+ sessions_dir = graph_dir / "sessions"
169
+ if not sessions_dir.exists():
170
+ warnings.append("No sessions directory found")
171
+ return AnalyticsProjectResult(metrics={"total_sessions": 0}, warnings=warnings)
172
+
173
+ try:
174
+ # Initialize SDK
175
+ sdk = SDK(directory=str(graph_dir), agent="analytics-ops")
176
+
177
+ # Get session count
178
+ session_files = sorted(
179
+ sessions_dir.glob("*.html"), key=lambda p: p.stat().st_mtime, reverse=True
180
+ )
181
+ total_sessions = len(session_files)
182
+
183
+ # Compute metrics
184
+ metrics: dict[str, Any] = {
185
+ "total_sessions": total_sessions,
186
+ }
187
+
188
+ if total_sessions == 0:
189
+ warnings.append("No sessions found in project")
190
+ return AnalyticsProjectResult(metrics=metrics, warnings=warnings)
191
+
192
+ # Project-wide work distribution
193
+ try:
194
+ work_dist = sdk.analytics.work_type_distribution()
195
+ metrics["work_distribution"] = work_dist
196
+ except Exception as e:
197
+ warnings.append(f"Failed to compute work distribution: {e}")
198
+ metrics["work_distribution"] = {}
199
+
200
+ # Project-wide spike-to-feature ratio
201
+ try:
202
+ spike_ratio = sdk.analytics.spike_to_feature_ratio()
203
+ metrics["spike_to_feature_ratio"] = spike_ratio
204
+ except Exception as e:
205
+ warnings.append(f"Failed to compute spike ratio: {e}")
206
+ metrics["spike_to_feature_ratio"] = 0.0
207
+
208
+ # Project-wide maintenance burden
209
+ try:
210
+ maintenance = sdk.analytics.maintenance_burden()
211
+ metrics["maintenance_burden"] = maintenance
212
+ except Exception as e:
213
+ warnings.append(f"Failed to compute maintenance burden: {e}")
214
+ metrics["maintenance_burden"] = 0.0
215
+
216
+ # Project-wide transition metrics
217
+ try:
218
+ transition = sdk.analytics.transition_time_metrics()
219
+ metrics["transition_metrics"] = transition
220
+ except Exception as e:
221
+ warnings.append(f"Failed to compute transition metrics: {e}")
222
+ metrics["transition_metrics"] = {}
223
+
224
+ # Session type breakdown
225
+ try:
226
+ from htmlgraph import WorkType
227
+
228
+ spike_sessions = sdk.analytics.get_sessions_by_work_type(
229
+ WorkType.SPIKE.value
230
+ )
231
+ feature_sessions = sdk.analytics.get_sessions_by_work_type(
232
+ WorkType.FEATURE.value
233
+ )
234
+ maintenance_sessions = sdk.analytics.get_sessions_by_work_type(
235
+ WorkType.MAINTENANCE.value
236
+ )
237
+
238
+ metrics["session_types"] = {
239
+ "spike": len(spike_sessions),
240
+ "feature": len(feature_sessions),
241
+ "maintenance": len(maintenance_sessions),
242
+ }
243
+ except Exception as e:
244
+ warnings.append(f"Failed to compute session types: {e}")
245
+ metrics["session_types"] = {}
246
+
247
+ # Recent sessions (metadata only)
248
+ try:
249
+ recent_sessions = []
250
+ for session_path in session_files[:5]: # Top 5 most recent
251
+ try:
252
+ session = html_to_session(session_path)
253
+ primary = (
254
+ sdk.analytics.calculate_session_primary_work_type(session.id)
255
+ or "unknown"
256
+ )
257
+ recent_sessions.append(
258
+ {
259
+ "session_id": session.id,
260
+ "agent": session.agent,
261
+ "started_at": session.started_at.isoformat(),
262
+ "status": session.status,
263
+ "primary_work_type": primary,
264
+ }
265
+ )
266
+ except Exception as e:
267
+ warnings.append(f"Failed to load session {session_path.name}: {e}")
268
+ continue
269
+
270
+ metrics["recent_sessions"] = recent_sessions
271
+ except Exception as e:
272
+ warnings.append(f"Failed to load recent sessions: {e}")
273
+ metrics["recent_sessions"] = []
274
+
275
+ return AnalyticsProjectResult(metrics=metrics, warnings=warnings)
276
+
277
+ except AnalyticsOperationError:
278
+ raise
279
+ except Exception as e:
280
+ raise AnalyticsOperationError(f"Failed to analyze project: {e}")
281
+
282
+
283
+ def get_recommendations(*, graph_dir: Path) -> RecommendationsResult:
284
+ """
285
+ Get work recommendations based on project state.
286
+
287
+ Args:
288
+ graph_dir: Path to .htmlgraph directory
289
+
290
+ Returns:
291
+ RecommendationsResult with recommendations, reasoning, and warnings
292
+
293
+ Raises:
294
+ AnalyticsOperationError: If recommendations cannot be generated
295
+ """
296
+ warnings: list[str] = []
297
+
298
+ # Validate inputs
299
+ if not graph_dir.exists():
300
+ raise AnalyticsOperationError(f"Graph directory does not exist: {graph_dir}")
301
+
302
+ try:
303
+ # Initialize SDK
304
+ sdk = SDK(directory=str(graph_dir), agent="analytics-ops")
305
+
306
+ # Get recommendations
307
+ try:
308
+ task_recs = sdk.dep_analytics.recommend_next_tasks(agent_count=5)
309
+ recommendations = [
310
+ {
311
+ "id": rec.id,
312
+ "title": rec.title,
313
+ "priority": rec.priority,
314
+ "score": rec.score,
315
+ "reasons": rec.reasons,
316
+ "unlocks": rec.unlocks,
317
+ "estimated_effort": rec.estimated_effort,
318
+ }
319
+ for rec in task_recs.recommendations
320
+ ]
321
+ reasoning = {
322
+ "recommendation_count": len(task_recs.recommendations),
323
+ "parallel_suggestions": task_recs.parallel_suggestions,
324
+ }
325
+ except Exception as e:
326
+ raise AnalyticsOperationError(f"Failed to generate recommendations: {e}")
327
+
328
+ # Add contextual warnings based on recommendations
329
+ if not recommendations:
330
+ warnings.append("No recommendations available - project may be empty")
331
+
332
+ return RecommendationsResult(
333
+ recommendations=recommendations, reasoning=reasoning, warnings=warnings
334
+ )
335
+
336
+ except AnalyticsOperationError:
337
+ raise
338
+ except Exception as e:
339
+ raise AnalyticsOperationError(f"Failed to get recommendations: {e}")