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,204 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Spawner utilities for creating subagent prompts.
|
|
3
|
+
|
|
4
|
+
Provides session context information needed for orchestration.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import TYPE_CHECKING, Any
|
|
11
|
+
|
|
12
|
+
if TYPE_CHECKING:
|
|
13
|
+
from htmlgraph.analytics import DependencyAnalytics
|
|
14
|
+
from htmlgraph.collections.feature import FeatureCollection
|
|
15
|
+
from htmlgraph.collections.session import SessionCollection
|
|
16
|
+
from htmlgraph.sdk import SDK as SDK_TYPE
|
|
17
|
+
from htmlgraph.types import SessionStartInfo
|
|
18
|
+
else:
|
|
19
|
+
SDK_TYPE = "SDK" # type: ignore[misc,assignment]
|
|
20
|
+
SessionStartInfo = dict # type: ignore[misc,assignment]
|
|
21
|
+
FeatureCollection = Any # type: ignore[misc,assignment]
|
|
22
|
+
SessionCollection = Any # type: ignore[misc,assignment]
|
|
23
|
+
DependencyAnalytics = Any # type: ignore[misc,assignment]
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class SessionInfoMixin:
|
|
27
|
+
"""
|
|
28
|
+
Mixin providing session start information for orchestration.
|
|
29
|
+
|
|
30
|
+
Used by orchestrator to gather context for subagent spawning.
|
|
31
|
+
|
|
32
|
+
This mixin is used by SDK class which has these attributes.
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
_directory: Path
|
|
36
|
+
features: FeatureCollection
|
|
37
|
+
sessions: SessionCollection
|
|
38
|
+
dep_analytics: DependencyAnalytics
|
|
39
|
+
|
|
40
|
+
def get_status(self) -> dict[str, Any]:
|
|
41
|
+
"""Get project status. Implemented by SDK."""
|
|
42
|
+
raise NotImplementedError("Implemented by SDK")
|
|
43
|
+
|
|
44
|
+
def get_active_work_item(self) -> dict[str, Any] | None:
|
|
45
|
+
"""Get active work item. Implemented by SDK."""
|
|
46
|
+
raise NotImplementedError("Implemented by SDK")
|
|
47
|
+
|
|
48
|
+
def get_session_start_info(
|
|
49
|
+
self,
|
|
50
|
+
include_git_log: bool = True,
|
|
51
|
+
git_log_count: int = 5,
|
|
52
|
+
analytics_top_n: int = 3,
|
|
53
|
+
analytics_max_agents: int = 3,
|
|
54
|
+
) -> SessionStartInfo:
|
|
55
|
+
"""
|
|
56
|
+
Get comprehensive session start information in a single call.
|
|
57
|
+
|
|
58
|
+
Consolidates all information needed for session start into one method,
|
|
59
|
+
reducing context usage from 6+ tool calls to 1.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
include_git_log: Include recent git commits (default: True)
|
|
63
|
+
git_log_count: Number of recent commits to include (default: 5)
|
|
64
|
+
analytics_top_n: Number of bottlenecks/recommendations (default: 3)
|
|
65
|
+
analytics_max_agents: Max agents for parallel work analysis (default: 3)
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Dict with comprehensive session start context:
|
|
69
|
+
- status: Project status (nodes, collections, WIP)
|
|
70
|
+
- active_work: Current active work item (if any)
|
|
71
|
+
- features: List of features with status
|
|
72
|
+
- sessions: Recent sessions
|
|
73
|
+
- git_log: Recent commits (if include_git_log=True)
|
|
74
|
+
- analytics: Strategic insights (bottlenecks, recommendations, parallel)
|
|
75
|
+
|
|
76
|
+
Note:
|
|
77
|
+
Returns empty dict {} if session context unavailable.
|
|
78
|
+
Always check for expected keys before accessing.
|
|
79
|
+
|
|
80
|
+
Example:
|
|
81
|
+
>>> sdk = SDK(agent="claude")
|
|
82
|
+
>>> info = sdk.get_session_start_info()
|
|
83
|
+
>>> logger.info(f"Project: {info['status']['total_nodes']} nodes")
|
|
84
|
+
>>> logger.info(f"WIP: {info['status']['in_progress_count']}")
|
|
85
|
+
>>> if info.get('active_work'):
|
|
86
|
+
... logger.info(f"Active: {info['active_work']['title']}")
|
|
87
|
+
|
|
88
|
+
See also:
|
|
89
|
+
status: Get project status only
|
|
90
|
+
features.list_all: Get all features
|
|
91
|
+
dep_analytics.recommend_next_tasks: Get recommendations only
|
|
92
|
+
"""
|
|
93
|
+
# Build result dictionary incrementally, then cast at return
|
|
94
|
+
result: dict[str, Any] = {}
|
|
95
|
+
|
|
96
|
+
try:
|
|
97
|
+
# 1. Project status
|
|
98
|
+
status = self.get_status()
|
|
99
|
+
result["status"] = status
|
|
100
|
+
|
|
101
|
+
# 2. Active work item
|
|
102
|
+
active_work = self.get_active_work_item()
|
|
103
|
+
if active_work:
|
|
104
|
+
result["active_work"] = active_work
|
|
105
|
+
|
|
106
|
+
# 3. All features
|
|
107
|
+
features = self.features.list_all()
|
|
108
|
+
result["features"] = [
|
|
109
|
+
{
|
|
110
|
+
"id": f.id,
|
|
111
|
+
"title": f.title,
|
|
112
|
+
"status": f.status,
|
|
113
|
+
"priority": getattr(f, "priority", "medium"),
|
|
114
|
+
"steps_total": len(f.steps) if hasattr(f, "steps") else 0,
|
|
115
|
+
"steps_completed": sum(1 for s in f.steps if s.completed)
|
|
116
|
+
if hasattr(f, "steps")
|
|
117
|
+
else 0,
|
|
118
|
+
}
|
|
119
|
+
for f in features
|
|
120
|
+
]
|
|
121
|
+
|
|
122
|
+
# 4. Recent sessions
|
|
123
|
+
sessions = self.sessions.list_all()
|
|
124
|
+
result["sessions"] = [
|
|
125
|
+
{
|
|
126
|
+
"id": s.id,
|
|
127
|
+
"agent": getattr(s, "agent", "unknown"),
|
|
128
|
+
"status": s.status,
|
|
129
|
+
"event_count": getattr(s.properties, "event_count", 0)
|
|
130
|
+
if hasattr(s, "properties")
|
|
131
|
+
else 0,
|
|
132
|
+
}
|
|
133
|
+
for s in sessions[:5] # Last 5 sessions
|
|
134
|
+
]
|
|
135
|
+
|
|
136
|
+
# 5. Git log (optional)
|
|
137
|
+
if include_git_log:
|
|
138
|
+
import subprocess
|
|
139
|
+
|
|
140
|
+
try:
|
|
141
|
+
git_output = subprocess.check_output(
|
|
142
|
+
[
|
|
143
|
+
"git",
|
|
144
|
+
"log",
|
|
145
|
+
f"-{git_log_count}",
|
|
146
|
+
"--oneline",
|
|
147
|
+
"--no-decorate",
|
|
148
|
+
],
|
|
149
|
+
cwd=self._directory.parent,
|
|
150
|
+
stderr=subprocess.DEVNULL,
|
|
151
|
+
text=True,
|
|
152
|
+
)
|
|
153
|
+
result["git_log"] = git_output.strip().split("\n")
|
|
154
|
+
except Exception:
|
|
155
|
+
# Git not available or not a git repo
|
|
156
|
+
result["git_log"] = []
|
|
157
|
+
|
|
158
|
+
# 6. Strategic analytics
|
|
159
|
+
try:
|
|
160
|
+
bottlenecks = self.dep_analytics.find_bottlenecks(top_n=analytics_top_n)
|
|
161
|
+
recommendations = self.dep_analytics.recommend_next_tasks(
|
|
162
|
+
agent_count=1, lookahead=analytics_top_n
|
|
163
|
+
)
|
|
164
|
+
parallel_work = self.dep_analytics.find_parallelizable_work()
|
|
165
|
+
|
|
166
|
+
# Convert to serializable dicts for JSON response
|
|
167
|
+
result["analytics"] = {
|
|
168
|
+
"bottlenecks": [
|
|
169
|
+
{
|
|
170
|
+
"id": b.id,
|
|
171
|
+
"title": b.title,
|
|
172
|
+
"weighted_impact": b.weighted_impact,
|
|
173
|
+
}
|
|
174
|
+
for b in bottlenecks
|
|
175
|
+
],
|
|
176
|
+
"recommendations": [
|
|
177
|
+
{"id": r.id, "title": r.title, "score": r.score}
|
|
178
|
+
for r in recommendations.recommendations
|
|
179
|
+
]
|
|
180
|
+
if hasattr(recommendations, "recommendations")
|
|
181
|
+
else [],
|
|
182
|
+
"parallel": {
|
|
183
|
+
"max_parallelism": parallel_work.max_parallelism,
|
|
184
|
+
"levels": len(parallel_work.levels)
|
|
185
|
+
if hasattr(parallel_work, "levels")
|
|
186
|
+
else 0,
|
|
187
|
+
},
|
|
188
|
+
}
|
|
189
|
+
except Exception:
|
|
190
|
+
# Analytics not available
|
|
191
|
+
result["analytics"] = {
|
|
192
|
+
"bottlenecks": [],
|
|
193
|
+
"recommendations": [],
|
|
194
|
+
"parallel": {
|
|
195
|
+
"max_parallelism": 0,
|
|
196
|
+
"levels": 0,
|
|
197
|
+
},
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
except Exception:
|
|
201
|
+
# Return empty dict on any error - type ignore since we're returning partial dict
|
|
202
|
+
return {} # type: ignore[return-value,typeddict-item]
|
|
203
|
+
|
|
204
|
+
return result # type: ignore[return-value,typeddict-item]
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Planning module for SDK - Strategic planning and work recommendations.
|
|
3
|
+
|
|
4
|
+
Provides methods for:
|
|
5
|
+
- Bottleneck identification
|
|
6
|
+
- Parallel work detection
|
|
7
|
+
- Smart recommendations
|
|
8
|
+
- Risk assessment
|
|
9
|
+
- Impact analysis
|
|
10
|
+
- Work queue management
|
|
11
|
+
- Planning spike creation
|
|
12
|
+
- Track creation from plans
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
from __future__ import annotations
|
|
16
|
+
|
|
17
|
+
from htmlgraph.sdk.planning.mixin import PlanningMixin
|
|
18
|
+
|
|
19
|
+
__all__ = ["PlanningMixin"]
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""Bottleneck identification for planning."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from htmlgraph.types import BottleneckDict
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def find_bottlenecks(sdk: Any, top_n: int = 5) -> list[BottleneckDict]:
|
|
12
|
+
"""
|
|
13
|
+
Identify tasks blocking the most downstream work.
|
|
14
|
+
|
|
15
|
+
Note: Prefer using sdk.dep_analytics.find_bottlenecks() directly.
|
|
16
|
+
This method exists for backward compatibility.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
sdk: SDK instance
|
|
20
|
+
top_n: Maximum number of bottlenecks to return
|
|
21
|
+
|
|
22
|
+
Returns:
|
|
23
|
+
List of bottleneck tasks with impact metrics
|
|
24
|
+
|
|
25
|
+
Example:
|
|
26
|
+
>>> sdk = SDK(agent="claude")
|
|
27
|
+
>>> # Preferred approach
|
|
28
|
+
>>> bottlenecks = sdk.dep_analytics.find_bottlenecks(top_n=3)
|
|
29
|
+
>>> # Or via SDK (backward compatibility)
|
|
30
|
+
>>> bottlenecks = sdk.find_bottlenecks(top_n=3)
|
|
31
|
+
>>> for bn in bottlenecks:
|
|
32
|
+
... logger.info(f"{bn['title']} blocks {bn['blocks_count']} tasks")
|
|
33
|
+
"""
|
|
34
|
+
bottlenecks = sdk.dep_analytics.find_bottlenecks(top_n=top_n)
|
|
35
|
+
|
|
36
|
+
# Convert to agent-friendly dict format for backward compatibility
|
|
37
|
+
return [
|
|
38
|
+
{
|
|
39
|
+
"id": bn.id,
|
|
40
|
+
"title": bn.title,
|
|
41
|
+
"status": bn.status,
|
|
42
|
+
"priority": bn.priority,
|
|
43
|
+
"blocks_count": bn.transitive_blocking,
|
|
44
|
+
"impact_score": bn.weighted_impact,
|
|
45
|
+
"blocked_tasks": bn.blocked_nodes[:5],
|
|
46
|
+
}
|
|
47
|
+
for bn in bottlenecks
|
|
48
|
+
]
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def assess_risks(sdk: Any) -> dict[str, Any]:
|
|
52
|
+
"""
|
|
53
|
+
Assess dependency-related risks in the project.
|
|
54
|
+
|
|
55
|
+
Note: Prefer using sdk.dep_analytics.assess_dependency_risk() directly.
|
|
56
|
+
This method exists for backward compatibility.
|
|
57
|
+
|
|
58
|
+
Identifies single points of failure, circular dependencies,
|
|
59
|
+
and orphaned tasks.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
sdk: SDK instance
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Dict with risk assessment results
|
|
66
|
+
|
|
67
|
+
Example:
|
|
68
|
+
>>> sdk = SDK(agent="claude")
|
|
69
|
+
>>> # Preferred approach
|
|
70
|
+
>>> risk = sdk.dep_analytics.assess_dependency_risk()
|
|
71
|
+
>>> # Or via SDK (backward compatibility)
|
|
72
|
+
>>> risks = sdk.assess_risks()
|
|
73
|
+
>>> if risks['high_risk_count'] > 0:
|
|
74
|
+
... logger.info(f"Warning: {risks['high_risk_count']} high-risk tasks")
|
|
75
|
+
"""
|
|
76
|
+
risk = sdk.dep_analytics.assess_dependency_risk()
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
"high_risk_count": len(risk.high_risk),
|
|
80
|
+
"high_risk_tasks": [
|
|
81
|
+
{
|
|
82
|
+
"id": node.id,
|
|
83
|
+
"title": node.title,
|
|
84
|
+
"risk_score": node.risk_score,
|
|
85
|
+
"risk_factors": [f.description for f in node.risk_factors],
|
|
86
|
+
}
|
|
87
|
+
for node in risk.high_risk
|
|
88
|
+
],
|
|
89
|
+
"circular_dependencies": risk.circular_dependencies,
|
|
90
|
+
"orphaned_count": len(risk.orphaned_nodes),
|
|
91
|
+
"orphaned_tasks": risk.orphaned_nodes[:5],
|
|
92
|
+
"recommendations": risk.recommendations,
|
|
93
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
"""Planning mixin for SDK - integrates all planning functionality."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING, Any
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from htmlgraph.models import Node
|
|
9
|
+
from htmlgraph.types import BottleneckDict
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class PlanningMixin:
|
|
13
|
+
"""
|
|
14
|
+
Mixin class providing planning and recommendation methods to SDK.
|
|
15
|
+
|
|
16
|
+
This mixin delegates to specialized planning modules for:
|
|
17
|
+
- Bottleneck identification (bottlenecks.py)
|
|
18
|
+
- Parallel work detection (parallel.py)
|
|
19
|
+
- Smart recommendations (recommendations.py)
|
|
20
|
+
- Work queue management (queue.py)
|
|
21
|
+
- Planning spike creation (smart_planning.py)
|
|
22
|
+
- Track creation from plans (smart_planning.py)
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
# =========================================================================
|
|
26
|
+
# Strategic Planning & Analytics (Agent-Friendly Interface)
|
|
27
|
+
# =========================================================================
|
|
28
|
+
|
|
29
|
+
def find_bottlenecks(self, top_n: int = 5) -> list[BottleneckDict]:
|
|
30
|
+
"""
|
|
31
|
+
Identify tasks blocking the most downstream work.
|
|
32
|
+
|
|
33
|
+
Delegates to sdk.planning.bottlenecks.find_bottlenecks()
|
|
34
|
+
"""
|
|
35
|
+
from htmlgraph.sdk.planning.bottlenecks import find_bottlenecks
|
|
36
|
+
|
|
37
|
+
return find_bottlenecks(self, top_n=top_n) # type: ignore[arg-type]
|
|
38
|
+
|
|
39
|
+
def get_parallel_work(self, max_agents: int = 5) -> dict[str, Any]:
|
|
40
|
+
"""
|
|
41
|
+
Find tasks that can be worked on simultaneously.
|
|
42
|
+
|
|
43
|
+
Delegates to sdk.planning.parallel.get_parallel_work()
|
|
44
|
+
"""
|
|
45
|
+
from htmlgraph.sdk.planning.parallel import get_parallel_work
|
|
46
|
+
|
|
47
|
+
return get_parallel_work(self, max_agents=max_agents) # type: ignore[arg-type]
|
|
48
|
+
|
|
49
|
+
def recommend_next_work(self, agent_count: int = 1) -> list[dict[str, Any]]:
|
|
50
|
+
"""
|
|
51
|
+
Get smart recommendations for what to work on next.
|
|
52
|
+
|
|
53
|
+
Delegates to sdk.planning.recommendations.recommend_next_work()
|
|
54
|
+
"""
|
|
55
|
+
from htmlgraph.sdk.planning.recommendations import recommend_next_work
|
|
56
|
+
|
|
57
|
+
return recommend_next_work(self, agent_count=agent_count) # type: ignore[arg-type]
|
|
58
|
+
|
|
59
|
+
def assess_risks(self) -> dict[str, Any]:
|
|
60
|
+
"""
|
|
61
|
+
Assess dependency-related risks in the project.
|
|
62
|
+
|
|
63
|
+
Delegates to sdk.planning.bottlenecks.assess_risks()
|
|
64
|
+
"""
|
|
65
|
+
from htmlgraph.sdk.planning.bottlenecks import assess_risks
|
|
66
|
+
|
|
67
|
+
return assess_risks(self) # type: ignore[arg-type]
|
|
68
|
+
|
|
69
|
+
def analyze_impact(self, node_id: str) -> dict[str, Any]:
|
|
70
|
+
"""
|
|
71
|
+
Analyze the impact of completing a specific task.
|
|
72
|
+
|
|
73
|
+
Delegates to sdk.planning.recommendations.analyze_impact()
|
|
74
|
+
"""
|
|
75
|
+
from htmlgraph.sdk.planning.recommendations import analyze_impact
|
|
76
|
+
|
|
77
|
+
return analyze_impact(self, node_id) # type: ignore[arg-type]
|
|
78
|
+
|
|
79
|
+
def get_work_queue(
|
|
80
|
+
self, agent_id: str | None = None, limit: int = 10, min_score: float = 0.0
|
|
81
|
+
) -> list[dict[str, Any]]:
|
|
82
|
+
"""
|
|
83
|
+
Get prioritized work queue showing recommended work, active work, and dependencies.
|
|
84
|
+
|
|
85
|
+
Delegates to sdk.planning.queue.get_work_queue()
|
|
86
|
+
"""
|
|
87
|
+
from htmlgraph.sdk.planning.queue import get_work_queue
|
|
88
|
+
|
|
89
|
+
return get_work_queue(self, agent_id=agent_id, limit=limit, min_score=min_score) # type: ignore[arg-type]
|
|
90
|
+
|
|
91
|
+
def work_next(
|
|
92
|
+
self,
|
|
93
|
+
agent_id: str | None = None,
|
|
94
|
+
auto_claim: bool = False,
|
|
95
|
+
min_score: float = 0.0,
|
|
96
|
+
) -> Node | None:
|
|
97
|
+
"""
|
|
98
|
+
Get the next best task for an agent using smart routing.
|
|
99
|
+
|
|
100
|
+
Delegates to sdk.planning.queue.work_next()
|
|
101
|
+
"""
|
|
102
|
+
from htmlgraph.sdk.planning.queue import work_next
|
|
103
|
+
|
|
104
|
+
return work_next(
|
|
105
|
+
self, agent_id=agent_id, auto_claim=auto_claim, min_score=min_score
|
|
106
|
+
) # type: ignore[arg-type]
|
|
107
|
+
|
|
108
|
+
# =========================================================================
|
|
109
|
+
# Planning Workflow Integration
|
|
110
|
+
# =========================================================================
|
|
111
|
+
|
|
112
|
+
def start_planning_spike(
|
|
113
|
+
self,
|
|
114
|
+
title: str,
|
|
115
|
+
context: str = "",
|
|
116
|
+
timebox_hours: float = 4.0,
|
|
117
|
+
auto_start: bool = True,
|
|
118
|
+
) -> Node:
|
|
119
|
+
"""
|
|
120
|
+
Create a planning spike to research and design before implementation.
|
|
121
|
+
|
|
122
|
+
Delegates to sdk.planning.smart_planning.start_planning_spike()
|
|
123
|
+
"""
|
|
124
|
+
from htmlgraph.sdk.planning.smart_planning import start_planning_spike
|
|
125
|
+
|
|
126
|
+
return start_planning_spike(
|
|
127
|
+
self,
|
|
128
|
+
title=title,
|
|
129
|
+
context=context,
|
|
130
|
+
timebox_hours=timebox_hours,
|
|
131
|
+
auto_start=auto_start,
|
|
132
|
+
) # type: ignore[arg-type]
|
|
133
|
+
|
|
134
|
+
def create_track_from_plan(
|
|
135
|
+
self,
|
|
136
|
+
title: str,
|
|
137
|
+
description: str,
|
|
138
|
+
spike_id: str | None = None,
|
|
139
|
+
priority: str = "high",
|
|
140
|
+
requirements: list[str | tuple[str, str]] | None = None,
|
|
141
|
+
phases: list[tuple[str, list[str]]] | None = None,
|
|
142
|
+
) -> dict[str, Any]:
|
|
143
|
+
"""
|
|
144
|
+
Create a track with spec and plan from planning results.
|
|
145
|
+
|
|
146
|
+
Delegates to sdk.planning.smart_planning.create_track_from_plan()
|
|
147
|
+
"""
|
|
148
|
+
from htmlgraph.sdk.planning.smart_planning import create_track_from_plan
|
|
149
|
+
|
|
150
|
+
return create_track_from_plan(
|
|
151
|
+
self, # type: ignore[arg-type]
|
|
152
|
+
title=title,
|
|
153
|
+
description=description,
|
|
154
|
+
spike_id=spike_id,
|
|
155
|
+
priority=priority,
|
|
156
|
+
requirements=requirements,
|
|
157
|
+
phases=phases,
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
def smart_plan(
|
|
161
|
+
self,
|
|
162
|
+
description: str,
|
|
163
|
+
create_spike: bool = True,
|
|
164
|
+
timebox_hours: float = 4.0,
|
|
165
|
+
research_completed: bool = False,
|
|
166
|
+
research_findings: dict[str, Any] | None = None,
|
|
167
|
+
) -> dict[str, Any]:
|
|
168
|
+
"""
|
|
169
|
+
Smart planning workflow: analyzes project context and creates spike or track.
|
|
170
|
+
|
|
171
|
+
Delegates to sdk.planning.smart_planning.smart_plan()
|
|
172
|
+
"""
|
|
173
|
+
from htmlgraph.sdk.planning.smart_planning import smart_plan
|
|
174
|
+
|
|
175
|
+
return smart_plan(
|
|
176
|
+
self, # type: ignore[arg-type]
|
|
177
|
+
description=description,
|
|
178
|
+
create_spike=create_spike,
|
|
179
|
+
timebox_hours=timebox_hours,
|
|
180
|
+
research_completed=research_completed,
|
|
181
|
+
research_findings=research_findings,
|
|
182
|
+
)
|
|
183
|
+
|
|
184
|
+
def plan_parallel_work(
|
|
185
|
+
self,
|
|
186
|
+
max_agents: int = 5,
|
|
187
|
+
shared_files: list[str] | None = None,
|
|
188
|
+
) -> dict[str, Any]:
|
|
189
|
+
"""
|
|
190
|
+
Plan and prepare parallel work execution.
|
|
191
|
+
|
|
192
|
+
Delegates to sdk.planning.parallel.plan_parallel_work()
|
|
193
|
+
"""
|
|
194
|
+
from htmlgraph.sdk.planning.parallel import plan_parallel_work
|
|
195
|
+
|
|
196
|
+
return plan_parallel_work(
|
|
197
|
+
self, max_agents=max_agents, shared_files=shared_files
|
|
198
|
+
) # type: ignore[arg-type]
|
|
199
|
+
|
|
200
|
+
def aggregate_parallel_results(
|
|
201
|
+
self,
|
|
202
|
+
agent_ids: list[str],
|
|
203
|
+
) -> dict[str, Any]:
|
|
204
|
+
"""
|
|
205
|
+
Aggregate results from parallel agent execution.
|
|
206
|
+
|
|
207
|
+
Delegates to sdk.planning.parallel.aggregate_parallel_results()
|
|
208
|
+
"""
|
|
209
|
+
from htmlgraph.sdk.planning.parallel import aggregate_parallel_results
|
|
210
|
+
|
|
211
|
+
return aggregate_parallel_results(self, agent_ids=agent_ids) # type: ignore[arg-type]
|