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
|
@@ -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}")
|