htmlgraph 0.26.24__py3-none-any.whl → 0.27.0__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 (155) hide show
  1. htmlgraph/__init__.py +23 -1
  2. htmlgraph/__init__.pyi +123 -0
  3. htmlgraph/agent_registry.py +2 -1
  4. htmlgraph/analytics/cli.py +3 -3
  5. htmlgraph/analytics/cost_analyzer.py +5 -1
  6. htmlgraph/analytics/cross_session.py +13 -9
  7. htmlgraph/analytics/dependency.py +10 -6
  8. htmlgraph/analytics/work_type.py +15 -11
  9. htmlgraph/analytics_index.py +2 -1
  10. htmlgraph/api/main.py +114 -51
  11. htmlgraph/api/templates/dashboard-redesign.html +3 -3
  12. htmlgraph/api/templates/dashboard.html +3 -3
  13. htmlgraph/api/templates/partials/work-items.html +613 -0
  14. htmlgraph/attribute_index.py +2 -1
  15. htmlgraph/builders/base.py +2 -1
  16. htmlgraph/builders/bug.py +2 -1
  17. htmlgraph/builders/chore.py +2 -1
  18. htmlgraph/builders/epic.py +2 -1
  19. htmlgraph/builders/feature.py +2 -1
  20. htmlgraph/builders/insight.py +2 -1
  21. htmlgraph/builders/metric.py +2 -1
  22. htmlgraph/builders/pattern.py +2 -1
  23. htmlgraph/builders/phase.py +2 -1
  24. htmlgraph/builders/spike.py +2 -1
  25. htmlgraph/builders/track.py +28 -1
  26. htmlgraph/cli/analytics.py +2 -1
  27. htmlgraph/cli/base.py +33 -8
  28. htmlgraph/cli/core.py +2 -1
  29. htmlgraph/cli/main.py +2 -1
  30. htmlgraph/cli/models.py +2 -1
  31. htmlgraph/cli/templates/cost_dashboard.py +2 -1
  32. htmlgraph/cli/work/__init__.py +76 -1
  33. htmlgraph/cli/work/browse.py +115 -0
  34. htmlgraph/cli/work/features.py +2 -1
  35. htmlgraph/cli/work/orchestration.py +2 -1
  36. htmlgraph/cli/work/report.py +2 -1
  37. htmlgraph/cli/work/sessions.py +2 -1
  38. htmlgraph/cli/work/snapshot.py +559 -0
  39. htmlgraph/cli/work/tracks.py +2 -1
  40. htmlgraph/collections/base.py +43 -4
  41. htmlgraph/collections/bug.py +2 -1
  42. htmlgraph/collections/chore.py +2 -1
  43. htmlgraph/collections/epic.py +2 -1
  44. htmlgraph/collections/feature.py +2 -1
  45. htmlgraph/collections/insight.py +2 -1
  46. htmlgraph/collections/metric.py +2 -1
  47. htmlgraph/collections/pattern.py +2 -1
  48. htmlgraph/collections/phase.py +2 -1
  49. htmlgraph/collections/session.py +12 -7
  50. htmlgraph/collections/spike.py +6 -1
  51. htmlgraph/collections/task_delegation.py +7 -2
  52. htmlgraph/collections/todo.py +14 -1
  53. htmlgraph/collections/traces.py +15 -10
  54. htmlgraph/context_analytics.py +2 -1
  55. htmlgraph/converter.py +11 -0
  56. htmlgraph/dependency_models.py +2 -1
  57. htmlgraph/edge_index.py +2 -1
  58. htmlgraph/event_log.py +81 -66
  59. htmlgraph/event_migration.py +2 -1
  60. htmlgraph/file_watcher.py +12 -8
  61. htmlgraph/find_api.py +2 -1
  62. htmlgraph/git_events.py +6 -2
  63. htmlgraph/hooks/cigs_pretool_enforcer.py +5 -1
  64. htmlgraph/hooks/drift_handler.py +3 -3
  65. htmlgraph/hooks/event_tracker.py +40 -61
  66. htmlgraph/hooks/installer.py +5 -1
  67. htmlgraph/hooks/orchestrator.py +92 -14
  68. htmlgraph/hooks/orchestrator_reflector.py +4 -0
  69. htmlgraph/hooks/post_tool_use_failure.py +7 -3
  70. htmlgraph/hooks/posttooluse.py +4 -0
  71. htmlgraph/hooks/prompt_analyzer.py +5 -5
  72. htmlgraph/hooks/session_handler.py +5 -2
  73. htmlgraph/hooks/session_summary.py +6 -2
  74. htmlgraph/hooks/validator.py +8 -4
  75. htmlgraph/ids.py +2 -1
  76. htmlgraph/learning.py +2 -1
  77. htmlgraph/mcp_server.py +2 -1
  78. htmlgraph/models.py +18 -1
  79. htmlgraph/operations/analytics.py +2 -1
  80. htmlgraph/operations/bootstrap.py +2 -1
  81. htmlgraph/operations/events.py +2 -1
  82. htmlgraph/operations/fastapi_server.py +2 -1
  83. htmlgraph/operations/hooks.py +2 -1
  84. htmlgraph/operations/initialization.py +2 -1
  85. htmlgraph/operations/server.py +2 -1
  86. htmlgraph/orchestration/__init__.py +4 -0
  87. htmlgraph/orchestration/claude_launcher.py +23 -20
  88. htmlgraph/orchestration/command_builder.py +2 -1
  89. htmlgraph/orchestration/headless_spawner.py +6 -2
  90. htmlgraph/orchestration/model_selection.py +7 -3
  91. htmlgraph/orchestration/plugin_manager.py +25 -21
  92. htmlgraph/orchestration/spawner_event_tracker.py +383 -0
  93. htmlgraph/orchestration/spawners/claude.py +5 -2
  94. htmlgraph/orchestration/spawners/codex.py +12 -19
  95. htmlgraph/orchestration/spawners/copilot.py +13 -18
  96. htmlgraph/orchestration/spawners/gemini.py +12 -19
  97. htmlgraph/orchestration/subprocess_runner.py +6 -3
  98. htmlgraph/orchestration/task_coordination.py +16 -8
  99. htmlgraph/orchestrator.py +2 -1
  100. htmlgraph/parallel.py +2 -1
  101. htmlgraph/query_builder.py +2 -1
  102. htmlgraph/reflection.py +2 -1
  103. htmlgraph/refs.py +344 -0
  104. htmlgraph/repo_hash.py +2 -1
  105. htmlgraph/sdk/__init__.py +398 -0
  106. htmlgraph/sdk/__init__.pyi +14 -0
  107. htmlgraph/sdk/analytics/__init__.py +19 -0
  108. htmlgraph/sdk/analytics/engine.py +155 -0
  109. htmlgraph/sdk/analytics/helpers.py +178 -0
  110. htmlgraph/sdk/analytics/registry.py +109 -0
  111. htmlgraph/sdk/base.py +484 -0
  112. htmlgraph/sdk/constants.py +216 -0
  113. htmlgraph/sdk/core.pyi +308 -0
  114. htmlgraph/sdk/discovery.py +120 -0
  115. htmlgraph/sdk/help/__init__.py +12 -0
  116. htmlgraph/sdk/help/mixin.py +699 -0
  117. htmlgraph/sdk/mixins/__init__.py +15 -0
  118. htmlgraph/sdk/mixins/attribution.py +113 -0
  119. htmlgraph/sdk/mixins/mixin.py +410 -0
  120. htmlgraph/sdk/operations/__init__.py +12 -0
  121. htmlgraph/sdk/operations/mixin.py +427 -0
  122. htmlgraph/sdk/orchestration/__init__.py +17 -0
  123. htmlgraph/sdk/orchestration/coordinator.py +203 -0
  124. htmlgraph/sdk/orchestration/spawner.py +204 -0
  125. htmlgraph/sdk/planning/__init__.py +19 -0
  126. htmlgraph/sdk/planning/bottlenecks.py +93 -0
  127. htmlgraph/sdk/planning/mixin.py +211 -0
  128. htmlgraph/sdk/planning/parallel.py +186 -0
  129. htmlgraph/sdk/planning/queue.py +210 -0
  130. htmlgraph/sdk/planning/recommendations.py +87 -0
  131. htmlgraph/sdk/planning/smart_planning.py +319 -0
  132. htmlgraph/sdk/session/__init__.py +19 -0
  133. htmlgraph/sdk/session/continuity.py +57 -0
  134. htmlgraph/sdk/session/handoff.py +110 -0
  135. htmlgraph/sdk/session/info.py +309 -0
  136. htmlgraph/sdk/session/manager.py +103 -0
  137. htmlgraph/server.py +21 -17
  138. htmlgraph/session_manager.py +1 -7
  139. htmlgraph/session_warning.py +2 -1
  140. htmlgraph/sessions/handoff.py +10 -3
  141. htmlgraph/system_prompts.py +2 -1
  142. htmlgraph/track_builder.py +14 -1
  143. htmlgraph/transcript.py +2 -1
  144. htmlgraph/watch.py +2 -1
  145. htmlgraph/work_type_utils.py +2 -1
  146. {htmlgraph-0.26.24.dist-info → htmlgraph-0.27.0.dist-info}/METADATA +15 -1
  147. {htmlgraph-0.26.24.dist-info → htmlgraph-0.27.0.dist-info}/RECORD +154 -117
  148. htmlgraph/sdk.py +0 -3430
  149. {htmlgraph-0.26.24.data → htmlgraph-0.27.0.data}/data/htmlgraph/dashboard.html +0 -0
  150. {htmlgraph-0.26.24.data → htmlgraph-0.27.0.data}/data/htmlgraph/styles.css +0 -0
  151. {htmlgraph-0.26.24.data → htmlgraph-0.27.0.data}/data/htmlgraph/templates/AGENTS.md.template +0 -0
  152. {htmlgraph-0.26.24.data → htmlgraph-0.27.0.data}/data/htmlgraph/templates/CLAUDE.md.template +0 -0
  153. {htmlgraph-0.26.24.data → htmlgraph-0.27.0.data}/data/htmlgraph/templates/GEMINI.md.template +0 -0
  154. {htmlgraph-0.26.24.dist-info → htmlgraph-0.27.0.dist-info}/WHEEL +0 -0
  155. {htmlgraph-0.26.24.dist-info → htmlgraph-0.27.0.dist-info}/entry_points.txt +0 -0
