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,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  """
2
4
  Feature builder for creating feature nodes.
3
5
 
@@ -5,8 +7,8 @@ Extends BaseBuilder with feature-specific methods like
5
7
  capability management.
6
8
  """
7
9
 
8
- from __future__ import annotations
9
- from typing import TYPE_CHECKING
10
+
11
+ from typing import TYPE_CHECKING, Any
10
12
 
11
13
  if TYPE_CHECKING:
12
14
  from htmlgraph.sdk import SDK
@@ -14,7 +16,7 @@ if TYPE_CHECKING:
14
16
  from htmlgraph.builders.base import BaseBuilder
15
17
 
16
18
 
17
- class FeatureBuilder(BaseBuilder['FeatureBuilder']):
19
+ class FeatureBuilder(BaseBuilder["FeatureBuilder"]):
18
20
  """
19
21
  Fluent builder for creating features.
20
22
 
@@ -33,7 +35,30 @@ class FeatureBuilder(BaseBuilder['FeatureBuilder']):
33
35
 
34
36
  node_type = "feature"
35
37
 
36
- def set_required_capabilities(self, capabilities: list[str]) -> 'FeatureBuilder':
38
+ def __init__(self, sdk: SDK, title: str, **kwargs: Any):
39
+ """Initialize feature builder with agent attribution and validation."""
40
+ # Validate title before creating builder
41
+
42
+ stripped_title = title.strip() if title else ""
43
+ if not stripped_title:
44
+ raise ValueError("Feature title cannot be empty or whitespace only")
45
+ if len(stripped_title) < 3:
46
+ raise ValueError("Feature title must be at least 3 characters")
47
+
48
+ super().__init__(sdk, title, **kwargs)
49
+ # Auto-assign agent from SDK for work tracking
50
+ if sdk._agent_id:
51
+ self._data["agent_assigned"] = sdk._agent_id
52
+ elif "agent_assigned" not in self._data:
53
+ # Log warning if agent not assigned (defensive check)
54
+ import logging
55
+
56
+ logging.warning(
57
+ f"Creating feature '{self._data.get('title', 'Unknown')}' without agent attribution. "
58
+ "Pass agent='name' to SDK() initialization."
59
+ )
60
+
61
+ def set_required_capabilities(self, capabilities: list[str]) -> FeatureBuilder:
37
62
  """
38
63
  Set required capabilities for this feature.
39
64
 
@@ -52,7 +77,7 @@ class FeatureBuilder(BaseBuilder['FeatureBuilder']):
52
77
  self._data["required_capabilities"] = capabilities
53
78
  return self
54
79
 
55
- def add_capability_tag(self, tag: str) -> 'FeatureBuilder':
80
+ def add_capability_tag(self, tag: str) -> FeatureBuilder:
56
81
  """
57
82
  Add a capability tag for flexible matching.
58
83
 
@@ -73,7 +98,7 @@ class FeatureBuilder(BaseBuilder['FeatureBuilder']):
73
98
  self._data["capability_tags"].append(tag)
74
99
  return self
75
100
 
76
- def add_capability_tags(self, tags: list[str]) -> 'FeatureBuilder':
101
+ def add_capability_tags(self, tags: list[str]) -> FeatureBuilder:
77
102
  """
78
103
  Add multiple capability tags.
79
104
 
