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.
- htmlgraph/.htmlgraph/.session-warning-state.json +6 -0
- htmlgraph/.htmlgraph/agents.json +72 -0
- htmlgraph/.htmlgraph/htmlgraph.db +0 -0
- htmlgraph/__init__.py +173 -17
- htmlgraph/__init__.pyi +123 -0
- htmlgraph/agent_detection.py +127 -0
- htmlgraph/agent_registry.py +45 -30
- htmlgraph/agents.py +160 -107
- htmlgraph/analytics/__init__.py +9 -2
- htmlgraph/analytics/cli.py +190 -51
- htmlgraph/analytics/cost_analyzer.py +391 -0
- htmlgraph/analytics/cost_monitor.py +664 -0
- htmlgraph/analytics/cost_reporter.py +675 -0
- htmlgraph/analytics/cross_session.py +617 -0
- htmlgraph/analytics/dependency.py +192 -100
- htmlgraph/analytics/pattern_learning.py +771 -0
- htmlgraph/analytics/session_graph.py +707 -0
- htmlgraph/analytics/strategic/__init__.py +80 -0
- htmlgraph/analytics/strategic/cost_optimizer.py +611 -0
- htmlgraph/analytics/strategic/pattern_detector.py +876 -0
- htmlgraph/analytics/strategic/preference_manager.py +709 -0
- htmlgraph/analytics/strategic/suggestion_engine.py +747 -0
- htmlgraph/analytics/work_type.py +190 -14
- htmlgraph/analytics_index.py +135 -51
- htmlgraph/api/__init__.py +3 -0
- htmlgraph/api/cost_alerts_websocket.py +416 -0
- htmlgraph/api/main.py +2498 -0
- htmlgraph/api/static/htmx.min.js +1 -0
- htmlgraph/api/static/style-redesign.css +1344 -0
- htmlgraph/api/static/style.css +1079 -0
- htmlgraph/api/templates/dashboard-redesign.html +1366 -0
- htmlgraph/api/templates/dashboard.html +794 -0
- htmlgraph/api/templates/partials/activity-feed-hierarchical.html +326 -0
- htmlgraph/api/templates/partials/activity-feed.html +1100 -0
- htmlgraph/api/templates/partials/agents-redesign.html +317 -0
- htmlgraph/api/templates/partials/agents.html +317 -0
- htmlgraph/api/templates/partials/event-traces.html +373 -0
- htmlgraph/api/templates/partials/features-kanban-redesign.html +509 -0
- htmlgraph/api/templates/partials/features.html +578 -0
- htmlgraph/api/templates/partials/metrics-redesign.html +346 -0
- htmlgraph/api/templates/partials/metrics.html +346 -0
- htmlgraph/api/templates/partials/orchestration-redesign.html +443 -0
- htmlgraph/api/templates/partials/orchestration.html +198 -0
- htmlgraph/api/templates/partials/spawners.html +375 -0
- htmlgraph/api/templates/partials/work-items.html +613 -0
- htmlgraph/api/websocket.py +538 -0
- htmlgraph/archive/__init__.py +24 -0
- htmlgraph/archive/bloom.py +234 -0
- htmlgraph/archive/fts.py +297 -0
- htmlgraph/archive/manager.py +583 -0
- htmlgraph/archive/search.py +244 -0
- htmlgraph/atomic_ops.py +560 -0
- htmlgraph/attribute_index.py +208 -0
- htmlgraph/bounded_paths.py +539 -0
- htmlgraph/builders/__init__.py +14 -0
- htmlgraph/builders/base.py +118 -29
- htmlgraph/builders/bug.py +150 -0
- htmlgraph/builders/chore.py +119 -0
- htmlgraph/builders/epic.py +150 -0
- htmlgraph/builders/feature.py +31 -6
- htmlgraph/builders/insight.py +195 -0
- htmlgraph/builders/metric.py +217 -0
- htmlgraph/builders/pattern.py +202 -0
- htmlgraph/builders/phase.py +162 -0
- htmlgraph/builders/spike.py +52 -19
- htmlgraph/builders/track.py +148 -72
- htmlgraph/cigs/__init__.py +81 -0
- htmlgraph/cigs/autonomy.py +385 -0
- htmlgraph/cigs/cost.py +475 -0
- htmlgraph/cigs/messages_basic.py +472 -0
- htmlgraph/cigs/messaging.py +365 -0
- htmlgraph/cigs/models.py +771 -0
- htmlgraph/cigs/pattern_storage.py +427 -0
- htmlgraph/cigs/patterns.py +503 -0
- htmlgraph/cigs/posttool_analyzer.py +234 -0
- htmlgraph/cigs/reporter.py +818 -0
- htmlgraph/cigs/tracker.py +317 -0
- htmlgraph/cli/.htmlgraph/.session-warning-state.json +6 -0
- htmlgraph/cli/.htmlgraph/agents.json +72 -0
- htmlgraph/cli/.htmlgraph/htmlgraph.db +0 -0
- htmlgraph/cli/__init__.py +42 -0
- htmlgraph/cli/__main__.py +6 -0
- htmlgraph/cli/analytics.py +1424 -0
- htmlgraph/cli/base.py +685 -0
- htmlgraph/cli/constants.py +206 -0
- htmlgraph/cli/core.py +954 -0
- htmlgraph/cli/main.py +147 -0
- htmlgraph/cli/models.py +475 -0
- htmlgraph/cli/templates/__init__.py +1 -0
- htmlgraph/cli/templates/cost_dashboard.py +399 -0
- htmlgraph/cli/work/__init__.py +239 -0
- htmlgraph/cli/work/browse.py +115 -0
- htmlgraph/cli/work/features.py +568 -0
- htmlgraph/cli/work/orchestration.py +676 -0
- htmlgraph/cli/work/report.py +728 -0
- htmlgraph/cli/work/sessions.py +466 -0
- htmlgraph/cli/work/snapshot.py +559 -0
- htmlgraph/cli/work/tracks.py +486 -0
- htmlgraph/cli_commands/__init__.py +1 -0
- htmlgraph/cli_commands/feature.py +195 -0
- htmlgraph/cli_framework.py +115 -0
- htmlgraph/collections/__init__.py +18 -0
- htmlgraph/collections/base.py +415 -98
- htmlgraph/collections/bug.py +53 -0
- htmlgraph/collections/chore.py +53 -0
- htmlgraph/collections/epic.py +53 -0
- htmlgraph/collections/feature.py +12 -26
- htmlgraph/collections/insight.py +100 -0
- htmlgraph/collections/metric.py +92 -0
- htmlgraph/collections/pattern.py +97 -0
- htmlgraph/collections/phase.py +53 -0
- htmlgraph/collections/session.py +194 -0
- htmlgraph/collections/spike.py +56 -16
- htmlgraph/collections/task_delegation.py +241 -0
- htmlgraph/collections/todo.py +511 -0
- htmlgraph/collections/traces.py +487 -0
- htmlgraph/config/cost_models.json +56 -0
- htmlgraph/config.py +190 -0
- htmlgraph/context_analytics.py +344 -0
- htmlgraph/converter.py +216 -28
- htmlgraph/cost_analysis/__init__.py +5 -0
- htmlgraph/cost_analysis/analyzer.py +438 -0
- htmlgraph/dashboard.html +2406 -307
- htmlgraph/dashboard.html.backup +6592 -0
- htmlgraph/dashboard.html.bak +7181 -0
- htmlgraph/dashboard.html.bak2 +7231 -0
- htmlgraph/dashboard.html.bak3 +7232 -0
- htmlgraph/db/__init__.py +38 -0
- htmlgraph/db/queries.py +790 -0
- htmlgraph/db/schema.py +1788 -0
- htmlgraph/decorators.py +317 -0
- htmlgraph/dependency_models.py +19 -2
- htmlgraph/deploy.py +142 -125
- htmlgraph/deployment_models.py +474 -0
- htmlgraph/docs/API_REFERENCE.md +841 -0
- htmlgraph/docs/HTTP_API.md +750 -0
- htmlgraph/docs/INTEGRATION_GUIDE.md +752 -0
- htmlgraph/docs/ORCHESTRATION_PATTERNS.md +717 -0
- htmlgraph/docs/README.md +532 -0
- htmlgraph/docs/__init__.py +77 -0
- htmlgraph/docs/docs_version.py +55 -0
- htmlgraph/docs/metadata.py +93 -0
- htmlgraph/docs/migrations.py +232 -0
- htmlgraph/docs/template_engine.py +143 -0
- htmlgraph/docs/templates/_sections/cli_reference.md.j2 +52 -0
- htmlgraph/docs/templates/_sections/core_concepts.md.j2 +29 -0
- htmlgraph/docs/templates/_sections/sdk_basics.md.j2 +69 -0
- htmlgraph/docs/templates/base_agents.md.j2 +78 -0
- htmlgraph/docs/templates/example_user_override.md.j2 +47 -0
- htmlgraph/docs/version_check.py +163 -0
- htmlgraph/edge_index.py +182 -27
- htmlgraph/error_handler.py +544 -0
- htmlgraph/event_log.py +100 -52
- htmlgraph/event_migration.py +13 -4
- htmlgraph/exceptions.py +49 -0
- htmlgraph/file_watcher.py +101 -28
- htmlgraph/find_api.py +75 -63
- htmlgraph/git_events.py +145 -63
- htmlgraph/graph.py +1122 -106
- htmlgraph/hooks/.htmlgraph/.session-warning-state.json +6 -0
- htmlgraph/hooks/.htmlgraph/agents.json +72 -0
- htmlgraph/hooks/.htmlgraph/index.sqlite +0 -0
- htmlgraph/hooks/__init__.py +45 -0
- htmlgraph/hooks/bootstrap.py +169 -0
- htmlgraph/hooks/cigs_pretool_enforcer.py +354 -0
- htmlgraph/hooks/concurrent_sessions.py +208 -0
- htmlgraph/hooks/context.py +350 -0
- htmlgraph/hooks/drift_handler.py +525 -0
- htmlgraph/hooks/event_tracker.py +1314 -0
- htmlgraph/hooks/git_commands.py +175 -0
- htmlgraph/hooks/hooks-config.example.json +12 -0
- htmlgraph/hooks/installer.py +343 -0
- htmlgraph/hooks/orchestrator.py +674 -0
- htmlgraph/hooks/orchestrator_reflector.py +223 -0
- htmlgraph/hooks/post-checkout.sh +28 -0
- htmlgraph/hooks/post-commit.sh +24 -0
- htmlgraph/hooks/post-merge.sh +26 -0
- htmlgraph/hooks/post_tool_use_failure.py +273 -0
- htmlgraph/hooks/post_tool_use_handler.py +257 -0
- htmlgraph/hooks/posttooluse.py +408 -0
- htmlgraph/hooks/pre-commit.sh +94 -0
- htmlgraph/hooks/pre-push.sh +28 -0
- htmlgraph/hooks/pretooluse.py +819 -0
- htmlgraph/hooks/prompt_analyzer.py +637 -0
- htmlgraph/hooks/session_handler.py +668 -0
- htmlgraph/hooks/session_summary.py +395 -0
- htmlgraph/hooks/state_manager.py +504 -0
- htmlgraph/hooks/subagent_detection.py +202 -0
- htmlgraph/hooks/subagent_stop.py +369 -0
- htmlgraph/hooks/task_enforcer.py +255 -0
- htmlgraph/hooks/task_validator.py +177 -0
- htmlgraph/hooks/validator.py +628 -0
- htmlgraph/ids.py +41 -27
- htmlgraph/index.d.ts +286 -0
- htmlgraph/learning.py +767 -0
- htmlgraph/mcp_server.py +69 -23
- htmlgraph/models.py +1586 -87
- htmlgraph/operations/README.md +62 -0
- htmlgraph/operations/__init__.py +79 -0
- htmlgraph/operations/analytics.py +339 -0
- htmlgraph/operations/bootstrap.py +289 -0
- htmlgraph/operations/events.py +244 -0
- htmlgraph/operations/fastapi_server.py +231 -0
- htmlgraph/operations/hooks.py +350 -0
- htmlgraph/operations/initialization.py +597 -0
- htmlgraph/operations/initialization.py.backup +228 -0
- htmlgraph/operations/server.py +303 -0
- htmlgraph/orchestration/__init__.py +58 -0
- htmlgraph/orchestration/claude_launcher.py +179 -0
- htmlgraph/orchestration/command_builder.py +72 -0
- htmlgraph/orchestration/headless_spawner.py +281 -0
- htmlgraph/orchestration/live_events.py +377 -0
- htmlgraph/orchestration/model_selection.py +327 -0
- htmlgraph/orchestration/plugin_manager.py +140 -0
- htmlgraph/orchestration/prompts.py +137 -0
- htmlgraph/orchestration/spawner_event_tracker.py +383 -0
- htmlgraph/orchestration/spawners/__init__.py +16 -0
- htmlgraph/orchestration/spawners/base.py +194 -0
- htmlgraph/orchestration/spawners/claude.py +173 -0
- htmlgraph/orchestration/spawners/codex.py +435 -0
- htmlgraph/orchestration/spawners/copilot.py +294 -0
- htmlgraph/orchestration/spawners/gemini.py +471 -0
- htmlgraph/orchestration/subprocess_runner.py +36 -0
- htmlgraph/orchestration/task_coordination.py +343 -0
- htmlgraph/orchestration.md +563 -0
- htmlgraph/orchestrator-system-prompt-optimized.txt +863 -0
- htmlgraph/orchestrator.py +669 -0
- htmlgraph/orchestrator_config.py +357 -0
- htmlgraph/orchestrator_mode.py +328 -0
- htmlgraph/orchestrator_validator.py +133 -0
- htmlgraph/parallel.py +646 -0
- htmlgraph/parser.py +160 -35
- htmlgraph/path_query.py +608 -0
- htmlgraph/pattern_matcher.py +636 -0
- htmlgraph/planning.py +147 -52
- htmlgraph/pydantic_models.py +476 -0
- htmlgraph/quality_gates.py +350 -0
- htmlgraph/query_builder.py +109 -72
- htmlgraph/query_composer.py +509 -0
- htmlgraph/reflection.py +443 -0
- htmlgraph/refs.py +344 -0
- htmlgraph/repo_hash.py +512 -0
- htmlgraph/repositories/__init__.py +292 -0
- htmlgraph/repositories/analytics_repository.py +455 -0
- htmlgraph/repositories/analytics_repository_standard.py +628 -0
- htmlgraph/repositories/feature_repository.py +581 -0
- htmlgraph/repositories/feature_repository_htmlfile.py +668 -0
- htmlgraph/repositories/feature_repository_memory.py +607 -0
- htmlgraph/repositories/feature_repository_sqlite.py +858 -0
- htmlgraph/repositories/filter_service.py +620 -0
- htmlgraph/repositories/filter_service_standard.py +445 -0
- htmlgraph/repositories/shared_cache.py +621 -0
- htmlgraph/repositories/shared_cache_memory.py +395 -0
- htmlgraph/repositories/track_repository.py +552 -0
- htmlgraph/repositories/track_repository_htmlfile.py +619 -0
- htmlgraph/repositories/track_repository_memory.py +508 -0
- htmlgraph/repositories/track_repository_sqlite.py +711 -0
- htmlgraph/routing.py +8 -19
- htmlgraph/scripts/deploy.py +1 -2
- htmlgraph/sdk/__init__.py +398 -0
- htmlgraph/sdk/__init__.pyi +14 -0
- htmlgraph/sdk/analytics/__init__.py +19 -0
- htmlgraph/sdk/analytics/engine.py +155 -0
- htmlgraph/sdk/analytics/helpers.py +178 -0
- htmlgraph/sdk/analytics/registry.py +109 -0
- htmlgraph/sdk/base.py +484 -0
- htmlgraph/sdk/constants.py +216 -0
- htmlgraph/sdk/core.pyi +308 -0
- htmlgraph/sdk/discovery.py +120 -0
- htmlgraph/sdk/help/__init__.py +12 -0
- htmlgraph/sdk/help/mixin.py +699 -0
- htmlgraph/sdk/mixins/__init__.py +15 -0
- htmlgraph/sdk/mixins/attribution.py +113 -0
- htmlgraph/sdk/mixins/mixin.py +410 -0
- htmlgraph/sdk/operations/__init__.py +12 -0
- htmlgraph/sdk/operations/mixin.py +427 -0
- htmlgraph/sdk/orchestration/__init__.py +17 -0
- htmlgraph/sdk/orchestration/coordinator.py +203 -0
- htmlgraph/sdk/orchestration/spawner.py +204 -0
- htmlgraph/sdk/planning/__init__.py +19 -0
- htmlgraph/sdk/planning/bottlenecks.py +93 -0
- htmlgraph/sdk/planning/mixin.py +211 -0
- htmlgraph/sdk/planning/parallel.py +186 -0
- htmlgraph/sdk/planning/queue.py +210 -0
- htmlgraph/sdk/planning/recommendations.py +87 -0
- htmlgraph/sdk/planning/smart_planning.py +319 -0
- htmlgraph/sdk/session/__init__.py +19 -0
- htmlgraph/sdk/session/continuity.py +57 -0
- htmlgraph/sdk/session/handoff.py +110 -0
- htmlgraph/sdk/session/info.py +309 -0
- htmlgraph/sdk/session/manager.py +103 -0
- htmlgraph/sdk/strategic/__init__.py +26 -0
- htmlgraph/sdk/strategic/mixin.py +563 -0
- htmlgraph/server.py +685 -180
- htmlgraph/services/__init__.py +10 -0
- htmlgraph/services/claiming.py +199 -0
- htmlgraph/session_hooks.py +300 -0
- htmlgraph/session_manager.py +1392 -175
- htmlgraph/session_registry.py +587 -0
- htmlgraph/session_state.py +436 -0
- htmlgraph/session_warning.py +201 -0
- htmlgraph/sessions/__init__.py +23 -0
- htmlgraph/sessions/handoff.py +756 -0
- htmlgraph/setup.py +34 -17
- htmlgraph/spike_index.py +143 -0
- htmlgraph/sync_docs.py +12 -15
- htmlgraph/system_prompts.py +450 -0
- htmlgraph/templates/AGENTS.md.template +366 -0
- htmlgraph/templates/CLAUDE.md.template +97 -0
- htmlgraph/templates/GEMINI.md.template +87 -0
- htmlgraph/templates/orchestration-view.html +350 -0
- htmlgraph/track_builder.py +146 -15
- htmlgraph/track_manager.py +69 -21
- htmlgraph/transcript.py +890 -0
- htmlgraph/transcript_analytics.py +699 -0
- htmlgraph/types.py +323 -0
- htmlgraph/validation.py +115 -0
- htmlgraph/watch.py +8 -5
- htmlgraph/work_type_utils.py +3 -2
- {htmlgraph-0.9.3.data → htmlgraph-0.27.5.data}/data/htmlgraph/dashboard.html +2406 -307
- htmlgraph-0.27.5.data/data/htmlgraph/templates/AGENTS.md.template +366 -0
- htmlgraph-0.27.5.data/data/htmlgraph/templates/CLAUDE.md.template +97 -0
- htmlgraph-0.27.5.data/data/htmlgraph/templates/GEMINI.md.template +87 -0
- {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/METADATA +97 -64
- htmlgraph-0.27.5.dist-info/RECORD +337 -0
- {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/entry_points.txt +1 -1
- htmlgraph/cli.py +0 -2688
- htmlgraph/sdk.py +0 -709
- htmlgraph-0.9.3.dist-info/RECORD +0 -61
- {htmlgraph-0.9.3.data → htmlgraph-0.27.5.data}/data/htmlgraph/styles.css +0 -0
- {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/WHEEL +0 -0
htmlgraph/analytics/cli.py
CHANGED
|
@@ -4,22 +4,24 @@ CLI Analytics Command - Beautiful work type analytics with rich formatting.
|
|
|
4
4
|
This module provides the `htmlgraph analytics` command for analyzing work patterns.
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
import argparse
|
|
8
|
+
from collections.abc import Iterator
|
|
9
|
+
from contextlib import AbstractContextManager, nullcontext
|
|
7
10
|
from pathlib import Path
|
|
8
|
-
|
|
11
|
+
|
|
12
|
+
from rich import box
|
|
9
13
|
from rich.console import Console
|
|
10
|
-
from rich.table import Table
|
|
11
14
|
from rich.panel import Panel
|
|
12
|
-
from rich.
|
|
13
|
-
from rich import box
|
|
14
|
-
from rich.text import Text
|
|
15
|
+
from rich.table import Table
|
|
15
16
|
|
|
16
17
|
from htmlgraph import SDK, WorkType
|
|
17
18
|
from htmlgraph.converter import html_to_session
|
|
18
19
|
|
|
19
20
|
|
|
20
|
-
def cmd_analytics(args):
|
|
21
|
+
def cmd_analytics(args: argparse.Namespace) -> int:
|
|
21
22
|
"""Display work type analytics with beautiful rich formatting."""
|
|
22
23
|
console = Console()
|
|
24
|
+
quiet = getattr(args, "quiet", False)
|
|
23
25
|
|
|
24
26
|
try:
|
|
25
27
|
sdk = SDK(agent=args.agent or "cli")
|
|
@@ -31,13 +33,13 @@ def cmd_analytics(args):
|
|
|
31
33
|
sessions_dir = Path(args.graph_dir) / "sessions"
|
|
32
34
|
|
|
33
35
|
if not sessions_dir.exists():
|
|
34
|
-
console.print(
|
|
36
|
+
console.print(
|
|
37
|
+
"[yellow]No sessions found. Run some work to generate analytics![/yellow]"
|
|
38
|
+
)
|
|
35
39
|
return 0
|
|
36
40
|
|
|
37
41
|
session_files = sorted(
|
|
38
|
-
sessions_dir.glob("*.html"),
|
|
39
|
-
key=lambda p: p.stat().st_mtime,
|
|
40
|
-
reverse=True
|
|
42
|
+
sessions_dir.glob("*.html"), key=lambda p: p.stat().st_mtime, reverse=True
|
|
41
43
|
)
|
|
42
44
|
|
|
43
45
|
if not session_files:
|
|
@@ -47,18 +49,68 @@ def cmd_analytics(args):
|
|
|
47
49
|
# Determine scope
|
|
48
50
|
if args.session_id:
|
|
49
51
|
# Single session analysis
|
|
50
|
-
_display_session_analytics(
|
|
52
|
+
_display_session_analytics(
|
|
53
|
+
console, sdk, args.session_id, args.graph_dir, quiet=quiet
|
|
54
|
+
)
|
|
51
55
|
elif args.recent:
|
|
52
56
|
# Recent sessions
|
|
53
|
-
_display_recent_sessions(
|
|
57
|
+
_display_recent_sessions(
|
|
58
|
+
console, sdk, session_files[: args.recent], args.graph_dir, quiet=quiet
|
|
59
|
+
)
|
|
54
60
|
else:
|
|
55
61
|
# Project-wide overview
|
|
56
|
-
_display_project_analytics(
|
|
62
|
+
_display_project_analytics(
|
|
63
|
+
console, sdk, session_files, args.graph_dir, quiet=quiet
|
|
64
|
+
)
|
|
57
65
|
|
|
58
66
|
return 0
|
|
59
67
|
|
|
60
68
|
|
|
61
|
-
def
|
|
69
|
+
def _status_context(
|
|
70
|
+
console: Console, quiet: bool, message: str
|
|
71
|
+
) -> AbstractContextManager[object]:
|
|
72
|
+
if quiet:
|
|
73
|
+
return nullcontext()
|
|
74
|
+
return console.status(message)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _iter_with_progress(
|
|
78
|
+
console: Console, quiet: bool, items: list[Path], description: str
|
|
79
|
+
) -> Iterator[Path]:
|
|
80
|
+
if quiet:
|
|
81
|
+
for item in items:
|
|
82
|
+
yield item
|
|
83
|
+
return
|
|
84
|
+
try:
|
|
85
|
+
from rich.progress import (
|
|
86
|
+
BarColumn,
|
|
87
|
+
Progress,
|
|
88
|
+
SpinnerColumn,
|
|
89
|
+
TextColumn,
|
|
90
|
+
TimeElapsedColumn,
|
|
91
|
+
)
|
|
92
|
+
except Exception:
|
|
93
|
+
for item in items:
|
|
94
|
+
yield item
|
|
95
|
+
return
|
|
96
|
+
|
|
97
|
+
with Progress(
|
|
98
|
+
SpinnerColumn(),
|
|
99
|
+
TextColumn("{task.description}"),
|
|
100
|
+
BarColumn(),
|
|
101
|
+
TimeElapsedColumn(),
|
|
102
|
+
console=console,
|
|
103
|
+
transient=True,
|
|
104
|
+
) as progress:
|
|
105
|
+
task_id = progress.add_task(description, total=len(items))
|
|
106
|
+
for item in items:
|
|
107
|
+
yield item
|
|
108
|
+
progress.advance(task_id)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _display_session_analytics(
|
|
112
|
+
console: Console, sdk: "SDK", session_id: str, graph_dir: str, quiet: bool
|
|
113
|
+
) -> None:
|
|
62
114
|
"""Display analytics for a single session."""
|
|
63
115
|
from htmlgraph.converter import html_to_session
|
|
64
116
|
|
|
@@ -69,18 +121,23 @@ def _display_session_analytics(console: Console, sdk: SDK, session_id: str, grap
|
|
|
69
121
|
return
|
|
70
122
|
|
|
71
123
|
try:
|
|
72
|
-
session
|
|
124
|
+
with _status_context(console, quiet, "Loading session data..."):
|
|
125
|
+
session = html_to_session(session_path)
|
|
73
126
|
except Exception as e:
|
|
74
127
|
console.print(f"[red]Error loading session: {e}[/red]")
|
|
75
128
|
return
|
|
76
129
|
|
|
77
130
|
# Get analytics
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
131
|
+
with _status_context(console, quiet, "Computing session analytics..."):
|
|
132
|
+
dist = sdk.analytics.work_type_distribution(session_id=session_id)
|
|
133
|
+
ratio = sdk.analytics.spike_to_feature_ratio(session_id=session_id)
|
|
134
|
+
burden = sdk.analytics.maintenance_burden(session_id=session_id)
|
|
135
|
+
primary = sdk.analytics.calculate_session_primary_work_type(session_id)
|
|
136
|
+
breakdown = sdk.analytics.calculate_session_work_breakdown(session_id)
|
|
137
|
+
total_events = sum(breakdown.values()) if breakdown else session.event_count
|
|
138
|
+
transition_metrics = sdk.analytics.transition_time_metrics(
|
|
139
|
+
session_id=session_id
|
|
140
|
+
)
|
|
84
141
|
|
|
85
142
|
# Header panel
|
|
86
143
|
header = Panel(
|
|
@@ -88,7 +145,7 @@ def _display_session_analytics(console: Console, sdk: SDK, session_id: str, grap
|
|
|
88
145
|
f"Agent: {session.agent} | Status: {session.status}\n"
|
|
89
146
|
f"Started: {session.started_at.strftime('%Y-%m-%d %H:%M')} | Events: {total_events}",
|
|
90
147
|
title="📊 Session Analytics",
|
|
91
|
-
border_style="cyan"
|
|
148
|
+
border_style="cyan",
|
|
92
149
|
)
|
|
93
150
|
console.print(header)
|
|
94
151
|
console.print()
|
|
@@ -138,16 +195,45 @@ def _display_session_analytics(console: Console, sdk: SDK, session_id: str, grap
|
|
|
138
195
|
burden_label = "[green]Low[/green]"
|
|
139
196
|
metrics.add_row("Maintenance Burden:", f"{burden_text} {burden_label}")
|
|
140
197
|
|
|
198
|
+
# Add transition time metrics
|
|
199
|
+
if transition_metrics.get("total_minutes", 0) > 0:
|
|
200
|
+
trans_pct = transition_metrics["transition_percent"]
|
|
201
|
+
trans_mins = transition_metrics["transition_minutes"]
|
|
202
|
+
feat_mins = transition_metrics["feature_minutes"]
|
|
203
|
+
|
|
204
|
+
# Format transition time
|
|
205
|
+
if trans_pct > 30:
|
|
206
|
+
trans_label = "[yellow]High - Lots of context switching[/yellow]"
|
|
207
|
+
elif trans_pct > 15:
|
|
208
|
+
trans_label = "[cyan]Moderate - Normal transitions[/cyan]"
|
|
209
|
+
else:
|
|
210
|
+
trans_label = "[green]Low - Focused work[/green]"
|
|
211
|
+
|
|
212
|
+
metrics.add_row("", "")
|
|
213
|
+
metrics.add_row(
|
|
214
|
+
"Transition Time:",
|
|
215
|
+
f"{trans_pct:.1f}% ({trans_mins:.0f} min) - {trans_label}",
|
|
216
|
+
)
|
|
217
|
+
metrics.add_row("Feature Work Time:", f"{feat_mins:.0f} minutes")
|
|
218
|
+
|
|
141
219
|
console.print(Panel(metrics, title="📈 Key Metrics", border_style="green"))
|
|
142
220
|
|
|
143
221
|
|
|
144
|
-
def _display_recent_sessions(
|
|
222
|
+
def _display_recent_sessions(
|
|
223
|
+
console: Console,
|
|
224
|
+
sdk: "SDK",
|
|
225
|
+
session_files: list[Path],
|
|
226
|
+
graph_dir: str,
|
|
227
|
+
quiet: bool,
|
|
228
|
+
) -> None:
|
|
145
229
|
"""Display analytics for recent sessions."""
|
|
146
|
-
console.print(
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
230
|
+
console.print(
|
|
231
|
+
Panel(
|
|
232
|
+
f"[bold cyan]Analyzing {len(session_files)} Recent Sessions[/bold cyan]",
|
|
233
|
+
title="📊 Recent Sessions Analytics",
|
|
234
|
+
border_style="cyan",
|
|
235
|
+
)
|
|
236
|
+
)
|
|
151
237
|
console.print()
|
|
152
238
|
|
|
153
239
|
# Sessions table
|
|
@@ -159,20 +245,26 @@ def _display_recent_sessions(console: Console, sdk: SDK, session_files: list, gr
|
|
|
159
245
|
table.add_column("Primary Type", style="yellow")
|
|
160
246
|
table.add_column("Spike Ratio", justify="right")
|
|
161
247
|
|
|
162
|
-
for session_path in
|
|
248
|
+
for session_path in _iter_with_progress(
|
|
249
|
+
console, quiet, session_files, "Processing sessions"
|
|
250
|
+
):
|
|
163
251
|
try:
|
|
164
252
|
session = html_to_session(session_path)
|
|
165
253
|
session_id = session.id
|
|
166
254
|
|
|
167
255
|
# Get metrics
|
|
168
|
-
primary =
|
|
256
|
+
primary = (
|
|
257
|
+
sdk.analytics.calculate_session_primary_work_type(session_id) or "-"
|
|
258
|
+
)
|
|
169
259
|
ratio = sdk.analytics.spike_to_feature_ratio(session_id=session_id)
|
|
170
260
|
breakdown = sdk.analytics.calculate_session_work_breakdown(session_id)
|
|
171
261
|
total_events = sum(breakdown.values()) if breakdown else session.event_count
|
|
172
262
|
|
|
173
263
|
# Format primary type
|
|
174
264
|
if primary and len(primary) > 20:
|
|
175
|
-
primary = primary.replace("-implementation", "").replace(
|
|
265
|
+
primary = primary.replace("-implementation", "").replace(
|
|
266
|
+
"-investigation", ""
|
|
267
|
+
)
|
|
176
268
|
|
|
177
269
|
# Format ratio
|
|
178
270
|
ratio_str = f"{ratio:.2f}" if ratio > 0 else "-"
|
|
@@ -180,10 +272,10 @@ def _display_recent_sessions(console: Console, sdk: SDK, session_files: list, gr
|
|
|
180
272
|
table.add_row(
|
|
181
273
|
session_id[:30] + "..." if len(session_id) > 30 else session_id,
|
|
182
274
|
session.agent,
|
|
183
|
-
session.started_at.strftime(
|
|
275
|
+
session.started_at.strftime("%m-%d %H:%M"),
|
|
184
276
|
str(total_events),
|
|
185
277
|
primary,
|
|
186
|
-
ratio_str
|
|
278
|
+
ratio_str,
|
|
187
279
|
)
|
|
188
280
|
except Exception as e:
|
|
189
281
|
console.print(f"[dim red]Error loading {session_path.name}: {e}[/dim red]")
|
|
@@ -192,20 +284,30 @@ def _display_recent_sessions(console: Console, sdk: SDK, session_files: list, gr
|
|
|
192
284
|
console.print(table)
|
|
193
285
|
|
|
194
286
|
|
|
195
|
-
def _display_project_analytics(
|
|
287
|
+
def _display_project_analytics(
|
|
288
|
+
console: Console,
|
|
289
|
+
sdk: "SDK",
|
|
290
|
+
session_files: list[Path],
|
|
291
|
+
graph_dir: str,
|
|
292
|
+
quiet: bool,
|
|
293
|
+
) -> None:
|
|
196
294
|
"""Display project-wide analytics."""
|
|
197
|
-
console.print(
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
295
|
+
console.print(
|
|
296
|
+
Panel(
|
|
297
|
+
f"[bold cyan]Project-Wide Analytics[/bold cyan]\n"
|
|
298
|
+
f"Analyzing {len(session_files)} total sessions",
|
|
299
|
+
title="📊 HtmlGraph Project Analytics",
|
|
300
|
+
border_style="cyan",
|
|
301
|
+
)
|
|
302
|
+
)
|
|
203
303
|
console.print()
|
|
204
304
|
|
|
205
305
|
# Get project-wide metrics
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
306
|
+
with _status_context(console, quiet, "Computing project analytics..."):
|
|
307
|
+
all_dist = sdk.analytics.work_type_distribution()
|
|
308
|
+
all_ratio = sdk.analytics.spike_to_feature_ratio()
|
|
309
|
+
all_burden = sdk.analytics.maintenance_burden()
|
|
310
|
+
all_transition = sdk.analytics.transition_time_metrics()
|
|
209
311
|
|
|
210
312
|
# Work distribution table
|
|
211
313
|
if all_dist:
|
|
@@ -214,7 +316,9 @@ def _display_project_analytics(console: Console, sdk: SDK, session_files: list,
|
|
|
214
316
|
table.add_column("Percentage", justify="right", style="green")
|
|
215
317
|
table.add_column("Bar", style="magenta", min_width=50)
|
|
216
318
|
|
|
217
|
-
for work_type, pct in sorted(
|
|
319
|
+
for work_type, pct in sorted(
|
|
320
|
+
all_dist.items(), key=lambda x: x[1], reverse=True
|
|
321
|
+
):
|
|
218
322
|
bar_length = int(pct / 2) # Scale to 50 chars max
|
|
219
323
|
bar = "█" * bar_length
|
|
220
324
|
table.add_row(work_type, f"{pct:.1f}%", bar)
|
|
@@ -253,14 +357,38 @@ def _display_project_analytics(console: Console, sdk: SDK, session_files: list,
|
|
|
253
357
|
burden_desc = "[green]Low - Mostly New Development[/green]"
|
|
254
358
|
|
|
255
359
|
metrics.add_row("Maintenance Burden:", f"{burden_text} - {burden_desc}")
|
|
360
|
+
metrics.add_row("", "")
|
|
361
|
+
|
|
362
|
+
# Transition Time metrics
|
|
363
|
+
if all_transition.get("total_minutes", 0) > 0:
|
|
364
|
+
trans_pct = all_transition["transition_percent"]
|
|
365
|
+
trans_mins = all_transition["transition_minutes"]
|
|
366
|
+
all_transition["feature_minutes"]
|
|
367
|
+
total_mins = all_transition["total_minutes"]
|
|
368
|
+
|
|
369
|
+
if trans_pct > 30:
|
|
370
|
+
trans_desc = "[yellow]⚠️ High Context Switching Overhead[/yellow]"
|
|
371
|
+
elif trans_pct > 15:
|
|
372
|
+
trans_desc = "[cyan]Moderate Transition Time[/cyan]"
|
|
373
|
+
else:
|
|
374
|
+
trans_desc = "[green]Low - Focused Development[/green]"
|
|
256
375
|
|
|
257
|
-
|
|
376
|
+
metrics.add_row(
|
|
377
|
+
"Transition Time:",
|
|
378
|
+
f"{trans_pct:.1f}% ({trans_mins:.0f}m of {total_mins:.0f}m) - {trans_desc}",
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
console.print(
|
|
382
|
+
Panel(metrics, title="📈 Project Health Metrics", border_style="green")
|
|
383
|
+
)
|
|
258
384
|
console.print()
|
|
259
385
|
|
|
260
386
|
# Session type breakdown
|
|
261
387
|
spike_sessions = sdk.analytics.get_sessions_by_work_type(WorkType.SPIKE.value)
|
|
262
388
|
feature_sessions = sdk.analytics.get_sessions_by_work_type(WorkType.FEATURE.value)
|
|
263
|
-
maintenance_sessions = sdk.analytics.get_sessions_by_work_type(
|
|
389
|
+
maintenance_sessions = sdk.analytics.get_sessions_by_work_type(
|
|
390
|
+
WorkType.MAINTENANCE.value
|
|
391
|
+
)
|
|
264
392
|
|
|
265
393
|
session_table = Table(title="Session Types", box=box.SIMPLE)
|
|
266
394
|
session_table.add_column("Session Type", style="cyan")
|
|
@@ -277,18 +405,29 @@ def _display_project_analytics(console: Console, sdk: SDK, session_files: list,
|
|
|
277
405
|
console.print("[bold]Recent Sessions:[/bold]")
|
|
278
406
|
recent_files = session_files[:5]
|
|
279
407
|
|
|
280
|
-
for session_path in
|
|
408
|
+
for session_path in _iter_with_progress(
|
|
409
|
+
console, quiet, recent_files, "Loading recent sessions"
|
|
410
|
+
):
|
|
281
411
|
try:
|
|
282
412
|
session = html_to_session(session_path)
|
|
283
|
-
primary =
|
|
413
|
+
primary = (
|
|
414
|
+
sdk.analytics.calculate_session_primary_work_type(session.id)
|
|
415
|
+
or "unknown"
|
|
416
|
+
)
|
|
284
417
|
|
|
285
418
|
# Shorten work type
|
|
286
419
|
if primary != "unknown":
|
|
287
|
-
primary = primary.replace("-implementation", "").replace(
|
|
420
|
+
primary = primary.replace("-implementation", "").replace(
|
|
421
|
+
"-investigation", ""
|
|
422
|
+
)
|
|
288
423
|
|
|
289
|
-
console.print(
|
|
424
|
+
console.print(
|
|
425
|
+
f" • [cyan]{session.id[:40]}[/cyan] - {session.agent} - [yellow]{primary}[/yellow]"
|
|
426
|
+
)
|
|
290
427
|
except Exception:
|
|
291
428
|
continue
|
|
292
429
|
|
|
293
430
|
console.print()
|
|
294
|
-
console.print(
|
|
431
|
+
console.print(
|
|
432
|
+
"[dim]Run 'htmlgraph analytics --recent 10' for detailed recent session analysis[/dim]"
|
|
433
|
+
)
|