htmlgraph/__init__.py CHANGED
@@ -5,6 +5,28 @@ A lightweight graph database framework using HTML files as nodes,
5
5
  hyperlinks as edges, and CSS selectors as the query language.
6
6
  """
7
7
 
8
+ import logging
9
+
10
+ from rich.console import Console
11
+ from rich.logging import RichHandler
12
+
13
+ # Configure Rich logging for entire SDK
14
+ # CRITICAL: Use stderr=True to prevent pollution of stdout (hooks output JSON to stdout)
15
+ logging.basicConfig(
16
+ handlers=[
17
+ RichHandler(
18
+ console=Console(stderr=True),
19
+ show_time=True,
20
+ show_level=True,
21
+ rich_tracebacks=True,
22
+ )
23
+ ],
24
+ level=logging.INFO,
25
+ format="%(message)s",
26
+ datefmt="[%X]",
27
+ )
28
+
29
+ # SDK now lives in sdk/core.py - clean import from sdk package
8
30
  from htmlgraph.agent_detection import detect_agent_name, get_agent_display_name
9
31
  from htmlgraph.agents import AgentInterface
10
32
  from htmlgraph.analytics import Analytics, DependencyAnalytics
@@ -96,7 +118,7 @@ from htmlgraph.types import (
96
118
  )
97
119
  from htmlgraph.work_type_utils import infer_work_type, infer_work_type_from_id
98
120
 
99
- __version__ = "0.26.24"
121
+ __version__ = "0.27.0"
100
122
  __all__ = [
101
123
  # Exceptions
102
124
  "HtmlGraphError",
htmlgraph/__init__.pyi ADDED
@@ -0,0 +1,123 @@
1
+ """
2
+ Type stub for htmlgraph package.
3
+
4
+ This stub provides type information for mypy when the SDK class
5
+ is loaded dynamically via importlib at runtime.
6
+ """
7
+
8
+ from htmlgraph.agent_detection import detect_agent_name as detect_agent_name
9
+ from htmlgraph.agent_detection import get_agent_display_name as get_agent_display_name
10
+ from htmlgraph.agents import AgentInterface as AgentInterface
11
+ from htmlgraph.analytics import Analytics as Analytics
12
+
13
+ # Analytics
14
+ from htmlgraph.analytics import DependencyAnalytics as DependencyAnalytics
15
+ from htmlgraph.atomic_ops import AtomicFileWriter as AtomicFileWriter
16
+ from htmlgraph.atomic_ops import DirectoryLocker as DirectoryLocker
17
+ from htmlgraph.atomic_ops import atomic_rename as atomic_rename
18
+ from htmlgraph.atomic_ops import (
19
+ cleanup_orphaned_temp_files as cleanup_orphaned_temp_files,
20
+ )
21
+ from htmlgraph.atomic_ops import safe_temp_file as safe_temp_file
22
+ from htmlgraph.atomic_ops import validate_atomic_write as validate_atomic_write
23
+ from htmlgraph.builders import BaseBuilder as BaseBuilder
24
+ from htmlgraph.builders import FeatureBuilder as FeatureBuilder
25
+ from htmlgraph.builders import SpikeBuilder as SpikeBuilder
26
+ from htmlgraph.collections import BaseCollection as BaseCollection
27
+
28
+ # Collections
29
+ from htmlgraph.collections import FeatureCollection as FeatureCollection
30
+ from htmlgraph.collections import SpikeCollection as SpikeCollection
31
+ from htmlgraph.context_analytics import ContextAnalytics as ContextAnalytics
32
+ from htmlgraph.context_analytics import ContextUsage as ContextUsage
33
+ from htmlgraph.decorators import RetryError as RetryError
34
+ from htmlgraph.decorators import retry as retry
35
+ from htmlgraph.decorators import retry_async as retry_async
36
+ from htmlgraph.edge_index import EdgeIndex as EdgeIndex
37
+ from htmlgraph.edge_index import EdgeRef as EdgeRef
38
+ from htmlgraph.exceptions import ClaimConflictError as ClaimConflictError
39
+ from htmlgraph.exceptions import HtmlGraphError as HtmlGraphError
40
+ from htmlgraph.exceptions import NodeNotFoundError as NodeNotFoundError
41
+ from htmlgraph.exceptions import SessionNotFoundError as SessionNotFoundError
42
+ from htmlgraph.exceptions import ValidationError as ValidationError
43
+ from htmlgraph.find_api import FindAPI as FindAPI
44
+ from htmlgraph.find_api import find as find
45
+ from htmlgraph.find_api import find_all as find_all
46
+ from htmlgraph.graph import CompiledQuery as CompiledQuery
47
+ from htmlgraph.graph import HtmlGraph as HtmlGraph
48
+ from htmlgraph.ids import generate_hierarchical_id as generate_hierarchical_id
49
+ from htmlgraph.ids import generate_id as generate_id
50
+ from htmlgraph.ids import is_legacy_id as is_legacy_id
51
+ from htmlgraph.ids import is_valid_id as is_valid_id
52
+ from htmlgraph.ids import parse_id as parse_id
53
+ from htmlgraph.learning import LearningPersistence as LearningPersistence
54
+ from htmlgraph.learning import (
55
+ auto_persist_on_session_end as auto_persist_on_session_end,
56
+ )
57
+ from htmlgraph.models import ActivityEntry as ActivityEntry
58
+ from htmlgraph.models import AggregatedMetric as AggregatedMetric
59
+ from htmlgraph.models import Chore as Chore
60
+ from htmlgraph.models import ContextSnapshot as ContextSnapshot
61
+ from htmlgraph.models import Edge as Edge
62
+ from htmlgraph.models import Graph as Graph
63
+ from htmlgraph.models import MaintenanceType as MaintenanceType
64
+ from htmlgraph.models import Node as Node
65
+ from htmlgraph.models import Pattern as Pattern
66
+ from htmlgraph.models import Session as Session
67
+ from htmlgraph.models import SessionInsight as SessionInsight
68
+ from htmlgraph.models import Spike as Spike
69
+ from htmlgraph.models import SpikeType as SpikeType
70
+ from htmlgraph.models import Step as Step
71
+ from htmlgraph.models import WorkType as WorkType
72
+ from htmlgraph.orchestration import delegate_with_id as delegate_with_id
73
+ from htmlgraph.orchestration import generate_task_id as generate_task_id
74
+ from htmlgraph.orchestration import get_results_by_task_id as get_results_by_task_id
75
+ from htmlgraph.orchestration import parallel_delegate as parallel_delegate
76
+ from htmlgraph.orchestrator_mode import OrchestratorMode as OrchestratorMode
77
+ from htmlgraph.orchestrator_mode import (
78
+ OrchestratorModeManager as OrchestratorModeManager,
79
+ )
80
+ from htmlgraph.parallel import AggregateResult as AggregateResult
81
+ from htmlgraph.parallel import ParallelAnalysis as ParallelAnalysis
82
+ from htmlgraph.parallel import ParallelWorkflow as ParallelWorkflow
83
+ from htmlgraph.query_builder import Condition as Condition
84
+ from htmlgraph.query_builder import Operator as Operator
85
+ from htmlgraph.query_builder import QueryBuilder as QueryBuilder
86
+ from htmlgraph.reflection import ComputationalReflection as ComputationalReflection
87
+ from htmlgraph.reflection import get_reflection_context as get_reflection_context
88
+ from htmlgraph.repo_hash import RepoHash as RepoHash
89
+ from htmlgraph.sdk.core import SDK as SDK
90
+ from htmlgraph.server import serve as serve
91
+ from htmlgraph.session_manager import SessionManager as SessionManager
92
+ from htmlgraph.session_registry import SessionRegistry as SessionRegistry
93
+ from htmlgraph.types import ActiveWorkItem as ActiveWorkItem
94
+ from htmlgraph.types import AggregateResultsDict as AggregateResultsDict
95
+ from htmlgraph.types import BottleneckDict as BottleneckDict
96
+ from htmlgraph.types import FeatureSummary as FeatureSummary
97
+ from htmlgraph.types import HighRiskTask as HighRiskTask
98
+ from htmlgraph.types import ImpactAnalysisDict as ImpactAnalysisDict
99
+ from htmlgraph.types import OrchestrationResult as OrchestrationResult
100
+ from htmlgraph.types import ParallelGuidelines as ParallelGuidelines
101
+ from htmlgraph.types import ParallelPlanResult as ParallelPlanResult
102
+ from htmlgraph.types import ParallelWorkInfo as ParallelWorkInfo
103
+ from htmlgraph.types import PlanningContext as PlanningContext
104
+ from htmlgraph.types import ProjectStatus as ProjectStatus
105
+ from htmlgraph.types import RiskAssessmentDict as RiskAssessmentDict
106
+ from htmlgraph.types import SessionAnalytics as SessionAnalytics
107
+ from htmlgraph.types import SessionStartInfo as SessionStartInfo
108
+ from htmlgraph.types import SessionSummary as SessionSummary
109
+ from htmlgraph.types import SmartPlanResult as SmartPlanResult
110
+ from htmlgraph.types import SubagentPrompt as SubagentPrompt
111
+ from htmlgraph.types import TaskPrompt as TaskPrompt
112
+ from htmlgraph.types import TrackCreationResult as TrackCreationResult
113
+ from htmlgraph.types import WorkQueueItem as WorkQueueItem
114
+ from htmlgraph.types import WorkRecommendation as WorkRecommendation
115
+ from htmlgraph.work_type_utils import infer_work_type as infer_work_type
116
+ from htmlgraph.work_type_utils import infer_work_type_from_id as infer_work_type_from_id
117
+
118
+ __version__: str
119
+
120
+ # SDK is imported from htmlgraph.sdk.core (see import above)
121
+ # Re-exported here for backward compatibility
122
+
123
+ __all__: list[str]
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  """
2
4
  Agent Registry - Manages agent capabilities and routing.