@@ -0,0 +1,195 @@
1
+ from __future__ import annotations
2
+
3
+ """
4
+ Insight builder for creating session insight nodes.
5
+
6
+ Extends BaseBuilder with insight-specific methods for
7
+ session health scoring and pattern detection.
8
+ """
9
+
10
+
11
+ from typing import TYPE_CHECKING, Any
12
+
13
+ if TYPE_CHECKING:
14
+ from htmlgraph.models import SessionInsight
15
+ from htmlgraph.sdk import SDK
16
+
17
+ from htmlgraph.builders.base import BaseBuilder
18
+ from htmlgraph.ids import generate_id
19
+
20
+
21
+ class InsightBuilder(BaseBuilder["InsightBuilder"]):
22
+ """
23
+ Fluent builder for creating session insights.
24
+
25
+ Insights analyze session health, detect patterns, and provide
26
+ recommendations for improvement.
27
+
28
+ Example:
29
+ >>> sdk = SDK(agent="claude")
30
+ >>> insight = sdk.insights.create("Session ABC Health Analysis") \\
31
+ ... .for_session("session-abc-123") \\
32
+ ... .set_health_scores(efficiency=0.85, retry_rate=0.1) \\
33
+ ... .add_issue("High retry rate on Bash commands") \\
34
+ ... .add_recommendation("Use Read before Edit") \\
35
+ ... .save()
36
+ """
37
+
38
+ node_type = "insight"
39
+
40
+ def __init__(self, sdk: SDK, title: str, **kwargs: Any):
41
+ """Initialize insight builder with insight-specific defaults."""
42
+ super().__init__(sdk, title, **kwargs)
43
+ # Set insight-specific defaults
44
+ if "insight_type" not in self._data:
45
+ self._data["insight_type"] = "health"
46
+
47
+ def for_session(self, session_id: str) -> InsightBuilder:
48
+ """
49
+ Set the source session ID.
50
+
51
+ Args:
52
+ session_id: ID of the session being analyzed
53
+
54
+ Returns:
55
+ Self for method chaining
56
+
57
+ Example:
58
+ >>> insight.for_session("session-abc-123")
59
+ """
60
+ self._data["session_id"] = session_id
61
+ return self
62
+
63
+ def set_health_scores(
64
+ self,
65
+ efficiency: float = 0.0,
66
+ retry_rate: float = 0.0,
67
+ context_rebuilds: int = 0,
68
+ tool_diversity: float = 0.0,
69
+ error_recovery: float = 0.0,
70
+ ) -> InsightBuilder:
71
+ """
72
+ Set all health metric scores.
73
+
74
+ Args:
75
+ efficiency: Efficiency score (0.0-1.0)
76
+ retry_rate: Retry rate (0.0-1.0, lower is better)
77
+ context_rebuilds: Number of context rebuilds
78
+ tool_diversity: Tool diversity score (0.0-1.0)
79
+ error_recovery: Error recovery rate (0.0-1.0)
80
+
81
+ Returns:
82
+ Self for method chaining
83
+
84
+ Example:
85
+ >>> insight.set_health_scores(
86
+ ... efficiency=0.85,
87
+ ... retry_rate=0.12,
88
+ ... tool_diversity=0.70
89
+ ... )
90
+ """
91
+ self._data["efficiency_score"] = efficiency
92
+ self._data["retry_rate"] = retry_rate
93
+ self._data["context_rebuild_count"] = context_rebuilds
94
+ self._data["tool_diversity"] = tool_diversity
95
+ self._data["error_recovery_rate"] = error_recovery
96
+ # Calculate overall health score
97
+ self._data["overall_health_score"] = (
98
+ efficiency + (1 - retry_rate) + tool_diversity
99
+ ) / 3
100
+ return self
101
+
102
+ def add_issue(self, issue: str) -> InsightBuilder:
103
+ """
104
+ Add a detected issue.
105
+
106
+ Args:
107
+ issue: Description of the issue
108
+
109
+ Returns:
110
+ Self for method chaining
111
+
112
+ Example:
113
+ >>> insight.add_issue("High retry rate on file operations")
114
+ """
115
+ if "issues_detected" not in self._data:
116
+ self._data["issues_detected"] = []
117
+ self._data["issues_detected"].append(issue)
118
+ return self
119
+
120
+ def add_recommendation(self, rec: str) -> InsightBuilder:
121
+ """
122
+ Add a recommendation for improvement.
123
+
124
+ Args:
125
+ rec: Recommendation text
126
+
127
+ Returns:
128
+ Self for method chaining
129
+
130
+ Example:
131
+ >>> insight.add_recommendation("Use Read before attempting Edit")
132
+ """
133
+ if "recommendations" not in self._data:
134
+ self._data["recommendations"] = []
135
+ self._data["recommendations"].append(rec)
136
+ return self
137
+
138
+ def add_pattern_match(
139
+ self, pattern_id: str, is_anti: bool = False
140
+ ) -> InsightBuilder:
141
+ """
142
+ Add a matched pattern ID.
143
+
144
+ Args:
145
+ pattern_id: ID of the matched pattern
146
+ is_anti: Whether this is an anti-pattern match
147
+
148
+ Returns:
149
+ Self for method chaining
150
+
151
+ Example:
152
+ >>> insight.add_pattern_match("pattern-efficient-testing", is_anti=False)
153
+ >>> insight.add_pattern_match("pattern-excessive-retries", is_anti=True)
154
+ """
155
+ key = "anti_patterns_matched" if is_anti else "patterns_matched"
156
+ if key not in self._data:
157
+ self._data[key] = []
158
+ self._data[key].append(pattern_id)
159
+ return self
160
+
161
+ def save(self) -> SessionInsight:
162
+ """
163
+ Save the insight and return the SessionInsight instance.
164
+
165
+ Overrides BaseBuilder.save() to ensure insights are saved
166
+ to the insights directory.
167
+
168
+ Returns:
169
+ Created SessionInsight instance
170
+ """
171
+ # Generate collision-resistant ID if not provided
172
+ if "id" not in self._data:
173
+ self._data["id"] = generate_id(
174
+ node_type="insight",
175
+ title=self._data.get("title", ""),
176
+ )
177
+
178
+ # Import SessionInsight here to avoid circular imports
179
+ from htmlgraph.models import SessionInsight
180
+
181
+ node = SessionInsight(**self._data)
182
+
183
+ # Save to the insights collection
184
+ if hasattr(self._sdk, "insights") and self._sdk.insights is not None:
185
+ graph = self._sdk.insights._ensure_graph()
186
+ graph.add(node)
187
+ else:
188
+ # Fallback: create new graph
189
+ from htmlgraph.graph import HtmlGraph
190
+
191
+ graph_path = self._sdk._directory / "insights"
192
+ graph = HtmlGraph(graph_path, auto_load=False)
193
+ graph.add(node)
194
+
195
+ return node
@@ -0,0 +1,217 @@
1
+ from __future__ import annotations
2
+
3
+ """
4
+ Metric builder for creating aggregated metric nodes.
5
+
6
+ Extends BaseBuilder with metric-specific methods for
7
+ time-series aggregation and trend analysis.
8
+ """
9
+
10
+
11
+ from datetime import datetime
12
+ from typing import TYPE_CHECKING, Any
13
+
14
+ if TYPE_CHECKING:
15
+ from htmlgraph.models import AggregatedMetric
16
+ from htmlgraph.sdk import SDK
17
+
18
+ from htmlgraph.builders.base import BaseBuilder
19
+ from htmlgraph.ids import generate_id
20
+
21
+
22
+ class MetricBuilder(BaseBuilder["MetricBuilder"]):
23
+ """
24
+ Fluent builder for creating aggregated metrics.
25
+
26
+ Metrics aggregate data over time periods (daily/weekly/monthly)
27
+ and scopes (session/feature/track/agent).
28
+
29
+ Example:
30
+ >>> sdk = SDK(agent="claude")
31
+ >>> metric = sdk.metrics.create("Weekly Efficiency") \\
32
+ ... .set_scope("agent", "claude") \\
33
+ ... .set_period("weekly", start=datetime(...), end=datetime(...)) \\
34
+ ... .set_metrics({"avg_efficiency": 0.85, "median_retry_rate": 0.12}) \\
35
+ ... .set_trend("improving", strength=0.15) \\
36
+ ... .save()
37
+ """
38
+
39
+ node_type = "metric"
40
+
41
+ def __init__(self, sdk: SDK, title: str, **kwargs: Any):
42
+ """Initialize metric builder with metric-specific defaults."""
43
+ super().__init__(sdk, title, **kwargs)
44
+ # Set metric-specific defaults
45
+ if "metric_type" not in self._data:
46
+ self._data["metric_type"] = "efficiency"
47
+ if "scope" not in self._data:
48
+ self._data["scope"] = "session"
49
+ if "period" not in self._data:
50
+ self._data["period"] = "weekly"
51
+
52
+ def set_scope(self, scope: str, scope_id: str | None = None) -> MetricBuilder:
53
+ """
54
+ Set metric scope: session, feature, track, or agent.
55
+
56
+ Args:
57
+ scope: Scope type (session/feature/track/agent)
58
+ scope_id: Specific ID within scope (optional)
59
+
60
+ Returns:
61
+ Self for method chaining
62
+
63
+ Example:
64
+ >>> metric.set_scope("agent", "claude")
65
+ >>> metric.set_scope("track", "track-planning-workflow")
66
+ """
67
+ self._data["scope"] = scope
68
+ if scope_id:
69
+ self._data["scope_id"] = scope_id
70
+ return self
71
+
72
+ def set_period(
73
+ self,
74
+ period: str,
75
+ start: datetime | None = None,
76
+ end: datetime | None = None,
77
+ ) -> MetricBuilder:
78
+ """
79
+ Set time period for aggregation.
80
+
81
+ Args:
82
+ period: Period type (daily/weekly/monthly)
83
+ start: Period start datetime (optional)
84
+ end: Period end datetime (optional)
85
+
86
+ Returns:
87
+ Self for method chaining
88
+
89
+ Example:
90
+ >>> metric.set_period("weekly", start=datetime(...), end=datetime(...))
91
+ """
92
+ self._data["period"] = period
93
+ if start:
94
+ self._data["period_start"] = start.isoformat()
95
+ if end:
96
+ self._data["period_end"] = end.isoformat()
97
+ return self
98
+
99
+ def set_metrics(self, metrics: dict[str, float]) -> MetricBuilder:
100
+ """
101
+ Set metric values dict.
102
+
103
+ Args:
104
+ metrics: Dictionary of metric name -> value
105
+
106
+ Returns:
107
+ Self for method chaining
108
+
109
+ Example:
110
+ >>> metric.set_metrics({
111
+ ... "avg_efficiency": 0.85,
112
+ ... "median_retry_rate": 0.12,
113
+ ... "tool_diversity": 0.68
114
+ ... })
115
+ """
116
+ self._data["metric_values"] = metrics
117
+ return self
118
+
119
+ def set_percentiles(self, percentiles: dict[str, float]) -> MetricBuilder:
120
+ """
121
+ Set percentile values (p50, p90, p99, etc.).
122
+
123
+ Args:
124
+ percentiles: Dictionary of percentile name -> value
125
+
126
+ Returns:
127
+ Self for method chaining
128
+
129
+ Example:
130
+ >>> metric.set_percentiles({
131
+ ... "p50": 0.82,
132
+ ... "p90": 0.95,
133
+ ... "p99": 0.98
134
+ ... })
135
+ """
136
+ self._data["percentiles"] = percentiles
137
+ return self
138
+
139
+ def set_trend(
140
+ self,
141
+ direction: str,
142
+ strength: float = 0.0,
143
+ vs_previous_pct: float = 0.0,
144
+ ) -> MetricBuilder:
145
+ """
146
+ Set trend information.
147
+
148
+ Args:
149
+ direction: Trend direction (improving/declining/stable)
150
+ strength: Trend strength (0.0-1.0)
151
+ vs_previous_pct: Percentage change vs previous period
152
+
153
+ Returns:
154
+ Self for method chaining
155
+
156
+ Example:
157
+ >>> metric.set_trend("improving", strength=0.15, vs_previous_pct=8.5)
158
+ """
159
+ self._data["trend_direction"] = direction
160
+ self._data["trend_strength"] = strength
161
+ self._data["vs_previous_period_pct"] = vs_previous_pct
162
+ return self
163
+
164
+ def add_session(self, session_id: str) -> MetricBuilder:
165
+ """
166
+ Add a session to the aggregation.
167
+
168
+ Args:
169
+ session_id: Session ID to include
170
+
171
+ Returns:
172
+ Self for method chaining
173
+
174
+ Example:
175
+ >>> metric.add_session("session-abc-123")
176
+ """
177
+ if "sessions_in_period" not in self._data:
178
+ self._data["sessions_in_period"] = []
179
+ self._data["sessions_in_period"].append(session_id)
180
+ self._data["data_points_count"] = len(self._data["sessions_in_period"])
181
+ return self
182
+
183
+ def save(self) -> AggregatedMetric:
184
+ """
185
+ Save the metric and return the AggregatedMetric instance.
186
+
187
+ Overrides BaseBuilder.save() to ensure metrics are saved
188
+ to the metrics directory.
189
+
190
+ Returns:
191
+ Created AggregatedMetric node instance
192
+ """
193
+ # Generate collision-resistant ID if not provided
194
+ if "id" not in self._data:
195
+ self._data["id"] = generate_id(
196
+ node_type="metric",
197
+ title=self._data.get("title", ""),
198
+ )
199
+
200
+ # Import AggregatedMetric here to avoid circular imports
201
+ from htmlgraph.models import AggregatedMetric
202
+
203
+ node = AggregatedMetric(**self._data)
204
+
205
+ # Save to the metrics collection
206
+ if hasattr(self._sdk, "metrics") and self._sdk.metrics is not None:
207
+ graph = self._sdk.metrics._ensure_graph()
208
+ graph.add(node)
209
+ else:
210
+ # Fallback: create new graph
211
+ from htmlgraph.graph import HtmlGraph
212
+
213
+ graph_path = self._sdk._directory / "metrics"
214
+ graph = HtmlGraph(graph_path, auto_load=False)
215
+ graph.add(node)
216
+
217
+ return node
@@ -0,0 +1,202 @@
1
+ from __future__ import annotations
2
+
3
+ """
4
+ Pattern builder for creating workflow pattern nodes.
5
+
6
+ Extends BaseBuilder with pattern-specific methods for
7
+ tracking optimal and anti-pattern tool sequences.
8
+ """
9
+
10
+
11
+ from datetime import datetime
12
+ from typing import TYPE_CHECKING, Any
13
+
14
+ if TYPE_CHECKING:
15
+ from htmlgraph.models import Pattern
16
+ from htmlgraph.sdk import SDK
17
+
18
+ from htmlgraph.builders.base import BaseBuilder
19
+ from htmlgraph.ids import generate_id
20
+
21
+
22
+ class PatternBuilder(BaseBuilder["PatternBuilder"]):
23
+ """
24
+ Fluent builder for creating workflow patterns.
25
+
26
+ Patterns represent observed tool usage sequences that are
27
+ either optimal (should encourage) or anti-patterns (should warn against).
28
+
29
+ Example:
30
+ >>> sdk = SDK(agent="claude")
31
+ >>> pattern = sdk.patterns.create("Efficient Testing Pattern") \\
32
+ ... .set_pattern_type("optimal") \\
33
+ ... .set_sequence(["Edit", "Bash", "Edit"]) \\
34
+ ... .set_success_rate(0.92) \\
35
+ ... .set_recommendation("Write tests, run them, fix failures") \\
36
+ ... .save()
37
+ """
38
+
39
+ node_type = "pattern"
40
+
41
+ def __init__(self, sdk: SDK, title: str, **kwargs: Any):
42
+ """Initialize pattern builder with pattern-specific defaults."""
43
+ super().__init__(sdk, title, **kwargs)
44
+ # Set pattern-specific defaults
45
+ if "pattern_type" not in self._data:
46
+ self._data["pattern_type"] = "neutral"
47
+ if "sequence" not in self._data:
48
+ self._data["sequence"] = []
49
+ if "detection_count" not in self._data:
50
+ self._data["detection_count"] = 0
51
+
52
+ def set_pattern_type(self, ptype: str) -> PatternBuilder:
53
+ """
54
+ Set pattern type: optimal, anti-pattern, or neutral.
55
+
56
+ Args:
57
+ ptype: Pattern classification (optimal/anti-pattern/neutral)
58
+
59
+ Returns:
60
+ Self for method chaining
61
+
62
+ Example:
63
+ >>> pattern.set_pattern_type("optimal")
64
+ """
65
+ self._data["pattern_type"] = ptype
66
+ return self
67
+
68
+ def set_sequence(self, sequence: list[str]) -> PatternBuilder:
69
+ """
70
+ Set the tool sequence for this pattern.
71
+
72
+ Args:
73
+ sequence: List of tool names in order (e.g., ["Edit", "Bash", "Read"])
74
+
75
+ Returns:
76
+ Self for method chaining
77
+
78
+ Example:
79
+ >>> pattern.set_sequence(["Edit", "Bash", "Bash", "Edit"])
80
+ """
81
+ self._data["sequence"] = sequence
82
+ return self
83
+
84
+ def set_success_rate(self, rate: float) -> PatternBuilder:
85
+ """
86
+ Set success rate (0.0-1.0).
87
+
88
+ Args:
89
+ rate: Success rate as decimal (0.0 = 0%, 1.0 = 100%)
90
+
91
+ Returns:
92
+ Self for method chaining
93
+
94
+ Example:
95
+ >>> pattern.set_success_rate(0.85)
96
+ """
97
+ self._data["success_rate"] = rate
98
+ return self
99
+
100
+ def set_recommendation(self, rec: str) -> PatternBuilder:
101
+ """
102
+ Set recommendation text for when this pattern is detected.
103
+
104
+ Args:
105
+ rec: Recommendation message
106
+
107
+ Returns:
108
+ Self for method chaining
109
+
110
+ Example:
111
+ >>> pattern.set_recommendation("Consider running tests after changes")
112
+ """
113
+ self._data["recommendation"] = rec
114
+ return self
115
+
116
+ def increment_detection(self) -> PatternBuilder:
117
+ """
118
+ Increment detection count (number of times pattern was observed).
119
+
120
+ Returns:
121
+ Self for method chaining
122
+
123
+ Example:
124
+ >>> pattern.increment_detection()
125
+ """
126
+ self._data["detection_count"] = self._data.get("detection_count", 0) + 1
127
+ return self
128
+
129
+ def set_detection_count(self, count: int) -> PatternBuilder:
130
+ """
131
+ Set detection count directly.
132
+
133
+ Args:
134
+ count: Number of times pattern was detected
135
+
136
+ Returns:
137
+ Self for method chaining
138
+ """
139
+ self._data["detection_count"] = count
140
+ return self
141
+
142
+ def set_first_detected(self, dt: datetime) -> PatternBuilder:
143
+ """
144
+ Set first detection timestamp.
145
+
146
+ Args:
147
+ dt: Timestamp of first detection
148
+
149
+ Returns:
150
+ Self for method chaining
151
+ """
152
+ self._data["first_detected"] = dt
153
+ return self
154
+
155
+ def set_last_detected(self, dt: datetime) -> PatternBuilder:
156
+ """
157
+ Set last detection timestamp.
158
+
159
+ Args:
160
+ dt: Timestamp of last detection
161
+
162
+ Returns:
163
+ Self for method chaining
164
+ """
165
+ self._data["last_detected"] = dt
166
+ return self
167
+
168
+ def save(self) -> Pattern:
169
+ """
170
+ Save the pattern and return the Node instance.
171
+
172
+ Overrides BaseBuilder.save() to ensure patterns are saved
173
+ to the patterns directory.
174
+
175
+ Returns:
176
+ Created Pattern node instance
177
+ """
178
+ # Generate collision-resistant ID if not provided
179
+ if "id" not in self._data:
180
+ self._data["id"] = generate_id(
181
+ node_type="pattern",
182
+ title=self._data.get("title", ""),
183
+ )
184
+
185
+ # Import Pattern here to avoid circular imports
186
+ from htmlgraph.models import Pattern
187
+
188
+ node = Pattern(**self._data)
189
+
190
+ # Save to the patterns collection
191
+ if hasattr(self._sdk, "patterns") and self._sdk.patterns is not None:
192
+ graph = self._sdk.patterns._ensure_graph()
193
+ graph.add(node)
194
+ else:
195
+ # Fallback: create new graph
196
+ from htmlgraph.graph import HtmlGraph
197
+
198
+ graph_path = self._sdk._directory / "patterns"
199
+ graph = HtmlGraph(graph_path, auto_load=False)
200
+ graph.add(node)
201
+
202
+ return node