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/builders/track.py
CHANGED
|
@@ -1,17 +1,28 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
1
3
|
"""
|
|
2
4
|
Track Builder for agent-friendly track creation.
|
|
3
5
|
"""
|
|
4
|
-
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
import re
|
|
5
9
|
from datetime import datetime
|
|
6
10
|
from pathlib import Path
|
|
7
|
-
from typing import TYPE_CHECKING
|
|
8
|
-
import re
|
|
11
|
+
from typing import TYPE_CHECKING, Any, Literal, cast
|
|
9
12
|
|
|
10
13
|
if TYPE_CHECKING:
|
|
11
14
|
from htmlgraph.sdk import SDK
|
|
12
15
|
|
|
13
|
-
from htmlgraph.planning import Track, Spec, Plan, Phase, Task, Requirement, AcceptanceCriterion
|
|
14
16
|
from htmlgraph.ids import generate_id
|
|
17
|
+
from htmlgraph.planning import (
|
|
18
|
+
AcceptanceCriterion,
|
|
19
|
+
Phase,
|
|
20
|
+
Plan,
|
|
21
|
+
Requirement,
|
|
22
|
+
Spec,
|
|
23
|
+
Task,
|
|
24
|
+
Track,
|
|
25
|
+
)
|
|
15
26
|
|
|
16
27
|
|
|
17
28
|
class TrackBuilder:
|
|
@@ -42,24 +53,24 @@ class TrackBuilder:
|
|
|
42
53
|
|
|
43
54
|
def __init__(self, sdk: SDK):
|
|
44
55
|
self.sdk = sdk
|
|
45
|
-
self._title = None
|
|
56
|
+
self._title: str | None = None
|
|
46
57
|
self._description = ""
|
|
47
58
|
self._priority = "medium"
|
|
48
|
-
self._spec_data = {}
|
|
49
|
-
self._plan_phases = []
|
|
59
|
+
self._spec_data: dict[str, Any] = {}
|
|
60
|
+
self._plan_phases: list[tuple[str, list[str]]] = []
|
|
50
61
|
self._consolidated = True # Default: single file
|
|
51
62
|
|
|
52
|
-
def title(self, title: str) ->
|
|
63
|
+
def title(self, title: str) -> TrackBuilder:
|
|
53
64
|
"""Set track title."""
|
|
54
65
|
self._title = title
|
|
55
66
|
return self
|
|
56
67
|
|
|
57
|
-
def description(self, desc: str) ->
|
|
68
|
+
def description(self, desc: str) -> TrackBuilder:
|
|
58
69
|
"""Set track description."""
|
|
59
70
|
self._description = desc
|
|
60
71
|
return self
|
|
61
72
|
|
|
62
|
-
def priority(self, priority: str) ->
|
|
73
|
+
def priority(self, priority: str) -> TrackBuilder:
|
|
63
74
|
"""Set track priority (low/medium/high/critical)."""
|
|
64
75
|
self._priority = priority
|
|
65
76
|
return self
|
|
@@ -68,9 +79,9 @@ class TrackBuilder:
|
|
|
68
79
|
self,
|
|
69
80
|
overview: str = "",
|
|
70
81
|
context: str = "",
|
|
71
|
-
requirements: list = None,
|
|
72
|
-
acceptance_criteria: list = None
|
|
73
|
-
) ->
|
|
82
|
+
requirements: list[Any] | None = None,
|
|
83
|
+
acceptance_criteria: list[Any] | None = None,
|
|
84
|
+
) -> TrackBuilder:
|
|
74
85
|
"""
|
|
75
86
|
Add spec content to track.
|
|
76
87
|
|
|
@@ -84,11 +95,11 @@ class TrackBuilder:
|
|
|
84
95
|
"overview": overview,
|
|
85
96
|
"context": context,
|
|
86
97
|
"requirements": requirements or [],
|
|
87
|
-
"acceptance_criteria": acceptance_criteria or []
|
|
98
|
+
"acceptance_criteria": acceptance_criteria or [],
|
|
88
99
|
}
|
|
89
100
|
return self
|
|
90
101
|
|
|
91
|
-
def with_plan_phases(self, phases: list[tuple[str, list[str]]]) ->
|
|
102
|
+
def with_plan_phases(self, phases: list[tuple[str, list[str]]]) -> TrackBuilder:
|
|
92
103
|
"""
|
|
93
104
|
Add plan phases with tasks.
|
|
94
105
|
|
|
@@ -99,20 +110,28 @@ class TrackBuilder:
|
|
|
99
110
|
self._plan_phases = phases
|
|
100
111
|
return self
|
|
101
112
|
|
|
102
|
-
def separate_files(self) ->
|
|
113
|
+
def separate_files(self) -> TrackBuilder:
|
|
103
114
|
"""Use legacy 3-file format (index.html, spec.html, plan.html)."""
|
|
104
115
|
self._consolidated = False
|
|
105
116
|
return self
|
|
106
117
|
|
|
107
|
-
def consolidated(self) ->
|
|
118
|
+
def consolidated(self) -> TrackBuilder:
|
|
108
119
|
"""Use single-file format (default). Everything in one index.html."""
|
|
109
120
|
self._consolidated = True
|
|
110
121
|
return self
|
|
111
122
|
|
|
112
123
|
def _generate_track_html(self, track: Track, track_dir: Path) -> str:
|
|
113
124
|
"""Generate track index.html content (legacy 3-file format)."""
|
|
114
|
-
spec_link =
|
|
115
|
-
|
|
125
|
+
spec_link = (
|
|
126
|
+
'<li><a href="spec.html">📝 Specification</a></li>'
|
|
127
|
+
if track.has_spec
|
|
128
|
+
else ""
|
|
129
|
+
)
|
|
130
|
+
plan_link = (
|
|
131
|
+
'<li><a href="plan.html">📋 Implementation Plan</a></li>'
|
|
132
|
+
if track.has_plan
|
|
133
|
+
else ""
|
|
134
|
+
)
|
|
116
135
|
|
|
117
136
|
return f'''<!DOCTYPE html>
|
|
118
137
|
<html lang="en">
|
|
@@ -147,13 +166,9 @@ class TrackBuilder:
|
|
|
147
166
|
</html>'''
|
|
148
167
|
|
|
149
168
|
def _generate_consolidated_html(
|
|
150
|
-
self,
|
|
151
|
-
track: Track,
|
|
152
|
-
requirements: list[Requirement],
|
|
153
|
-
phases: list[Phase]
|
|
169
|
+
self, track: Track, requirements: list[Requirement], phases: list[Phase]
|
|
154
170
|
) -> str:
|
|
155
171
|
"""Generate single consolidated HTML containing track, spec, and plan."""
|
|
156
|
-
from datetime import datetime
|
|
157
172
|
|
|
158
173
|
# Build requirements HTML
|
|
159
174
|
req_html = ""
|
|
@@ -167,13 +182,13 @@ class TrackBuilder:
|
|
|
167
182
|
<h4>{status} {req.description}</h4>
|
|
168
183
|
<span class="badge">{req.priority}</span>
|
|
169
184
|
</article>''')
|
|
170
|
-
req_html = f
|
|
185
|
+
req_html = f"""
|
|
171
186
|
<section data-section="requirements" id="requirements">
|
|
172
187
|
<h2>Requirements</h2>
|
|
173
188
|
<div class="requirements-list">
|
|
174
189
|
{"".join(req_items)}
|
|
175
190
|
</div>
|
|
176
|
-
</section>
|
|
191
|
+
</section>"""
|
|
177
192
|
|
|
178
193
|
# Build acceptance criteria HTML
|
|
179
194
|
ac_html = ""
|
|
@@ -182,34 +197,42 @@ class TrackBuilder:
|
|
|
182
197
|
for crit in self._spec_data["acceptance_criteria"]:
|
|
183
198
|
if isinstance(crit, tuple):
|
|
184
199
|
desc, test_case = crit
|
|
185
|
-
test_html = f
|
|
200
|
+
test_html = f" <code>{test_case}</code>" if test_case else ""
|
|
186
201
|
else:
|
|
187
202
|
desc = crit
|
|
188
|
-
test_html =
|
|
189
|
-
ac_items.append(f
|
|
190
|
-
ac_html = f
|
|
203
|
+
test_html = ""
|
|
204
|
+
ac_items.append(f"<li>⏳ {desc}{test_html}</li>")
|
|
205
|
+
ac_html = f"""
|
|
191
206
|
<section data-section="acceptance-criteria" id="acceptance">
|
|
192
207
|
<h2>Acceptance Criteria</h2>
|
|
193
208
|
<ol class="criteria-list">
|
|
194
209
|
{"".join(ac_items)}
|
|
195
210
|
</ol>
|
|
196
|
-
</section>
|
|
211
|
+
</section>"""
|
|
197
212
|
|
|
198
213
|
# Build phases/tasks HTML
|
|
199
214
|
plan_html = ""
|
|
200
215
|
if phases:
|
|
201
216
|
total_tasks = sum(len(p.tasks) for p in phases)
|
|
202
|
-
completed_tasks = sum(
|
|
203
|
-
|
|
217
|
+
completed_tasks = sum(
|
|
218
|
+
sum(1 for t in p.tasks if t.completed) for p in phases
|
|
219
|
+
)
|
|
220
|
+
completion = (
|
|
221
|
+
int((completed_tasks / total_tasks) * 100) if total_tasks > 0 else 0
|
|
222
|
+
)
|
|
204
223
|
|
|
205
224
|
phase_items = []
|
|
206
225
|
for i, phase in enumerate(phases):
|
|
207
226
|
task_items = []
|
|
208
227
|
for task in phase.tasks:
|
|
209
228
|
status_icon = "✅" if task.completed else "○"
|
|
210
|
-
estimate_html =
|
|
229
|
+
estimate_html = (
|
|
230
|
+
f' <span class="estimate">({task.estimate_hours}h)</span>'
|
|
231
|
+
if task.estimate_hours
|
|
232
|
+
else ""
|
|
233
|
+
)
|
|
211
234
|
task_items.append(f'''
|
|
212
|
-
<div data-task="{task.id}" data-status="{
|
|
235
|
+
<div data-task="{task.id}" data-status="{"done" if task.completed else "todo"}">
|
|
213
236
|
<input type="checkbox" {"checked" if task.completed else ""} disabled>
|
|
214
237
|
<div>
|
|
215
238
|
<strong>{status_icon} {task.description}</strong>
|
|
@@ -219,11 +242,11 @@ class TrackBuilder:
|
|
|
219
242
|
|
|
220
243
|
phase_items.append(f'''
|
|
221
244
|
<details {"open" if i == 0 else ""} data-phase="{phase.id}">
|
|
222
|
-
<summary>Phase {i+1}: {phase.name} ({len([t for t in phase.tasks if t.completed])}/{len(phase.tasks)} tasks)</summary>
|
|
245
|
+
<summary>Phase {i + 1}: {phase.name} ({len([t for t in phase.tasks if t.completed])}/{len(phase.tasks)} tasks)</summary>
|
|
223
246
|
{"".join(task_items)}
|
|
224
247
|
</details>''')
|
|
225
248
|
|
|
226
|
-
plan_html = f
|
|
249
|
+
plan_html = f"""
|
|
227
250
|
<section data-section="plan" id="plan">
|
|
228
251
|
<h2>Implementation Plan</h2>
|
|
229
252
|
<div class="progress-container">
|
|
@@ -238,24 +261,24 @@ class TrackBuilder:
|
|
|
238
261
|
<div class="phases-container">
|
|
239
262
|
{"".join(phase_items)}
|
|
240
263
|
</div>
|
|
241
|
-
</section>
|
|
264
|
+
</section>"""
|
|
242
265
|
|
|
243
266
|
# Build overview/context from spec
|
|
244
267
|
overview_html = ""
|
|
245
268
|
context_html = ""
|
|
246
269
|
if self._spec_data:
|
|
247
270
|
if self._spec_data.get("overview"):
|
|
248
|
-
overview_html = f
|
|
271
|
+
overview_html = f"""
|
|
249
272
|
<section data-section="overview" id="overview">
|
|
250
273
|
<h2>Overview</h2>
|
|
251
274
|
<p>{self._spec_data["overview"]}</p>
|
|
252
|
-
</section>
|
|
275
|
+
</section>"""
|
|
253
276
|
if self._spec_data.get("context"):
|
|
254
|
-
context_html = f
|
|
277
|
+
context_html = f"""
|
|
255
278
|
<section data-section="context" id="context">
|
|
256
279
|
<h2>Context</h2>
|
|
257
280
|
<p>{self._spec_data["context"]}</p>
|
|
258
|
-
</section>
|
|
281
|
+
</section>"""
|
|
259
282
|
|
|
260
283
|
# Navigation based on what's present
|
|
261
284
|
nav_items = ['<a href="#top" class="nav-link">Track</a>']
|
|
@@ -264,10 +287,19 @@ class TrackBuilder:
|
|
|
264
287
|
if phases:
|
|
265
288
|
nav_items.append('<a href="#plan" class="nav-link">Plan</a>')
|
|
266
289
|
|
|
267
|
-
nav_html = f
|
|
290
|
+
nav_html = f"""
|
|
268
291
|
<nav class="track-nav">
|
|
269
292
|
{"".join(nav_items)}
|
|
270
|
-
</nav>
|
|
293
|
+
</nav>"""
|
|
294
|
+
|
|
295
|
+
# Map Track status to Node-compatible status for HTML parsing
|
|
296
|
+
status_mapping = {
|
|
297
|
+
"planned": "todo", # Not started
|
|
298
|
+
"active": "in-progress", # In progress
|
|
299
|
+
"completed": "done", # Done
|
|
300
|
+
"abandoned": "blocked", # Blocked/stopped
|
|
301
|
+
}
|
|
302
|
+
node_status = status_mapping.get(track.status, "todo")
|
|
271
303
|
|
|
272
304
|
created_date = datetime.now().strftime("%Y-%m-%d")
|
|
273
305
|
|
|
@@ -510,11 +542,11 @@ class TrackBuilder:
|
|
|
510
542
|
</head>
|
|
511
543
|
<body>
|
|
512
544
|
{nav_html}
|
|
513
|
-
<article id="{track.id}" data-type="track" data-status="{
|
|
545
|
+
<article id="{track.id}" data-type="track" data-status="{node_status}" data-priority="{track.priority}">
|
|
514
546
|
<header id="top">
|
|
515
547
|
<h1>{self._title}</h1>
|
|
516
548
|
<div class="metadata">
|
|
517
|
-
<span class="badge status-{
|
|
549
|
+
<span class="badge status-{node_status}">{track.status.title()}</span>
|
|
518
550
|
<span class="badge priority-{track.priority}">{track.priority.title()} Priority</span>
|
|
519
551
|
<span class="badge">Created: {created_date}</span>
|
|
520
552
|
</div>
|
|
@@ -541,9 +573,9 @@ class TrackBuilder:
|
|
|
541
573
|
id=track_id,
|
|
542
574
|
title=f"Track: {self._title}",
|
|
543
575
|
description=self._description,
|
|
544
|
-
priority=self._priority,
|
|
576
|
+
priority=cast(Literal["low", "medium", "high", "critical"], self._priority),
|
|
545
577
|
has_spec=bool(self._spec_data),
|
|
546
|
-
has_plan=bool(self._plan_phases)
|
|
578
|
+
has_plan=bool(self._plan_phases),
|
|
547
579
|
)
|
|
548
580
|
|
|
549
581
|
# Build requirements list
|
|
@@ -554,11 +586,9 @@ class TrackBuilder:
|
|
|
554
586
|
desc, priority = req
|
|
555
587
|
else:
|
|
556
588
|
desc, priority = req, "must-have"
|
|
557
|
-
requirements.append(
|
|
558
|
-
id=f"req-{i+1}",
|
|
559
|
-
|
|
560
|
-
priority=priority
|
|
561
|
-
))
|
|
589
|
+
requirements.append(
|
|
590
|
+
Requirement(id=f"req-{i + 1}", description=desc, priority=priority)
|
|
591
|
+
)
|
|
562
592
|
|
|
563
593
|
# Build phases list
|
|
564
594
|
phases = []
|
|
@@ -569,36 +599,64 @@ class TrackBuilder:
|
|
|
569
599
|
# Parse estimate from task description
|
|
570
600
|
estimate = None
|
|
571
601
|
if "(" in task_desc and "h)" in task_desc:
|
|
572
|
-
match = re.search(r
|
|
602
|
+
match = re.search(r"\((\d+(?:\.\d+)?)\s*h\)", task_desc)
|
|
573
603
|
if match:
|
|
574
604
|
estimate = float(match.group(1))
|
|
575
|
-
task_desc = re.sub(
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
605
|
+
task_desc = re.sub(
|
|
606
|
+
r"\s*\(\d+(?:\.\d+)?\s*h\)", "", task_desc
|
|
607
|
+
).strip()
|
|
608
|
+
|
|
609
|
+
phase_tasks.append(
|
|
610
|
+
Task(
|
|
611
|
+
id=f"task-{i + 1}-{j + 1}",
|
|
612
|
+
description=task_desc,
|
|
613
|
+
estimate_hours=estimate,
|
|
614
|
+
)
|
|
615
|
+
)
|
|
616
|
+
|
|
617
|
+
phases.append(
|
|
618
|
+
Phase(id=f"phase-{i + 1}", name=phase_name, tasks=phase_tasks)
|
|
619
|
+
)
|
|
582
620
|
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
621
|
+
# Persist features to database from plan phases
|
|
622
|
+
features_created = 0
|
|
623
|
+
if phases:
|
|
624
|
+
for phase in phases:
|
|
625
|
+
for task in phase.tasks:
|
|
626
|
+
# Generate feature ID from task description
|
|
627
|
+
feature_id = generate_id(node_type="feat", title=task.description)
|
|
628
|
+
|
|
629
|
+
# Insert feature into database
|
|
630
|
+
success = self.sdk._db.insert_feature(
|
|
631
|
+
feature_id=feature_id,
|
|
632
|
+
feature_type="task", # Tasks from tracks are features of type "task"
|
|
633
|
+
title=task.description,
|
|
634
|
+
status="todo", # All new tasks start as "todo"
|
|
635
|
+
priority=self._priority, # Inherit priority from track
|
|
636
|
+
assigned_to=None, # No assignment initially
|
|
637
|
+
track_id=track_id,
|
|
638
|
+
description=f"Task from {phase.name}",
|
|
639
|
+
steps_total=0,
|
|
640
|
+
tags=None,
|
|
641
|
+
)
|
|
642
|
+
if success:
|
|
643
|
+
features_created += 1
|
|
588
644
|
|
|
589
645
|
if self._consolidated:
|
|
590
646
|
# Single-file format: everything in one index.html
|
|
591
|
-
track_file =
|
|
647
|
+
track_file = self.sdk._directory / "tracks" / f"{track_id}.html"
|
|
592
648
|
track_file.parent.mkdir(parents=True, exist_ok=True)
|
|
593
649
|
|
|
594
|
-
consolidated_html = self._generate_consolidated_html(
|
|
650
|
+
consolidated_html = self._generate_consolidated_html(
|
|
651
|
+
track, requirements, phases
|
|
652
|
+
)
|
|
595
653
|
track_file.write_text(consolidated_html, encoding="utf-8")
|
|
596
654
|
|
|
597
655
|
print(f"✓ Created track: {track_id} (single file)")
|
|
598
656
|
|
|
599
657
|
else:
|
|
600
658
|
# Legacy 3-file format: index.html, spec.html, plan.html
|
|
601
|
-
track_dir =
|
|
659
|
+
track_dir = self.sdk._directory / "tracks" / track_id
|
|
602
660
|
track_dir.mkdir(parents=True, exist_ok=True)
|
|
603
661
|
|
|
604
662
|
# Generate track index HTML
|
|
@@ -611,7 +669,9 @@ class TrackBuilder:
|
|
|
611
669
|
for crit in self._spec_data.get("acceptance_criteria", []):
|
|
612
670
|
if isinstance(crit, tuple):
|
|
613
671
|
desc, test_case = crit
|
|
614
|
-
criteria.append(
|
|
672
|
+
criteria.append(
|
|
673
|
+
AcceptanceCriterion(description=desc, test_case=test_case)
|
|
674
|
+
)
|
|
615
675
|
else:
|
|
616
676
|
criteria.append(AcceptanceCriterion(description=crit))
|
|
617
677
|
|
|
@@ -622,7 +682,7 @@ class TrackBuilder:
|
|
|
622
682
|
overview=self._spec_data.get("overview", ""),
|
|
623
683
|
context=self._spec_data.get("context", ""),
|
|
624
684
|
requirements=requirements,
|
|
625
|
-
acceptance_criteria=criteria
|
|
685
|
+
acceptance_criteria=criteria,
|
|
626
686
|
)
|
|
627
687
|
(track_dir / "spec.html").write_text(spec.to_html(), encoding="utf-8")
|
|
628
688
|
|
|
@@ -632,7 +692,7 @@ class TrackBuilder:
|
|
|
632
692
|
id=f"{track_id}-plan",
|
|
633
693
|
title=f"{self._title} Implementation Plan",
|
|
634
694
|
track_id=track_id,
|
|
635
|
-
phases=phases
|
|
695
|
+
phases=phases,
|
|
636
696
|
)
|
|
637
697
|
(track_dir / "plan.html").write_text(plan.to_html(), encoding="utf-8")
|
|
638
698
|
|
|
@@ -642,5 +702,21 @@ class TrackBuilder:
|
|
|
642
702
|
if self._plan_phases:
|
|
643
703
|
total_tasks = sum(len(tasks) for _, tasks in self._plan_phases)
|
|
644
704
|
print(f" - Plan with {len(self._plan_phases)} phases, {total_tasks} tasks")
|
|
705
|
+
if features_created > 0:
|
|
706
|
+
print(f" - Persisted {features_created} features to database")
|
|
645
707
|
|
|
646
708
|
return track
|
|
709
|
+
|
|
710
|
+
def save(self) -> Track:
|
|
711
|
+
"""
|
|
712
|
+
Save/create the track (alias for create()).
|
|
713
|
+
|
|
714
|
+
Provides API consistency with other builders.
|
|
715
|
+
|
|
716
|
+
Returns:
|
|
717
|
+
Track object that was created
|
|
718
|
+
|
|
719
|
+
Example:
|
|
720
|
+
track = sdk.tracks.create("My Track").save()
|
|
721
|
+
"""
|
|
722
|
+
return self.create()
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Computational Imperative Guidance System (CIGS)
|
|
3
|
+
|
|
4
|
+
Provides guidance, messaging, and tracking for delegation enforcement in HtmlGraph.
|
|
5
|
+
|
|
6
|
+
Modules:
|
|
7
|
+
- messages_basic: Level 0-1 imperative message templates
|
|
8
|
+
- models: Data models for violations, patterns, and autonomy
|
|
9
|
+
- tracker: Violation tracking and persistence
|
|
10
|
+
- cost: Cost calculation and efficiency metrics
|
|
11
|
+
- patterns: Anti-pattern detection and analysis
|
|
12
|
+
- autonomy: Autonomy level management
|
|
13
|
+
- reporter: Dashboard generation for cost analysis
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from htmlgraph.cigs.autonomy import AutonomyRecommender
|
|
17
|
+
from htmlgraph.cigs.messages_basic import (
|
|
18
|
+
BasicMessageGenerator,
|
|
19
|
+
MessageTemplateLibrary,
|
|
20
|
+
OperationContext,
|
|
21
|
+
ToolCategory,
|
|
22
|
+
classify_operation,
|
|
23
|
+
estimate_costs,
|
|
24
|
+
)
|
|
25
|
+
from htmlgraph.cigs.messaging import (
|
|
26
|
+
ImperativeMessageGenerator,
|
|
27
|
+
PositiveReinforcementGenerator,
|
|
28
|
+
)
|
|
29
|
+
from htmlgraph.cigs.models import (
|
|
30
|
+
AutonomyLevel,
|
|
31
|
+
CostMetrics,
|
|
32
|
+
CostPrediction,
|
|
33
|
+
OperationClassification,
|
|
34
|
+
PatternRecord,
|
|
35
|
+
SessionViolationSummary,
|
|
36
|
+
TokenCost,
|
|
37
|
+
ViolationRecord,
|
|
38
|
+
ViolationType,
|
|
39
|
+
)
|
|
40
|
+
from htmlgraph.cigs.patterns import (
|
|
41
|
+
DetectionResult,
|
|
42
|
+
PatternDetector,
|
|
43
|
+
detect_patterns,
|
|
44
|
+
)
|
|
45
|
+
from htmlgraph.cigs.posttool_analyzer import CIGSPostToolAnalyzer
|
|
46
|
+
from htmlgraph.cigs.reporter import CostReporter
|
|
47
|
+
from htmlgraph.cigs.tracker import ViolationTracker
|
|
48
|
+
|
|
49
|
+
__all__ = [
|
|
50
|
+
# Messages
|
|
51
|
+
"BasicMessageGenerator",
|
|
52
|
+
"PositiveReinforcementGenerator",
|
|
53
|
+
"ImperativeMessageGenerator",
|
|
54
|
+
"MessageTemplateLibrary",
|
|
55
|
+
"OperationContext",
|
|
56
|
+
"ToolCategory",
|
|
57
|
+
"classify_operation",
|
|
58
|
+
"estimate_costs",
|
|
59
|
+
# Models
|
|
60
|
+
"ViolationType",
|
|
61
|
+
"ViolationRecord",
|
|
62
|
+
"SessionViolationSummary",
|
|
63
|
+
"PatternRecord",
|
|
64
|
+
"TokenCost",
|
|
65
|
+
"CostPrediction",
|
|
66
|
+
"OperationClassification",
|
|
67
|
+
"AutonomyLevel",
|
|
68
|
+
"CostMetrics",
|
|
69
|
+
# Autonomy
|
|
70
|
+
"AutonomyRecommender",
|
|
71
|
+
# Patterns
|
|
72
|
+
"PatternDetector",
|
|
73
|
+
"DetectionResult",
|
|
74
|
+
"detect_patterns",
|
|
75
|
+
# Tracker
|
|
76
|
+
"ViolationTracker",
|
|
77
|
+
# PostTool Analysis
|
|
78
|
+
"CIGSPostToolAnalyzer",
|
|
79
|
+
# Reporter
|
|
80
|
+
"CostReporter",
|
|
81
|
+
]
|