3
5
 
@@ -7,7 +9,6 @@ Provides:
7
9
  - Capability matching for task routing
8
10
  """
9
11
 
10
- from __future__ import annotations
11
12
 
12
13
  import json
13
14
  from dataclasses import dataclass, field
@@ -109,7 +109,7 @@ def _iter_with_progress(
109
109
 
110
110
 
111
111
  def _display_session_analytics(
112
- console: Console, sdk: SDK, session_id: str, graph_dir: str, quiet: bool
112
+ console: Console, sdk: "SDK", session_id: str, graph_dir: str, quiet: bool
113
113
  ) -> None:
114
114
  """Display analytics for a single session."""
115
115
  from htmlgraph.converter import html_to_session
@@ -221,7 +221,7 @@ def _display_session_analytics(
221
221
 
222
222
  def _display_recent_sessions(
223
223
  console: Console,
224
- sdk: SDK,
224
+ sdk: "SDK",
225
225
  session_files: list[Path],
226
226
  graph_dir: str,
227
227
  quiet: bool,
@@ -286,7 +286,7 @@ def _display_recent_sessions(
286
286
 
287
287
  def _display_project_analytics(
288
288
  console: Console,
289
- sdk: SDK,
289
+ sdk: "SDK",
290
290
  session_files: list[Path],
291
291
  graph_dir: str,
292
292
  quiet: bool,
@@ -1,3 +1,7 @@
1
+ import logging
2
+
3
+ logger = logging.getLogger(__name__)
4
+
1
5
  """
