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
htmlgraph/sdk/base.py ADDED
@@ -0,0 +1,484 @@
1
+ from __future__ import annotations
2
+
3
+ """
4
+ Base SDK Core Class - Initialization and Core Properties
5
+
6
+ Extracted from sdk.py to reduce file size and improve modularity.
7
+ Contains the core SDK initialization logic and essential properties.
8
+ """
9
+
10
+
11
+ import os
12
+ from pathlib import Path
13
+ from typing import TYPE_CHECKING, Any, cast
14
+
15
+ if TYPE_CHECKING:
16
+ from htmlgraph import SDK
17
+
18
+ from htmlgraph.agent_detection import detect_agent_name
19
+ from htmlgraph.agents import AgentInterface
20
+ from htmlgraph.analytics import Analytics, CrossSessionAnalytics, DependencyAnalytics
21
+ from htmlgraph.collections import (
22
+ BaseCollection,
23
+ BugCollection,
24
+ ChoreCollection,
25
+ EpicCollection,
26
+ FeatureCollection,
27
+ PhaseCollection,
28
+ SpikeCollection,
29
+ TaskDelegationCollection,
30
+ TodoCollection,
31
+ )
32
+ from htmlgraph.collections.insight import InsightCollection
33
+ from htmlgraph.collections.metric import MetricCollection
34
+ from htmlgraph.collections.pattern import PatternCollection
35
+ from htmlgraph.collections.session import SessionCollection
36
+ from htmlgraph.context_analytics import ContextAnalytics
37
+ from htmlgraph.db.schema import HtmlGraphDB
38
+ from htmlgraph.graph import HtmlGraph
39
+ from htmlgraph.session_manager import SessionManager
40
+ from htmlgraph.session_warning import check_and_show_warning
41
+ from htmlgraph.system_prompts import SystemPromptManager
42
+ from htmlgraph.track_builder import TrackCollection
43
+
44
+
45
+ class BaseSDK:
46
+ """
47
+ Core SDK class with initialization logic and essential properties.
48
+
49
+ This class handles:
50
+ - SDK initialization and auto-discovery
51
+ - Database and graph initialization
52
+ - Collection setup and configuration
53
+ - Lazy-loaded properties (orchestrator, system_prompts)
54
+ - Core utility methods (_log_event, _ensure_session_exists)
55
+
56
+ Subclasses add domain-specific methods (analytics, planning, orchestration).
57
+ """
58
+
59
+ def __init__(
60
+ self,
61
+ directory: Path | str | None = None,
62
+ agent: str | None = None,
63
+ parent_session: str | None = None,
64
+ db_path: str | None = None,
65
+ ):
66
+ """
67
+ Initialize SDK.
68
+
69
+ Args:
70
+ directory: Path to .htmlgraph directory (auto-discovered if not provided)
71
+ agent: REQUIRED - Agent identifier for operations.
72
+ Used to attribute work items (features, spikes, bugs, etc) to the agent.
73
+ Examples: agent='explorer', agent='coder', agent='tester'
74
+ Critical for: Work attribution, result retrieval, orchestrator tracking
75
+ Falls back to: CLAUDE_AGENT_NAME env var, then detect_agent_name()
76
+ Raises ValueError if not provided and cannot be detected
77
+ parent_session: Parent session ID to log activities to (for nested contexts)
78
+ db_path: Path to SQLite database file (optional, defaults to ~/.htmlgraph/htmlgraph.db)
79
+ """
80
+ if directory is None:
81
+ directory = self._discover_htmlgraph()
82
+
83
+ if agent is None:
84
+ # Try environment variable fallback
85
+ agent = os.getenv("CLAUDE_AGENT_NAME")
86
+
87
+ if agent is None:
88
+ # Try automatic detection
89
+ detected = detect_agent_name()
90
+ if detected and detected != "cli":
91
+ # Only accept detected if it's not the default fallback
92
+ agent = detected
93
+ else:
94
+ # No valid agent found - fail fast with helpful error message
95
+ raise ValueError(
96
+ "Agent identifier is required for work attribution. "
97
+ "Pass agent='name' to SDK() initialization. "
98
+ "Examples: SDK(agent='explorer'), SDK(agent='coder'), SDK(agent='tester')\n"
99
+ "Alternatively, set CLAUDE_AGENT_NAME environment variable.\n"
100
+ "Critical for: Work attribution, result retrieval, orchestrator tracking"
101
+ )
102
+
103
+ self._directory = Path(directory)
104
+ self._agent_id = agent
105
+ self._parent_session = parent_session or os.getenv("HTMLGRAPH_PARENT_SESSION")
106
+
107
+ # Initialize SQLite database (Phase 2)
108
+ self._db = HtmlGraphDB(
109
+ db_path or str(Path.home() / ".htmlgraph" / "htmlgraph.db")
110
+ )
111
+ self._db.connect()
112
+ self._db.create_tables()
113
+
114
+ # Initialize underlying HtmlGraphs first (for backward compatibility and sharing)
115
+ # These are shared with SessionManager to avoid double-loading features
116
+ self._graph = HtmlGraph(self._directory / "features")
117
+ self._bugs_graph = HtmlGraph(self._directory / "bugs")
118
+
119
+ # Initialize SessionManager with shared graph instances to avoid double-loading
120
+ self.session_manager = SessionManager(
121
+ self._directory,
122
+ features_graph=self._graph,
123
+ bugs_graph=self._bugs_graph,
124
+ )
125
+
126
+ # Agent interface (for backward compatibility)
127
+ self._agent_interface = AgentInterface(
128
+ self._directory / "features", agent_id=agent
129
+ )
130
+
131
+ # Cast self to SDK for type checking - BaseSDK is only used via SDK subclass
132
+ sdk_self = cast("SDK", self)
133
+
134
+ # Collection interfaces - all work item types (all with builder support)
135
+ self.features = FeatureCollection(sdk_self)
136
+ self.bugs = BugCollection(sdk_self)
137
+ self.chores = ChoreCollection(sdk_self)
138
+ self.spikes = SpikeCollection(sdk_self)
139
+ self.epics = EpicCollection(sdk_self)
140
+ self.phases = PhaseCollection(sdk_self)
141
+
142
+ # Non-work collections
143
+ self.sessions: SessionCollection = SessionCollection(sdk_self)
144
+ self.tracks: TrackCollection = TrackCollection(
145
+ sdk_self
146
+ ) # Use specialized collection with builder support
147
+ self.agents: BaseCollection[Any] = BaseCollection(sdk_self, "agents", "agent")
148
+
149
+ # Learning collections (Active Learning Persistence)
150
+ self.patterns = PatternCollection(sdk_self)
151
+ self.insights = InsightCollection(sdk_self)
152
+ self.metrics = MetricCollection(sdk_self)
153
+
154
+ # Todo collection (persistent task tracking)
155
+ self.todos = TodoCollection(sdk_self)
156
+
157
+ # Task delegation collection (observability for spawned agents)
158
+ self.task_delegations = TaskDelegationCollection(sdk_self)
159
+
160
+ # Create learning directories if needed
161
+ (self._directory / "patterns").mkdir(exist_ok=True)
162
+ (self._directory / "insights").mkdir(exist_ok=True)
163
+ (self._directory / "metrics").mkdir(exist_ok=True)
164
+ (self._directory / "todos").mkdir(exist_ok=True)
165
+ (self._directory / "task-delegations").mkdir(exist_ok=True)
166
+
167
+ # Initialize RefManager and set on all collections
168
+ from htmlgraph.refs import RefManager
169
+
170
+ self.refs = RefManager(self._directory)
171
+
172
+ # Set ref manager on all work item collections
173
+ self.features.set_ref_manager(self.refs)
174
+ self.bugs.set_ref_manager(self.refs)
175
+ self.chores.set_ref_manager(self.refs)
176
+ self.spikes.set_ref_manager(self.refs)
177
+ self.epics.set_ref_manager(self.refs)
178
+ self.phases.set_ref_manager(self.refs)
179
+ self.tracks.set_ref_manager(self.refs)
180
+ self.todos.set_ref_manager(self.refs)
181
+
182
+ # Analytics interface (Phase 2: Work Type Analytics)
183
+ self.analytics = Analytics(sdk_self)
184
+
185
+ # Dependency analytics interface (Advanced graph analytics)
186
+ self.dep_analytics = DependencyAnalytics(self._graph)
187
+
188
+ # Cross-session analytics interface (Git commit-based analytics)
189
+ self.cross_session_analytics = CrossSessionAnalytics(sdk_self)
190
+
191
+ # Context analytics interface (Context usage tracking)
192
+ self.context = ContextAnalytics(sdk_self)
193
+
194
+ # Pattern learning interface (Phase 2: Behavior Pattern Learning)
195
+ from htmlgraph.analytics.pattern_learning import PatternLearner
196
+
197
+ self.pattern_learning = PatternLearner(self._directory)
198
+
199
+ # Lazy-loaded orchestrator for subagent management
200
+ self._orchestrator: Any = None
201
+
202
+ # System prompt manager (lazy-loaded)
203
+ self._system_prompts: SystemPromptManager | None = None
204
+
205
+ # Session warning system (workaround for Claude Code hook bug #10373)
206
+ # Shows orchestrator instructions on first SDK usage per session
207
+ self._session_warning = check_and_show_warning(
208
+ self._directory,
209
+ agent=self._agent_id,
210
+ session_id=None, # Will be set by session manager if available
211
+ )
212
+
213
+ @staticmethod
214
+ def _discover_htmlgraph() -> Path:
215
+ """
216
+ Auto-discover .htmlgraph directory.
217
+
218
+ Searches current directory and parents.
219
+ """
220
+ current = Path.cwd()
221
+
222
+ # Check current directory
223
+ if (current / ".htmlgraph").exists():
224
+ return current / ".htmlgraph"
225
+
226
+ # Check parent directories
227
+ for parent in current.parents:
228
+ if (parent / ".htmlgraph").exists():
229
+ return parent / ".htmlgraph"
230
+
231
+ # Default to current directory
232
+ return current / ".htmlgraph"
233
+
234
+ @property
235
+ def agent(self) -> str | None:
236
+ """Get current agent ID."""
237
+ return self._agent_id
238
+
239
+ @property
240
+ def system_prompts(self) -> SystemPromptManager:
241
+ """
242
+ Access system prompt management.
243
+
244
+ Provides methods to:
245
+ - Get active prompt (project override OR plugin default)
246
+ - Create/delete project-level overrides
247
+ - Validate token counts
248
+ - Get prompt statistics
249
+
250
+ Lazy-loaded on first access.
251
+
252
+ Returns:
253
+ SystemPromptManager instance
254
+
255
+ Example:
256
+ >>> sdk = SDK(agent="claude")
257
+
258
+ # Get active prompt
259
+ >>> prompt = sdk.system_prompts.get_active()
260
+
261
+ # Create project override
262
+ >>> sdk.system_prompts.create("## Custom prompt\\n...")
263
+
264
+ # Validate token count
265
+ >>> result = sdk.system_prompts.validate()
266
+ >>> print(result['message'])
267
+
268
+ # Get statistics
269
+ >>> stats = sdk.system_prompts.get_stats()
270
+ >>> print(f"Source: {stats['source']}")
271
+ """
272
+ if self._system_prompts is None:
273
+ self._system_prompts = SystemPromptManager(self._directory)
274
+ return self._system_prompts
275
+
276
+ def dismiss_session_warning(self) -> bool:
277
+ """
278
+ Dismiss the session warning after reading it.
279
+
280
+ IMPORTANT: Call this as your FIRST action after seeing the orchestrator
281
+ warning. This confirms you've read the instructions.
282
+
283
+ Returns:
284
+ True if warning was dismissed, False if already dismissed
285
+
286
+ Example:
287
+ sdk = SDK(agent="claude")
288
+ # Warning shown automatically...
289
+
290
+ # First action: dismiss to confirm you read it
291
+ sdk.dismiss_session_warning()
292
+
293
+ # Now proceed with orchestration
294
+ sdk.spawn_coder(feature_id="feat-123", ...)
295
+ """
296
+ if self._session_warning:
297
+ return self._session_warning.dismiss(
298
+ agent=self._agent_id,
299
+ session_id=None,
300
+ )
301
+ return False
302
+
303
+ def get_warning_status(self) -> dict[str, Any]:
304
+ """
305
+ Get current session warning status.
306
+
307
+ Returns:
308
+ Dict with dismissed status, timestamp, and show count
309
+ """
310
+ if self._session_warning:
311
+ return self._session_warning.get_status()
312
+ return {"dismissed": True, "show_count": 0}
313
+
314
+ def db(self) -> HtmlGraphDB:
315
+ """
316
+ Get the SQLite database instance.
317
+
318
+ Returns:
319
+ HtmlGraphDB instance for executing queries
320
+
321
+ Example:
322
+ >>> sdk = SDK(agent="claude")
323
+ >>> db = sdk.db()
324
+ >>> events = db.get_session_events("sess-123")
325
+ >>> features = db.get_features_by_status("todo")
326
+ """
327
+ return self._db
328
+
329
+ def query(self, sql: str, params: tuple = ()) -> list[dict[str, Any]]:
330
+ """
331
+ Execute a raw SQL query on the SQLite database.
332
+
333
+ Args:
334
+ sql: SQL query string
335
+ params: Query parameters (for safe parameterized queries)
336
+
337
+ Returns:
338
+ List of result dictionaries
339
+
340
+ Example:
341
+ >>> sdk = SDK(agent="claude")
342
+ >>> results = sdk.query(
343
+ ... "SELECT * FROM features WHERE status = ? AND priority = ?",
344
+ ... ("todo", "high")
345
+ ... )
346
+ >>> for row in results:
347
+ ... print(row["title"])
348
+ """
349
+ if not self._db.connection:
350
+ self._db.connect()
351
+
352
+ cursor = self._db.connection.cursor() # type: ignore[union-attr]
353
+ cursor.execute(sql, params)
354
+ rows = cursor.fetchall()
355
+ return [dict(row) for row in rows]
356
+
357
+ def execute_query_builder(
358
+ self, sql: str, params: tuple = ()
359
+ ) -> list[dict[str, Any]]:
360
+ """
361
+ Execute a query using the Queries builder.
362
+
363
+ Args:
364
+ sql: SQL query from Queries builder
365
+ params: Parameters from Queries builder
366
+
367
+ Returns:
368
+ List of result dictionaries
369
+
370
+ Example:
371
+ >>> sdk = SDK(agent="claude")
372
+ >>> sql, params = Queries.get_features_by_status("todo", limit=5)
373
+ >>> results = sdk.execute_query_builder(sql, params)
374
+ """
375
+ return self.query(sql, params)
376
+
377
+ def _log_event(
378
+ self,
379
+ event_type: str,
380
+ tool_name: str | None = None,
381
+ input_summary: str | None = None,
382
+ output_summary: str | None = None,
383
+ context: dict[str, Any] | None = None,
384
+ cost_tokens: int = 0,
385
+ ) -> bool:
386
+ """
387
+ Log an event to the SQLite database with parent-child linking.
388
+
389
+ Internal method used by collections to track operations.
390
+ Automatically creates a session if one doesn't exist.
391
+ Reads parent event ID from HTMLGRAPH_PARENT_ACTIVITY env var for hierarchical tracking.
392
+
393
+ Args:
394
+ event_type: Type of event (tool_call, completion, error, etc.)
395
+ tool_name: Tool that was called
396
+ input_summary: Summary of input
397
+ output_summary: Summary of output
398
+ context: Additional context metadata
399
+ cost_tokens: Token cost estimate
400
+
401
+ Returns:
402
+ True if logged successfully, False otherwise
403
+
404
+ Example (internal use):
405
+ >>> sdk._log_event(
406
+ ... event_type="tool_call",
407
+ ... tool_name="Edit",
408
+ ... input_summary="Edit file.py",
409
+ ... cost_tokens=100
410
+ ... )
411
+ """
412
+ from uuid import uuid4
413
+
414
+ event_id = f"evt-{uuid4().hex[:12]}"
415
+ session_id = self._parent_session or "cli-session"
416
+
417
+ # Read parent event ID from environment variable for hierarchical linking
418
+ parent_event_id = os.getenv("HTMLGRAPH_PARENT_ACTIVITY")
419
+
420
+ # Ensure session exists before logging event
421
+ try:
422
+ self._ensure_session_exists(session_id, parent_event_id=parent_event_id)
423
+ except Exception as e:
424
+ import logging
425
+
426
+ logging.debug(f"Failed to ensure session exists: {e}")
427
+ # Continue anyway - session creation failure shouldn't block event logging
428
+
429
+ return self._db.insert_event(
430
+ event_id=event_id,
431
+ agent_id=self._agent_id,
432
+ event_type=event_type,
433
+ session_id=session_id,
434
+ tool_name=tool_name,
435
+ input_summary=input_summary,
436
+ output_summary=output_summary,
437
+ context=context,
438
+ parent_event_id=parent_event_id,
439
+ cost_tokens=cost_tokens,
440
+ )
441
+
442
+ def _ensure_session_exists(
443
+ self, session_id: str, parent_event_id: str | None = None
444
+ ) -> None:
445
+ """
446
+ Create a session record if it doesn't exist.
447
+
448
+ Args:
449
+ session_id: Session ID to ensure exists
450
+ parent_event_id: Event that spawned this session (optional)
451
+ """
452
+ if not self._db.connection:
453
+ self._db.connect()
454
+
455
+ cursor = self._db.connection.cursor() # type: ignore[union-attr]
456
+ cursor.execute(
457
+ "SELECT COUNT(*) FROM sessions WHERE session_id = ?", (session_id,)
458
+ )
459
+ exists = cursor.fetchone()[0] > 0
460
+
461
+ if not exists:
462
+ # Create session record
463
+ self._db.insert_session(
464
+ session_id=session_id,
465
+ agent_assigned=self._agent_id,
466
+ is_subagent=self._parent_session is not None,
467
+ parent_session_id=self._parent_session,
468
+ parent_event_id=parent_event_id,
469
+ )
470
+
471
+ def reload(self) -> None:
472
+ """Reload all data from disk."""
473
+ self._graph.reload()
474
+ self._agent_interface.reload()
475
+ # SessionManager reloads implicitly on access via its converters/graphs
476
+
477
+ def summary(self, max_items: int = 10) -> str:
478
+ """
479
+ Get project summary.
480
+
481
+ Returns:
482
+ Compact overview for AI agent orientation
483
+ """
484
+ return self._agent_interface.get_summary(max_items)
@@ -0,0 +1,216 @@
1
+ from __future__ import annotations
2
+
3
+ """
4
+ SDK Constants and Settings
5
+
6
+ Centralized configuration for the HtmlGraph SDK using Pydantic.
7
+ """
8
+
9
+
10
+ from pathlib import Path
11
+ from typing import Any
12
+
13
+ try:
14
+ from pydantic import Field
15
+ from pydantic_settings import BaseSettings, SettingsConfigDict
16
+
17
+ _PYDANTIC_AVAILABLE = True
18
+ except ImportError:
19
+ # Fallback if pydantic-settings not available
20
+ _PYDANTIC_AVAILABLE = False
21
+ BaseSettings = object # type: ignore
22
+
23
+ def Field(**kwargs: Any) -> None: # type: ignore[misc,no-redef] # noqa: N802
24
+ """Fallback Field for environments without pydantic-settings."""
25
+ return None
26
+
27
+ SettingsConfigDict = dict # type: ignore
28
+
29
+
30
+ if _PYDANTIC_AVAILABLE:
31
+
32
+ class SDKSettings(BaseSettings):
33
+ """
34
+ HtmlGraph SDK Configuration.
35
+
36
+ Uses Pydantic Settings for configuration from environment variables,
37
+ .env files, and direct instantiation.
38
+
39
+ Environment variables are prefixed with HTMLGRAPH_ (e.g., HTMLGRAPH_PROJECT_ROOT).
40
+ """
41
+
42
+ # Core paths
43
+ project_root: Path = Field(default_factory=Path.cwd)
44
+ htmlgraph_dir_name: str = ".htmlgraph"
45
+
46
+ # Collection directories (relative to .htmlgraph)
47
+ features_dir: str = "features"
48
+ bugs_dir: str = "bugs"
49
+ chores_dir: str = "chores"
50
+ spikes_dir: str = "spikes"
51
+ epics_dir: str = "epics"
52
+ phases_dir: str = "phases"
53
+ sessions_dir: str = "sessions"
54
+ tracks_dir: str = "tracks"
55
+ agents_dir: str = "agents"
56
+ patterns_dir: str = "patterns"
57
+ insights_dir: str = "insights"
58
+ metrics_dir: str = "metrics"
59
+ todos_dir: str = "todos"
60
+ task_delegations_dir: str = "task-delegations"
61
+ archives_dir: str = "archives"
62
+
63
+ # Database
64
+ database_filename: str = "htmlgraph.db"
65
+ analytics_cache_filename: str = "index.sqlite"
66
+
67
+ # Session management
68
+ max_sessions: int = 100
69
+ session_retention_days: int = 30
70
+ auto_archive_sessions: bool = True
71
+
72
+ # Performance
73
+ max_query_results: int = 1000
74
+ cache_enabled: bool = True
75
+ cache_ttl_seconds: int = 3600
76
+
77
+ # Logging
78
+ log_level: str = "INFO"
79
+
80
+ # Agent detection
81
+ agent_env_var: str = "CLAUDE_AGENT_NAME"
82
+ parent_session_env_var: str = "HTMLGRAPH_PARENT_SESSION"
83
+
84
+ model_config = SettingsConfigDict(
85
+ env_prefix="HTMLGRAPH_",
86
+ env_file=".env",
87
+ case_sensitive=False,
88
+ extra="ignore",
89
+ )
90
+
91
+ def get_htmlgraph_dir(self: SDKSettings) -> Path: # type: ignore[misc]
92
+ """Get the .htmlgraph directory path."""
93
+ return Path(self.project_root) / self.htmlgraph_dir_name # type: ignore[no-any-return]
94
+
95
+ def get_collection_dir(self: SDKSettings, collection: str) -> Path:
96
+ """
97
+ Get the directory path for a specific collection.
98
+
99
+ Args:
100
+ collection: Collection name (e.g., "features", "bugs", "spikes")
101
+
102
+ Returns:
103
+ Path to collection directory
104
+ """
105
+ collection_attr = f"{collection}_dir"
106
+ if hasattr(self, collection_attr):
107
+ dir_name = getattr(self, collection_attr)
108
+ return Path(self.get_htmlgraph_dir()) / str(dir_name)
109
+ raise ValueError(f"Unknown collection: {collection}")
110
+
111
+ def get_database_path(self: SDKSettings) -> Path: # type: ignore[misc]
112
+ """Get the unified database path."""
113
+ return Path(self.get_htmlgraph_dir()) / self.database_filename # type: ignore[no-any-return]
114
+
115
+ def get_analytics_cache_path(self: SDKSettings) -> Path: # type: ignore[misc]
116
+ """Get the analytics cache database path."""
117
+ return Path(self.get_htmlgraph_dir()) / self.analytics_cache_filename # type: ignore[no-any-return]
118
+
119
+ def ensure_directories(self: SDKSettings) -> None: # type: ignore[misc]
120
+ """Create all collection directories if they don't exist."""
121
+ htmlgraph_dir = self.get_htmlgraph_dir()
122
+ htmlgraph_dir.mkdir(parents=True, exist_ok=True)
123
+
124
+ # Create all collection directories
125
+ for collection in [
126
+ "features",
127
+ "bugs",
128
+ "chores",
129
+ "spikes",
130
+ "epics",
131
+ "phases",
132
+ "sessions",
133
+ "tracks",
134
+ "agents",
135
+ "patterns",
136
+ "insights",
137
+ "metrics",
138
+ "todos",
139
+ "task_delegations",
140
+ "archives",
141
+ ]:
142
+ self.get_collection_dir(collection).mkdir(exist_ok=True)
143
+
144
+ else:
145
+ # Pydantic not available - provide simple fallback
146
+ class SDKSettings: # type: ignore[no-redef]
147
+ """Fallback settings without Pydantic."""
148
+
149
+ def __init__(self) -> None:
150
+ self.project_root = Path.cwd()
151
+ self.htmlgraph_dir_name = ".htmlgraph"
152
+ self.database_filename = "htmlgraph.db"
153
+ self.analytics_cache_filename = "index.sqlite"
154
+
155
+ def get_htmlgraph_dir(self) -> Path:
156
+ return self.project_root / self.htmlgraph_dir_name
157
+
158
+ def get_database_path(self) -> Path:
159
+ return self.get_htmlgraph_dir() / self.database_filename
160
+
161
+ def get_analytics_cache_path(self) -> Path:
162
+ return self.get_htmlgraph_dir() / self.analytics_cache_filename
163
+
164
+ default_settings = SDKSettings()
165
+
166
+
167
+ # Error messages (centralized)
168
+ ERROR_MESSAGES = {
169
+ "agent_required": (
170
+ "Agent identifier is required for work attribution. "
171
+ "Pass agent='name' to SDK() initialization. "
172
+ "Examples: SDK(agent='explorer'), SDK(agent='coder'), SDK(agent='tester')\n"
173
+ "Alternatively, set CLAUDE_AGENT_NAME environment variable.\n"
174
+ "Critical for: Work attribution, result retrieval, orchestrator tracking"
175
+ ),
176
+ "htmlgraph_not_found": (
177
+ "Could not find .htmlgraph directory in {path} or any parent directory. "
178
+ "Run 'htmlgraph init' to initialize a new project."
179
+ ),
180
+ "invalid_collection": "Unknown collection: {collection}",
181
+ "node_not_found": "Node not found: {node_id}",
182
+ "session_not_found": "Session not found: {session_id}",
183
+ }
184
+
185
+
186
+ # Work type constants
187
+ WORK_TYPES = [
188
+ "feature",
189
+ "bug",
190
+ "chore",
191
+ "spike",
192
+ "epic",
193
+ "phase",
194
+ "task",
195
+ "pattern",
196
+ "insight",
197
+ "metric",
198
+ ]
199
+
200
+
201
+ # Status constants
202
+ STATUSES = ["todo", "active", "done", "archived", "abandoned"]
203
+
204
+
205
+ # Priority constants
206
+ PRIORITIES = ["low", "medium", "high", "critical"]
207
+
208
+
209
+ __all__ = [
210
+ "SDKSettings",
211
+ "default_settings",
212
+ "ERROR_MESSAGES",
213
+ "WORK_TYPES",
214
+ "STATUSES",
215
+ "PRIORITIES",
216
+ ]