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.
Files changed (331) hide show
  1. htmlgraph/.htmlgraph/.session-warning-state.json +6 -0
  2. htmlgraph/.htmlgraph/agents.json +72 -0
  3. htmlgraph/.htmlgraph/htmlgraph.db +0 -0
  4. htmlgraph/__init__.py +173 -17
  5. htmlgraph/__init__.pyi +123 -0
  6. htmlgraph/agent_detection.py +127 -0
  7. htmlgraph/agent_registry.py +45 -30
  8. htmlgraph/agents.py +160 -107
  9. htmlgraph/analytics/__init__.py +9 -2
  10. htmlgraph/analytics/cli.py +190 -51
  11. htmlgraph/analytics/cost_analyzer.py +391 -0
  12. htmlgraph/analytics/cost_monitor.py +664 -0
  13. htmlgraph/analytics/cost_reporter.py +675 -0
  14. htmlgraph/analytics/cross_session.py +617 -0
  15. htmlgraph/analytics/dependency.py +192 -100
  16. htmlgraph/analytics/pattern_learning.py +771 -0
  17. htmlgraph/analytics/session_graph.py +707 -0
  18. htmlgraph/analytics/strategic/__init__.py +80 -0
  19. htmlgraph/analytics/strategic/cost_optimizer.py +611 -0
  20. htmlgraph/analytics/strategic/pattern_detector.py +876 -0
  21. htmlgraph/analytics/strategic/preference_manager.py +709 -0
  22. htmlgraph/analytics/strategic/suggestion_engine.py +747 -0
  23. htmlgraph/analytics/work_type.py +190 -14
  24. htmlgraph/analytics_index.py +135 -51
  25. htmlgraph/api/__init__.py +3 -0
  26. htmlgraph/api/cost_alerts_websocket.py +416 -0
  27. htmlgraph/api/main.py +2498 -0
  28. htmlgraph/api/static/htmx.min.js +1 -0
  29. htmlgraph/api/static/style-redesign.css +1344 -0
  30. htmlgraph/api/static/style.css +1079 -0
  31. htmlgraph/api/templates/dashboard-redesign.html +1366 -0
  32. htmlgraph/api/templates/dashboard.html +794 -0
  33. htmlgraph/api/templates/partials/activity-feed-hierarchical.html +326 -0
  34. htmlgraph/api/templates/partials/activity-feed.html +1100 -0
  35. htmlgraph/api/templates/partials/agents-redesign.html +317 -0
  36. htmlgraph/api/templates/partials/agents.html +317 -0
  37. htmlgraph/api/templates/partials/event-traces.html +373 -0
  38. htmlgraph/api/templates/partials/features-kanban-redesign.html +509 -0
  39. htmlgraph/api/templates/partials/features.html +578 -0
  40. htmlgraph/api/templates/partials/metrics-redesign.html +346 -0
  41. htmlgraph/api/templates/partials/metrics.html +346 -0
  42. htmlgraph/api/templates/partials/orchestration-redesign.html +443 -0
  43. htmlgraph/api/templates/partials/orchestration.html +198 -0
  44. htmlgraph/api/templates/partials/spawners.html +375 -0
  45. htmlgraph/api/templates/partials/work-items.html +613 -0
  46. htmlgraph/api/websocket.py +538 -0
  47. htmlgraph/archive/__init__.py +24 -0
  48. htmlgraph/archive/bloom.py +234 -0
  49. htmlgraph/archive/fts.py +297 -0
  50. htmlgraph/archive/manager.py +583 -0
  51. htmlgraph/archive/search.py +244 -0
  52. htmlgraph/atomic_ops.py +560 -0
  53. htmlgraph/attribute_index.py +208 -0
  54. htmlgraph/bounded_paths.py +539 -0
  55. htmlgraph/builders/__init__.py +14 -0
  56. htmlgraph/builders/base.py +118 -29
  57. htmlgraph/builders/bug.py +150 -0
  58. htmlgraph/builders/chore.py +119 -0
  59. htmlgraph/builders/epic.py +150 -0
  60. htmlgraph/builders/feature.py +31 -6
  61. htmlgraph/builders/insight.py +195 -0
  62. htmlgraph/builders/metric.py +217 -0
  63. htmlgraph/builders/pattern.py +202 -0
  64. htmlgraph/builders/phase.py +162 -0
  65. htmlgraph/builders/spike.py +52 -19
  66. htmlgraph/builders/track.py +148 -72
  67. htmlgraph/cigs/__init__.py +81 -0
  68. htmlgraph/cigs/autonomy.py +385 -0
  69. htmlgraph/cigs/cost.py +475 -0
  70. htmlgraph/cigs/messages_basic.py +472 -0
  71. htmlgraph/cigs/messaging.py +365 -0
  72. htmlgraph/cigs/models.py +771 -0
  73. htmlgraph/cigs/pattern_storage.py +427 -0
  74. htmlgraph/cigs/patterns.py +503 -0
  75. htmlgraph/cigs/posttool_analyzer.py +234 -0
  76. htmlgraph/cigs/reporter.py +818 -0
  77. htmlgraph/cigs/tracker.py +317 -0
  78. htmlgraph/cli/.htmlgraph/.session-warning-state.json +6 -0
  79. htmlgraph/cli/.htmlgraph/agents.json +72 -0
  80. htmlgraph/cli/.htmlgraph/htmlgraph.db +0 -0
  81. htmlgraph/cli/__init__.py +42 -0
  82. htmlgraph/cli/__main__.py +6 -0
  83. htmlgraph/cli/analytics.py +1424 -0
  84. htmlgraph/cli/base.py +685 -0
  85. htmlgraph/cli/constants.py +206 -0
  86. htmlgraph/cli/core.py +954 -0
  87. htmlgraph/cli/main.py +147 -0
  88. htmlgraph/cli/models.py +475 -0
  89. htmlgraph/cli/templates/__init__.py +1 -0
  90. htmlgraph/cli/templates/cost_dashboard.py +399 -0
  91. htmlgraph/cli/work/__init__.py +239 -0
  92. htmlgraph/cli/work/browse.py +115 -0
  93. htmlgraph/cli/work/features.py +568 -0
  94. htmlgraph/cli/work/orchestration.py +676 -0
  95. htmlgraph/cli/work/report.py +728 -0
  96. htmlgraph/cli/work/sessions.py +466 -0
  97. htmlgraph/cli/work/snapshot.py +559 -0
  98. htmlgraph/cli/work/tracks.py +486 -0
  99. htmlgraph/cli_commands/__init__.py +1 -0
  100. htmlgraph/cli_commands/feature.py +195 -0
  101. htmlgraph/cli_framework.py +115 -0
  102. htmlgraph/collections/__init__.py +18 -0
  103. htmlgraph/collections/base.py +415 -98
  104. htmlgraph/collections/bug.py +53 -0
  105. htmlgraph/collections/chore.py +53 -0
  106. htmlgraph/collections/epic.py +53 -0
  107. htmlgraph/collections/feature.py +12 -26
  108. htmlgraph/collections/insight.py +100 -0
  109. htmlgraph/collections/metric.py +92 -0
  110. htmlgraph/collections/pattern.py +97 -0
  111. htmlgraph/collections/phase.py +53 -0
  112. htmlgraph/collections/session.py +194 -0
  113. htmlgraph/collections/spike.py +56 -16
  114. htmlgraph/collections/task_delegation.py +241 -0
  115. htmlgraph/collections/todo.py +511 -0
  116. htmlgraph/collections/traces.py +487 -0
  117. htmlgraph/config/cost_models.json +56 -0
  118. htmlgraph/config.py +190 -0
  119. htmlgraph/context_analytics.py +344 -0
  120. htmlgraph/converter.py +216 -28
  121. htmlgraph/cost_analysis/__init__.py +5 -0
  122. htmlgraph/cost_analysis/analyzer.py +438 -0
  123. htmlgraph/dashboard.html +2406 -307
  124. htmlgraph/dashboard.html.backup +6592 -0
  125. htmlgraph/dashboard.html.bak +7181 -0
  126. htmlgraph/dashboard.html.bak2 +7231 -0
  127. htmlgraph/dashboard.html.bak3 +7232 -0
  128. htmlgraph/db/__init__.py +38 -0
  129. htmlgraph/db/queries.py +790 -0
  130. htmlgraph/db/schema.py +1788 -0
  131. htmlgraph/decorators.py +317 -0
  132. htmlgraph/dependency_models.py +19 -2
  133. htmlgraph/deploy.py +142 -125
  134. htmlgraph/deployment_models.py +474 -0
  135. htmlgraph/docs/API_REFERENCE.md +841 -0
  136. htmlgraph/docs/HTTP_API.md +750 -0
  137. htmlgraph/docs/INTEGRATION_GUIDE.md +752 -0
  138. htmlgraph/docs/ORCHESTRATION_PATTERNS.md +717 -0
  139. htmlgraph/docs/README.md +532 -0
  140. htmlgraph/docs/__init__.py +77 -0
  141. htmlgraph/docs/docs_version.py +55 -0
  142. htmlgraph/docs/metadata.py +93 -0
  143. htmlgraph/docs/migrations.py +232 -0
  144. htmlgraph/docs/template_engine.py +143 -0
  145. htmlgraph/docs/templates/_sections/cli_reference.md.j2 +52 -0
  146. htmlgraph/docs/templates/_sections/core_concepts.md.j2 +29 -0
  147. htmlgraph/docs/templates/_sections/sdk_basics.md.j2 +69 -0
  148. htmlgraph/docs/templates/base_agents.md.j2 +78 -0
  149. htmlgraph/docs/templates/example_user_override.md.j2 +47 -0
  150. htmlgraph/docs/version_check.py +163 -0
  151. htmlgraph/edge_index.py +182 -27
  152. htmlgraph/error_handler.py +544 -0
  153. htmlgraph/event_log.py +100 -52
  154. htmlgraph/event_migration.py +13 -4
  155. htmlgraph/exceptions.py +49 -0
  156. htmlgraph/file_watcher.py +101 -28
  157. htmlgraph/find_api.py +75 -63
  158. htmlgraph/git_events.py +145 -63
  159. htmlgraph/graph.py +1122 -106
  160. htmlgraph/hooks/.htmlgraph/.session-warning-state.json +6 -0
  161. htmlgraph/hooks/.htmlgraph/agents.json +72 -0
  162. htmlgraph/hooks/.htmlgraph/index.sqlite +0 -0
  163. htmlgraph/hooks/__init__.py +45 -0
  164. htmlgraph/hooks/bootstrap.py +169 -0
  165. htmlgraph/hooks/cigs_pretool_enforcer.py +354 -0
  166. htmlgraph/hooks/concurrent_sessions.py +208 -0
  167. htmlgraph/hooks/context.py +350 -0
  168. htmlgraph/hooks/drift_handler.py +525 -0
  169. htmlgraph/hooks/event_tracker.py +1314 -0
  170. htmlgraph/hooks/git_commands.py +175 -0
  171. htmlgraph/hooks/hooks-config.example.json +12 -0
  172. htmlgraph/hooks/installer.py +343 -0
  173. htmlgraph/hooks/orchestrator.py +674 -0
  174. htmlgraph/hooks/orchestrator_reflector.py +223 -0
  175. htmlgraph/hooks/post-checkout.sh +28 -0
  176. htmlgraph/hooks/post-commit.sh +24 -0
  177. htmlgraph/hooks/post-merge.sh +26 -0
  178. htmlgraph/hooks/post_tool_use_failure.py +273 -0
  179. htmlgraph/hooks/post_tool_use_handler.py +257 -0
  180. htmlgraph/hooks/posttooluse.py +408 -0
  181. htmlgraph/hooks/pre-commit.sh +94 -0
  182. htmlgraph/hooks/pre-push.sh +28 -0
  183. htmlgraph/hooks/pretooluse.py +819 -0
  184. htmlgraph/hooks/prompt_analyzer.py +637 -0
  185. htmlgraph/hooks/session_handler.py +668 -0
  186. htmlgraph/hooks/session_summary.py +395 -0
  187. htmlgraph/hooks/state_manager.py +504 -0
  188. htmlgraph/hooks/subagent_detection.py +202 -0
  189. htmlgraph/hooks/subagent_stop.py +369 -0
  190. htmlgraph/hooks/task_enforcer.py +255 -0
  191. htmlgraph/hooks/task_validator.py +177 -0
  192. htmlgraph/hooks/validator.py +628 -0
  193. htmlgraph/ids.py +41 -27
  194. htmlgraph/index.d.ts +286 -0
  195. htmlgraph/learning.py +767 -0
  196. htmlgraph/mcp_server.py +69 -23
  197. htmlgraph/models.py +1586 -87
  198. htmlgraph/operations/README.md +62 -0
  199. htmlgraph/operations/__init__.py +79 -0
  200. htmlgraph/operations/analytics.py +339 -0
  201. htmlgraph/operations/bootstrap.py +289 -0
  202. htmlgraph/operations/events.py +244 -0
  203. htmlgraph/operations/fastapi_server.py +231 -0
  204. htmlgraph/operations/hooks.py +350 -0
  205. htmlgraph/operations/initialization.py +597 -0
  206. htmlgraph/operations/initialization.py.backup +228 -0
  207. htmlgraph/operations/server.py +303 -0
  208. htmlgraph/orchestration/__init__.py +58 -0
  209. htmlgraph/orchestration/claude_launcher.py +179 -0
  210. htmlgraph/orchestration/command_builder.py +72 -0
  211. htmlgraph/orchestration/headless_spawner.py +281 -0
  212. htmlgraph/orchestration/live_events.py +377 -0
  213. htmlgraph/orchestration/model_selection.py +327 -0
  214. htmlgraph/orchestration/plugin_manager.py +140 -0
  215. htmlgraph/orchestration/prompts.py +137 -0
  216. htmlgraph/orchestration/spawner_event_tracker.py +383 -0
  217. htmlgraph/orchestration/spawners/__init__.py +16 -0
  218. htmlgraph/orchestration/spawners/base.py +194 -0
  219. htmlgraph/orchestration/spawners/claude.py +173 -0
  220. htmlgraph/orchestration/spawners/codex.py +435 -0
  221. htmlgraph/orchestration/spawners/copilot.py +294 -0
  222. htmlgraph/orchestration/spawners/gemini.py +471 -0
  223. htmlgraph/orchestration/subprocess_runner.py +36 -0
  224. htmlgraph/orchestration/task_coordination.py +343 -0
  225. htmlgraph/orchestration.md +563 -0
  226. htmlgraph/orchestrator-system-prompt-optimized.txt +863 -0
  227. htmlgraph/orchestrator.py +669 -0
  228. htmlgraph/orchestrator_config.py +357 -0
  229. htmlgraph/orchestrator_mode.py +328 -0
  230. htmlgraph/orchestrator_validator.py +133 -0
  231. htmlgraph/parallel.py +646 -0
  232. htmlgraph/parser.py +160 -35
  233. htmlgraph/path_query.py +608 -0
  234. htmlgraph/pattern_matcher.py +636 -0
  235. htmlgraph/planning.py +147 -52
  236. htmlgraph/pydantic_models.py +476 -0
  237. htmlgraph/quality_gates.py +350 -0
  238. htmlgraph/query_builder.py +109 -72
  239. htmlgraph/query_composer.py +509 -0
  240. htmlgraph/reflection.py +443 -0
  241. htmlgraph/refs.py +344 -0
  242. htmlgraph/repo_hash.py +512 -0
  243. htmlgraph/repositories/__init__.py +292 -0
  244. htmlgraph/repositories/analytics_repository.py +455 -0
  245. htmlgraph/repositories/analytics_repository_standard.py +628 -0
  246. htmlgraph/repositories/feature_repository.py +581 -0
  247. htmlgraph/repositories/feature_repository_htmlfile.py +668 -0
  248. htmlgraph/repositories/feature_repository_memory.py +607 -0
  249. htmlgraph/repositories/feature_repository_sqlite.py +858 -0
  250. htmlgraph/repositories/filter_service.py +620 -0
  251. htmlgraph/repositories/filter_service_standard.py +445 -0
  252. htmlgraph/repositories/shared_cache.py +621 -0
  253. htmlgraph/repositories/shared_cache_memory.py +395 -0
  254. htmlgraph/repositories/track_repository.py +552 -0
  255. htmlgraph/repositories/track_repository_htmlfile.py +619 -0
  256. htmlgraph/repositories/track_repository_memory.py +508 -0
  257. htmlgraph/repositories/track_repository_sqlite.py +711 -0
  258. htmlgraph/routing.py +8 -19
  259. htmlgraph/scripts/deploy.py +1 -2
  260. htmlgraph/sdk/__init__.py +398 -0
  261. htmlgraph/sdk/__init__.pyi +14 -0
  262. htmlgraph/sdk/analytics/__init__.py +19 -0
  263. htmlgraph/sdk/analytics/engine.py +155 -0
  264. htmlgraph/sdk/analytics/helpers.py +178 -0
  265. htmlgraph/sdk/analytics/registry.py +109 -0
  266. htmlgraph/sdk/base.py +484 -0
  267. htmlgraph/sdk/constants.py +216 -0
  268. htmlgraph/sdk/core.pyi +308 -0
  269. htmlgraph/sdk/discovery.py +120 -0
  270. htmlgraph/sdk/help/__init__.py +12 -0
  271. htmlgraph/sdk/help/mixin.py +699 -0
  272. htmlgraph/sdk/mixins/__init__.py +15 -0
  273. htmlgraph/sdk/mixins/attribution.py +113 -0
  274. htmlgraph/sdk/mixins/mixin.py +410 -0
  275. htmlgraph/sdk/operations/__init__.py +12 -0
  276. htmlgraph/sdk/operations/mixin.py +427 -0
  277. htmlgraph/sdk/orchestration/__init__.py +17 -0
  278. htmlgraph/sdk/orchestration/coordinator.py +203 -0
  279. htmlgraph/sdk/orchestration/spawner.py +204 -0
  280. htmlgraph/sdk/planning/__init__.py +19 -0
  281. htmlgraph/sdk/planning/bottlenecks.py +93 -0
  282. htmlgraph/sdk/planning/mixin.py +211 -0
  283. htmlgraph/sdk/planning/parallel.py +186 -0
  284. htmlgraph/sdk/planning/queue.py +210 -0
  285. htmlgraph/sdk/planning/recommendations.py +87 -0
  286. htmlgraph/sdk/planning/smart_planning.py +319 -0
  287. htmlgraph/sdk/session/__init__.py +19 -0
  288. htmlgraph/sdk/session/continuity.py +57 -0
  289. htmlgraph/sdk/session/handoff.py +110 -0
  290. htmlgraph/sdk/session/info.py +309 -0
  291. htmlgraph/sdk/session/manager.py +103 -0
  292. htmlgraph/sdk/strategic/__init__.py +26 -0
  293. htmlgraph/sdk/strategic/mixin.py +563 -0
  294. htmlgraph/server.py +685 -180
  295. htmlgraph/services/__init__.py +10 -0
  296. htmlgraph/services/claiming.py +199 -0
  297. htmlgraph/session_hooks.py +300 -0
  298. htmlgraph/session_manager.py +1392 -175
  299. htmlgraph/session_registry.py +587 -0
  300. htmlgraph/session_state.py +436 -0
  301. htmlgraph/session_warning.py +201 -0
  302. htmlgraph/sessions/__init__.py +23 -0
  303. htmlgraph/sessions/handoff.py +756 -0
  304. htmlgraph/setup.py +34 -17
  305. htmlgraph/spike_index.py +143 -0
  306. htmlgraph/sync_docs.py +12 -15
  307. htmlgraph/system_prompts.py +450 -0
  308. htmlgraph/templates/AGENTS.md.template +366 -0
  309. htmlgraph/templates/CLAUDE.md.template +97 -0
  310. htmlgraph/templates/GEMINI.md.template +87 -0
  311. htmlgraph/templates/orchestration-view.html +350 -0
  312. htmlgraph/track_builder.py +146 -15
  313. htmlgraph/track_manager.py +69 -21
  314. htmlgraph/transcript.py +890 -0
  315. htmlgraph/transcript_analytics.py +699 -0
  316. htmlgraph/types.py +323 -0
  317. htmlgraph/validation.py +115 -0
  318. htmlgraph/watch.py +8 -5
  319. htmlgraph/work_type_utils.py +3 -2
  320. {htmlgraph-0.9.3.data → htmlgraph-0.27.5.data}/data/htmlgraph/dashboard.html +2406 -307
  321. htmlgraph-0.27.5.data/data/htmlgraph/templates/AGENTS.md.template +366 -0
  322. htmlgraph-0.27.5.data/data/htmlgraph/templates/CLAUDE.md.template +97 -0
  323. htmlgraph-0.27.5.data/data/htmlgraph/templates/GEMINI.md.template +87 -0
  324. {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/METADATA +97 -64
  325. htmlgraph-0.27.5.dist-info/RECORD +337 -0
  326. {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/entry_points.txt +1 -1
  327. htmlgraph/cli.py +0 -2688
  328. htmlgraph/sdk.py +0 -709
  329. htmlgraph-0.9.3.dist-info/RECORD +0 -61
  330. {htmlgraph-0.9.3.data → htmlgraph-0.27.5.data}/data/htmlgraph/styles.css +0 -0
  331. {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/WHEEL +0 -0
@@ -1,17 +1,28 @@
1
+ from __future__ import annotations
2
+
1
3
  """
2
4
  Track Builder for agent-friendly track creation.
3
5
  """
4
- from __future__ import annotations
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) -> 'TrackBuilder':
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) -> 'TrackBuilder':
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) -> 'TrackBuilder':
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
- ) -> 'TrackBuilder':
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]]]) -> 'TrackBuilder':
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) -> 'TrackBuilder':
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) -> 'TrackBuilder':
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 = '<li><a href="spec.html">📝 Specification</a></li>' if track.has_spec else ''
115
- plan_link = '<li><a href="plan.html">📋 Implementation Plan</a></li>' if track.has_plan else ''
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' <code>{test_case}</code>' if test_case else ''
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'<li>⏳ {desc}{test_html}</li>')
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(sum(1 for t in p.tasks if t.completed) for p in phases)
203
- completion = int((completed_tasks / total_tasks) * 100) if total_tasks > 0 else 0
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 = f' <span class="estimate">({task.estimate_hours}h)</span>' if task.estimate_hours else ''
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="{'done' if task.completed else 'todo'}">
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="{track.status}" data-priority="{track.priority}">
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-{track.status}">{track.status.title()}</span>
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(Requirement(
558
- id=f"req-{i+1}",
559
- description=desc,
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'\((\d+(?:\.\d+)?)\s*h\)', task_desc)
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(r'\s*\(\d+(?:\.\d+)?\s*h\)', '', task_desc).strip()
576
-
577
- phase_tasks.append(Task(
578
- id=f"task-{i+1}-{j+1}",
579
- description=task_desc,
580
- estimate_hours=estimate
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
- phases.append(Phase(
584
- id=f"phase-{i+1}",
585
- name=phase_name,
586
- tasks=phase_tasks
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 = Path(".htmlgraph") / "tracks" / f"{track_id}.html"
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(track, requirements, phases)
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 = Path(".htmlgraph") / "tracks" / track_id
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(AcceptanceCriterion(description=desc, test_case=test_case))
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
+ ]