2
6
  CostAnalyzer for OTEL ROI Analysis - Phase 1.
3
7
 
@@ -15,7 +19,7 @@ Usage:
15
19
  from htmlgraph.analytics.cost_analyzer import CostAnalyzer
16
20
  analyzer = CostAnalyzer()
17
21
  delegations = analyzer.get_task_delegations_with_costs()
18
- print(f"Total delegation cost: ${delegations['total_cost_usd']:.2f}")
22
+ logger.info(f"Total delegation cost: ${delegations['total_cost_usd']:.2f}")
19
23
  """
20
24
 
21
25
  import sqlite3
@@ -1,3 +1,9 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+
5
+ logger = logging.getLogger(__name__)
6
+
1
7
  """
2
8
  Cross-session analytics using Git commits as the continuity spine.
3
9
 
@@ -38,8 +44,6 @@ Example:
38
44
  authors = cross.work_by_author(since_commit="abc123")
39
45
  """
40
46
 
41
- from __future__ import annotations
42
-
43
47
  import subprocess
44
48
  from collections import defaultdict
45
49
  from dataclasses import dataclass
@@ -147,8 +151,8 @@ class CrossSessionAnalytics:
147
151
  ... from_commit="HEAD~10",
148
152
  ... to_commit="HEAD"
149
153
  ... )
150
- >>> print(f"Total events: {report.total_events}")
151
- >>> print(f"Features: {', '.join(report.features)}")
154
+ >>> logger.info(f"Total events: {report.total_events}")
155
+ >>> logger.info(f"Features: {', '.join(report.features)}")
152
156
  """
153
157
  # Get commit list from Git
154
158
  commits = self._get_commits_in_range(from_commit, to_commit)
@@ -273,7 +277,7 @@ class CrossSessionAnalytics:
273
277
 
274
278
  Example:
275
279
  >>> sessions = cross.sessions_for_feature("feature-auth")
276
- >>> print(f"Feature worked on in {len(sessions)} sessions")
280
+ >>> logger.info(f"Feature worked on in {len(sessions)} sessions")
277
281
  """
278
282
  sessions = set()
279
283
 
@@ -320,8 +324,8 @@ class CrossSessionAnalytics:
320
324
 
321
325
  Example:
322
326
  >>> report = cross.feature_cross_session_report("feature-auth")
323
- >>> print(f"Implemented across {len(report.sessions)} sessions")
324
- >>> print(f"Duration: {report.duration_hours:.1f} hours")
327
+ >>> logger.info(f"Implemented across {len(report.sessions)} sessions")
328
+ >>> logger.info(f"Duration: {report.duration_hours:.1f} hours")
325
329
  """
326
330
  sessions = set()
327
331
  commits = set()
@@ -395,7 +399,7 @@ class CrossSessionAnalytics:
395
399
  Example:
396
400
  >>> authors = cross.work_by_author(since_commit="v1.0.0")
397
401
  >>> for email, stats in authors.items():
398
- ... print(f"{email}: {stats['event_count']} events")
402
+ ... logger.info(f"{email}: {stats['event_count']} events")
399
403
  """
400
404
  authors: dict[str, dict[str, Any]] = defaultdict(
401
405
  lambda: {
@@ -476,7 +480,7 @@ class CrossSessionAnalytics:
476
480
 
477
481
  Example:
478
482
  >>> commits = cross.commits_for_session("session-abc")
479
- >>> print(f"Session produced {len(commits)} commits")
483
+ >>> logger.info(f"Session produced {len(commits)} commits")
480
484
  """
481
485
  commits = set()
482
486
 
@@ -1,3 +1,9 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+
5
+ logger = logging.getLogger(__name__)
6
+
1
7
  """
2
8
  Dependency-aware analytics for HtmlGraph.
3
9
 
@@ -9,8 +15,6 @@ Provides advanced graph analysis for project management:
9
15
  - Work prioritization
10
16
  """
11
17
 
12
- from __future__ import annotations
13
-
14
18
  from collections import deque
15
19
  from typing import TYPE_CHECKING
16
20
 
@@ -55,12 +59,12 @@ class DependencyAnalytics:
55
59
  # Find bottlenecks (cached internally for performance)
56
60
  bottlenecks = dep.find_bottlenecks(top_n=5)
57
61
  for bn in bottlenecks:
58
- print(f"{bn.title} blocks {bn.transitive_blocking} features")
62
+ logger.info(f"{bn.title} blocks {bn.transitive_blocking} features")
59
63
 
60
64
  # Get work recommendations (reuses cached data)
61
65
  recs = dep.recommend_next_tasks(agent_count=3)
62
66
  for rec in recs.recommendations:
63
- print(f"Work on: {rec.title} (unlocks {len(rec.unlocks)} features)")
67
+ logger.info(f"Work on: {rec.title} (unlocks {len(rec.unlocks)} features)")
64
68
 
65
69
  # After making graph changes, invalidate cache
66
70
  sdk.features.update(feature_id, status="done")
@@ -201,7 +205,7 @@ class DependencyAnalytics:
201
205
 
202
206
  Example:
203
207
  report = dep.find_parallelizable_work(status="todo")
204
- print(f"Can work on {report.max_parallelism} features in parallel")
208
+ logger.info(f"Can work on {report.max_parallelism} features in parallel")
205
209
  """
206
210
  # Get dependency levels (topological layers)
207
211
  levels = self.dependency_levels(status_filter=[status])
@@ -456,7 +460,7 @@ class DependencyAnalytics:
456
460
  Example:
457
461
  recs = dep.recommend_next_tasks(agent_count=3)
458
462
  for rec in recs.recommendations:
459
- print(f"Work on: {rec.title}")
463
+ logger.info(f"Work on: {rec.title}")
460
464
  """
461
465
  # Get all nodes with target status
462
466
  candidates = [n for n in self.graph.nodes.values() if n.status == status]
@@ -1,3 +1,9 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+
5
+ logger = logging.getLogger(__name__)
6
+
1
7
  """
2
8
  Analytics API for HtmlGraph work type analysis.
3
9
 
@@ -25,8 +31,6 @@ Example:
25
31
  # Returns: 25.5 (% of work spent on maintenance)
26
32
  """
27
33
 
28
- from __future__ import annotations
29
-
30
34
  from datetime import datetime, timezone
31
35
  from typing import TYPE_CHECKING
32
36
 
@@ -97,7 +101,7 @@ class Analytics:
97
101
  Example:
98
102
  >>> analytics = sdk.analytics
99
103
  >>> dist = analytics.work_type_distribution(session_id="session-123")
100
- >>> print(dist)
104
+ >>> logger.info("%s", dist)
101
105
  {
102
106
  "feature-implementation": 45.2,
103
107
  "spike-investigation": 28.3,
@@ -163,11 +167,11 @@ class Analytics:
163
167
 
164
168
  Example:
165
169
  >>> ratio = sdk.analytics.spike_to_feature_ratio(session_id="session-123")
166
- >>> print(f"Spike-to-feature ratio: {ratio:.2f}")
170
+ >>> logger.info(f"Spike-to-feature ratio: {ratio:.2f}")
167
171
  Spike-to-feature ratio: 0.63
168
172
 
169
173
  >>> if ratio > 0.5:
170
- ... print("This was a research-heavy session")
174
+ ... logger.info("This was a research-heavy session")
171
175
  """
172
176
  events = self._get_events(session_id, start_date, end_date)
173
177
 
@@ -221,11 +225,11 @@ class Analytics:
221
225
 
222
226
  Example:
223
227
  >>> burden = sdk.analytics.maintenance_burden(session_id="session-123")
224
- >>> print(f"Maintenance burden: {burden:.1f}%")
228
+ >>> logger.info(f"Maintenance burden: {burden:.1f}%")
225
229
  Maintenance burden: 32.5%
226
230
 
227
231
  >>> if burden > 40:
228
- ... print("⚠️ High maintenance burden - consider addressing technical debt")
232
+ ... logger.info("⚠️ High maintenance burden - consider addressing technical debt")
229
233
  """
230
234
  events = self._get_events(session_id, start_date, end_date)
231
235
 
@@ -276,7 +280,7 @@ class Analytics:
276
280
  >>> spike_sessions = sdk.analytics.get_sessions_by_work_type(
277
281
  ... "spike-investigation"
278
282
  ... )
279
- >>> print(f"Found {len(spike_sessions)} exploratory sessions")
283
+ >>> logger.info(f"Found {len(spike_sessions)} exploratory sessions")
280
284
  """
281
285
  session_nodes = self.sdk.sessions.all()
282
286
  matching_sessions = []
@@ -316,7 +320,7 @@ class Analytics:
316
320
 
317
321
  Example:
318
322
  >>> breakdown = sdk.analytics.calculate_session_work_breakdown("session-123")
319
- >>> print(breakdown)
323
+ >>> logger.info("%s", breakdown)
320
324
  {
321
325
  "feature-implementation": 45,
322
326
  "spike-investigation": 28,
@@ -344,7 +348,7 @@ class Analytics:
344
348
 
345
349
  Example:
346
350
  >>> primary = sdk.analytics.calculate_session_primary_work_type("session-123")
347
- >>> print(f"Primary work type: {primary}")
351
+ >>> logger.info(f"Primary work type: {primary}")
348
352
  Primary work type: spike-investigation
349
353
  """
350
354
  session = self._get_session(session_id)
@@ -399,7 +403,7 @@ class Analytics:
399
403
 
400
404
  Example:
401
405
  >>> metrics = sdk.analytics.transition_time_metrics(session_id="session-123")
402
- >>> print(f"Transition time: {metrics['transition_percent']:.1f}%")
406
+ >>> logger.info(f"Transition time: {metrics['transition_percent']:.1f}%")
403
407
  Transition time: 15.3%
404
408
  """
405
409
  from pathlib import Path
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  """
2
4
  SQLite analytics index for HtmlGraph event logs.
3
5
 
@@ -5,7 +7,6 @@ This is a rebuildable cache/index for fast dashboard queries.
5
7
  The canonical source of truth is the JSONL event log under `.htmlgraph/events/`.
6
8
  """
7
9
 
8
- from __future__ import annotations
9
10
 
10
11
  import json
11
12
  import sqlite3