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.py DELETED
@@ -1,709 +0,0 @@
1
- """
2
- HtmlGraph SDK - AI-Friendly Interface
3
-
4
- Provides a fluent, ergonomic API for AI agents with:
5
- - Auto-discovery of .htmlgraph directory
6
- - Method chaining for all operations
7
- - Context managers for auto-save
8
- - Batch operations
9
- - Minimal boilerplate
10
-
11
- Example:
12
- from htmlgraph import SDK
13
-
14
- # Auto-discovers .htmlgraph directory
15
- sdk = SDK(agent="claude")
16
-
17
- # Fluent feature creation
18
- feature = sdk.features.create(
19
- title="User Authentication",
20
- track="auth"
21
- ).add_steps([
22
- "Create login endpoint",
23
- "Add JWT middleware",
24
- "Write tests"
25
- ]).set_priority("high").save()
26
-
27
- # Work on a feature
28
- with sdk.features.get("feature-001") as feature:
29
- feature.start()
30
- feature.complete_step(0)
31
- # Auto-saves on exit
32
-
33
- # Query
34
- todos = sdk.features.where(status="todo", priority="high")
35
-
36
- # Batch operations
37
- sdk.features.mark_done(["feat-001", "feat-002", "feat-003"])
38
- """
39
-
40
- from __future__ import annotations
41
- from datetime import datetime
42
- from pathlib import Path
43
- from typing import Any
44
-
45
- from htmlgraph.models import Node, Step
46
- from htmlgraph.graph import HtmlGraph
47
- from htmlgraph.agents import AgentInterface
48
- from htmlgraph.track_builder import TrackCollection
49
- from htmlgraph.collections import BaseCollection, FeatureCollection, SpikeCollection
50
- from htmlgraph.analytics import Analytics, DependencyAnalytics
51
- from htmlgraph.session_manager import SessionManager
52
-
53
-
54
- class SDK:
55
- """
56
- Main SDK interface for AI agents.
57
-
58
- Auto-discovers .htmlgraph directory and provides fluent API for all collections.
59
-
60
- Available Collections:
61
- - features: Feature work items with builder support
62
- - bugs: Bug reports
63
- - chores: Maintenance and chore tasks
64
- - spikes: Investigation and research spikes
65
- - epics: Large bodies of work
66
- - phases: Project phases
67
- - sessions: Agent sessions
68
- - tracks: Work tracks
69
- - agents: Agent information
70
-
71
- Example:
72
- sdk = SDK(agent="claude")
73
-
74
- # Work with features (has builder support)
75
- feature = sdk.features.create("User Auth")
76
- .set_priority("high")
77
- .add_steps(["Login", "Logout"])
78
- .save()
79
-
80
- # Work with bugs
81
- high_bugs = sdk.bugs.where(status="todo", priority="high")
82
- with sdk.bugs.edit("bug-001") as bug:
83
- bug.status = "in-progress"
84
-
85
- # Work with any collection
86
- all_spikes = sdk.spikes.all()
87
- sdk.chores.mark_done(["chore-001", "chore-002"])
88
- sdk.epics.assign(["epic-001"], agent="claude")
89
- """
90
-
91
- def __init__(
92
- self,
93
- directory: Path | str | None = None,
94
- agent: str | None = None
95
- ):
96
- """
97
- Initialize SDK.
98
-
99
- Args:
100
- directory: Path to .htmlgraph directory (auto-discovered if not provided)
101
- agent: Agent identifier for operations
102
- """
103
- if directory is None:
104
- directory = self._discover_htmlgraph()
105
-
106
- self._directory = Path(directory)
107
- self._agent_id = agent
108
-
109
- # Initialize SessionManager for smart tracking and attribution
110
- self.session_manager = SessionManager(self._directory)
111
-
112
- # Initialize underlying components (for backward compatibility)
113
- self._graph = HtmlGraph(self._directory / "features")
114
- self._agent_interface = AgentInterface(
115
- self._directory / "features",
116
- agent_id=agent
117
- )
118
-
119
- # Collection interfaces - all work item types
120
- self.features = FeatureCollection(self)
121
- self.bugs = BaseCollection(self, "bugs", "bug")
122
- self.chores = BaseCollection(self, "chores", "chore")
123
- self.spikes = SpikeCollection(self)
124
- self.epics = BaseCollection(self, "epics", "epic")
125
- self.phases = BaseCollection(self, "phases", "phase")
126
-
127
- # Non-work collections
128
- self.sessions = BaseCollection(self, "sessions", "session")
129
- self.tracks = TrackCollection(self) # Use specialized collection with builder support
130
- self.agents = BaseCollection(self, "agents", "agent")
131
-
132
- # Analytics interface (Phase 2: Work Type Analytics)
133
- self.analytics = Analytics(self)
134
-
135
- # Dependency analytics interface (Advanced graph analytics)
136
- self.dep_analytics = DependencyAnalytics(self._graph)
137
-
138
- @staticmethod
139
- def _discover_htmlgraph() -> Path:
140
- """
141
- Auto-discover .htmlgraph directory.
142
-
143
- Searches current directory and parents.
144
- """
145
- current = Path.cwd()
146
-
147
- # Check current directory
148
- if (current / ".htmlgraph").exists():
149
- return current / ".htmlgraph"
150
-
151
- # Check parent directories
152
- for parent in current.parents:
153
- if (parent / ".htmlgraph").exists():
154
- return parent / ".htmlgraph"
155
-
156
- # Default to current directory
157
- return current / ".htmlgraph"
158
-
159
- @property
160
- def agent(self) -> str | None:
161
- """Get current agent ID."""
162
- return self._agent_id
163
-
164
- def reload(self) -> None:
165
- """Reload all data from disk."""
166
- self._graph.reload()
167
- self._agent_interface.reload()
168
- # SessionManager reloads implicitly on access via its converters/graphs
169
-
170
- def summary(self, max_items: int = 10) -> str:
171
- """
172
- Get project summary.
173
-
174
- Returns:
175
- Compact overview for AI agent orientation
176
- """
177
- return self._agent_interface.get_summary(max_items)
178
-
179
- def my_work(self) -> dict[str, Any]:
180
- """
181
- Get current agent's workload.
182
-
183
- Returns:
184
- Dict with in_progress, completed counts
185
- """
186
- if not self._agent_id:
187
- raise ValueError("No agent ID set")
188
- return self._agent_interface.get_workload(self._agent_id)
189
-
190
- def next_task(
191
- self,
192
- priority: str | None = None,
193
- auto_claim: bool = True
194
- ) -> Node | None:
195
- """
196
- Get next available task for this agent.
197
-
198
- Args:
199
- priority: Optional priority filter
200
- auto_claim: Automatically claim the task
201
-
202
- Returns:
203
- Next available Node or None
204
- """
205
- return self._agent_interface.get_next_task(
206
- agent_id=self._agent_id,
207
- priority=priority,
208
- node_type="feature",
209
- auto_claim=auto_claim
210
- )
211
-
212
- def set_session_handoff(
213
- self,
214
- handoff_notes: str | None = None,
215
- recommended_next: str | None = None,
216
- blockers: list[str] | None = None,
217
- session_id: str | None = None,
218
- ):
219
- """
220
- Set handoff context on a session.
221
-
222
- Args:
223
- handoff_notes: Notes for next session/agent
224
- recommended_next: Suggested next steps
225
- blockers: List of blockers
226
- session_id: Specific session ID (defaults to active session)
227
-
228
- Returns:
229
- Updated Session or None if not found
230
- """
231
- if not session_id:
232
- if self._agent_id:
233
- active = self.session_manager.get_active_session_for_agent(self._agent_id)
234
- else:
235
- active = self.session_manager.get_active_session()
236
- if not active:
237
- return None
238
- session_id = active.id
239
-
240
- return self.session_manager.set_session_handoff(
241
- session_id=session_id,
242
- handoff_notes=handoff_notes,
243
- recommended_next=recommended_next,
244
- blockers=blockers,
245
- )
246
-
247
- def start_session(
248
- self,
249
- session_id: str | None = None,
250
- title: str | None = None,
251
- agent: str | None = None
252
- ) -> Any:
253
- """
254
- Start a new session.
255
-
256
- Args:
257
- session_id: Optional session ID
258
- title: Optional session title
259
- agent: Optional agent override (defaults to SDK agent)
260
-
261
- Returns:
262
- New Session instance
263
- """
264
- return self.session_manager.start_session(
265
- session_id=session_id,
266
- agent=agent or self._agent_id or "cli",
267
- title=title
268
- )
269
-
270
- def end_session(
271
- self,
272
- session_id: str,
273
- handoff_notes: str | None = None,
274
- recommended_next: str | None = None,
275
- blockers: list[str] | None = None,
276
- ) -> Any:
277
- """
278
- End a session.
279
-
280
- Args:
281
- session_id: Session ID to end
282
- handoff_notes: Optional handoff notes
283
- recommended_next: Optional recommendations
284
- blockers: Optional blockers
285
-
286
- Returns:
287
- Ended Session instance
288
- """
289
- return self.session_manager.end_session(
290
- session_id=session_id,
291
- handoff_notes=handoff_notes,
292
- recommended_next=recommended_next,
293
- blockers=blockers
294
- )
295
-
296
- def get_status(self) -> dict[str, Any]:
297
- """
298
- Get project status.
299
-
300
- Returns:
301
- Dict with status metrics (WIP, counts, etc.)
302
- """
303
- return self.session_manager.get_status()
304
-
305
- def dedupe_sessions(
306
- self,
307
- max_events: int = 1,
308
- move_dir_name: str = "_orphans",
309
- dry_run: bool = False,
310
- stale_extra_active: bool = True,
311
- ) -> dict[str, int]:
312
- """
313
- Move low-signal sessions (e.g. SessionStart-only) out of the main sessions dir.
314
-
315
- Args:
316
- max_events: Maximum events threshold (sessions with <= this many events are moved)
317
- move_dir_name: Directory name to move orphaned sessions to
318
- dry_run: If True, only report what would be done without actually moving files
319
- stale_extra_active: If True, also mark extra active sessions as stale
320
-
321
- Returns:
322
- Dict with counts: {"scanned": int, "moved": int, "missing": int, "staled_active": int, "kept_active": int}
323
-
324
- Example:
325
- >>> sdk = SDK(agent="claude")
326
- >>> result = sdk.dedupe_sessions(max_events=1, dry_run=False)
327
- >>> print(f"Scanned: {result['scanned']}, Moved: {result['moved']}")
328
- """
329
- return self.session_manager.dedupe_orphan_sessions(
330
- max_events=max_events,
331
- move_dir_name=move_dir_name,
332
- dry_run=dry_run,
333
- stale_extra_active=stale_extra_active,
334
- )
335
-
336
- def track_activity(
337
- self,
338
- tool: str,
339
- summary: str,
340
- file_paths: list[str] | None = None,
341
- success: bool = True,
342
- feature_id: str | None = None,
343
- session_id: str | None = None,
344
- parent_activity_id: str | None = None,
345
- payload: dict[str, Any] | None = None,
346
- ) -> Any:
347
- """
348
- Track an activity in the current or specified session.
349
-
350
- Args:
351
- tool: Tool name (Edit, Bash, Read, etc.)
352
- summary: Human-readable summary of the activity
353
- file_paths: Files involved in this activity
354
- success: Whether the tool call succeeded
355
- feature_id: Explicit feature ID (skips attribution if provided)
356
- session_id: Session ID (defaults to active session for current agent)
357
- parent_activity_id: ID of parent activity (e.g., Skill/Task invocation)
358
- payload: Optional rich payload data
359
-
360
- Returns:
361
- Created ActivityEntry with attribution
362
-
363
- Example:
364
- >>> sdk = SDK(agent="claude")
365
- >>> entry = sdk.track_activity(
366
- ... tool="CustomTool",
367
- ... summary="Performed custom analysis",
368
- ... file_paths=["src/main.py"],
369
- ... success=True
370
- ... )
371
- >>> print(f"Tracked: [{entry.tool}] {entry.summary}")
372
- """
373
- # Find active session if not specified
374
- if not session_id:
375
- active = self.session_manager.get_active_session(agent=self._agent_id)
376
- if not active:
377
- raise ValueError("No active session. Start one with sdk.start_session()")
378
- session_id = active.id
379
-
380
- return self.session_manager.track_activity(
381
- session_id=session_id,
382
- tool=tool,
383
- summary=summary,
384
- file_paths=file_paths,
385
- success=success,
386
- feature_id=feature_id,
387
- parent_activity_id=parent_activity_id,
388
- payload=payload,
389
- )
390
-
391
- # =========================================================================
392
- # Strategic Planning & Analytics (Agent-Friendly Interface)
393
- # =========================================================================
394
-
395
- def find_bottlenecks(self, top_n: int = 5) -> list[dict[str, Any]]:
396
- """
397
- Identify tasks blocking the most downstream work.
398
-
399
- Args:
400
- top_n: Maximum number of bottlenecks to return
401
-
402
- Returns:
403
- List of bottleneck tasks with impact metrics
404
-
405
- Example:
406
- >>> sdk = SDK(agent="claude")
407
- >>> bottlenecks = sdk.find_bottlenecks(top_n=3)
408
- >>> for bn in bottlenecks:
409
- ... print(f"{bn['title']} blocks {bn['blocks_count']} tasks")
410
- """
411
- return self._agent_interface.find_bottlenecks(top_n=top_n)
412
-
413
- def get_parallel_work(self, max_agents: int = 5) -> dict[str, Any]:
414
- """
415
- Find tasks that can be worked on simultaneously.
416
-
417
- Args:
418
- max_agents: Maximum number of parallel agents to plan for
419
-
420
- Returns:
421
- Dict with parallelization opportunities
422
-
423
- Example:
424
- >>> sdk = SDK(agent="claude")
425
- >>> parallel = sdk.get_parallel_work(max_agents=3)
426
- >>> print(f"Can work on {parallel['max_parallelism']} tasks at once")
427
- >>> print(f"Ready now: {parallel['ready_now']}")
428
- """
429
- return self._agent_interface.get_parallel_work(max_agents=max_agents)
430
-
431
- def recommend_next_work(self, agent_count: int = 1) -> list[dict[str, Any]]:
432
- """
433
- Get smart recommendations for what to work on next.
434
-
435
- Considers priority, dependencies, and transitive impact.
436
-
437
- Args:
438
- agent_count: Number of agents/tasks to recommend
439
-
440
- Returns:
441
- List of recommended tasks with reasoning
442
-
443
- Example:
444
- >>> sdk = SDK(agent="claude")
445
- >>> recs = sdk.recommend_next_work(agent_count=3)
446
- >>> for rec in recs:
447
- ... print(f"{rec['title']} (score: {rec['score']})")
448
- ... print(f" Reasons: {rec['reasons']}")
449
- """
450
- return self._agent_interface.recommend_next_work(agent_count=agent_count)
451
-
452
- def assess_risks(self) -> dict[str, Any]:
453
- """
454
- Assess dependency-related risks in the project.
455
-
456
- Identifies single points of failure, circular dependencies,
457
- and orphaned tasks.
458
-
459
- Returns:
460
- Dict with risk assessment results
461
-
462
- Example:
463
- >>> sdk = SDK(agent="claude")
464
- >>> risks = sdk.assess_risks()
465
- >>> if risks['high_risk_count'] > 0:
466
- ... print(f"Warning: {risks['high_risk_count']} high-risk tasks")
467
- """
468
- return self._agent_interface.assess_risks()
469
-
470
- def analyze_impact(self, node_id: str) -> dict[str, Any]:
471
- """
472
- Analyze the impact of completing a specific task.
473
-
474
- Args:
475
- node_id: Task to analyze
476
-
477
- Returns:
478
- Dict with impact analysis
479
-
480
- Example:
481
- >>> sdk = SDK(agent="claude")
482
- >>> impact = sdk.analyze_impact("feature-001")
483
- >>> print(f"Completing this unlocks {impact['unlocks_count']} tasks")
484
- """
485
- return self._agent_interface.analyze_impact(node_id)
486
-
487
- # =========================================================================
488
- # Planning Workflow Integration
489
- # =========================================================================
490
-
491
- def start_planning_spike(
492
- self,
493
- title: str,
494
- context: str = "",
495
- timebox_hours: float = 4.0,
496
- auto_start: bool = True
497
- ) -> Node:
498
- """
499
- Create a planning spike to research and design before implementation.
500
-
501
- This is for timeboxed investigation before creating a full track.
502
-
503
- Args:
504
- title: Spike title (e.g., "Plan User Authentication System")
505
- context: Background information
506
- timebox_hours: Time limit for spike (default: 4 hours)
507
- auto_start: Automatically start the spike (default: True)
508
-
509
- Returns:
510
- Created spike Node
511
-
512
- Example:
513
- >>> sdk = SDK(agent="claude")
514
- >>> spike = sdk.start_planning_spike(
515
- ... "Plan Real-time Notifications",
516
- ... context="Users need live updates. Research options.",
517
- ... timebox_hours=3.0
518
- ... )
519
- """
520
- from htmlgraph.models import Spike, SpikeType
521
- from htmlgraph.ids import generate_id
522
-
523
- # Create spike directly (SpikeBuilder doesn't exist yet)
524
- spike_id = generate_id(node_type="spike", title=title)
525
- spike = Spike(
526
- id=spike_id,
527
- title=title,
528
- type="spike",
529
- status="in-progress" if auto_start and self._agent_id else "todo",
530
- spike_type=SpikeType.ARCHITECTURAL,
531
- timebox_hours=int(timebox_hours),
532
- agent_assigned=self._agent_id if auto_start and self._agent_id else None,
533
- steps=[
534
- Step(description="Research existing solutions and patterns"),
535
- Step(description="Define requirements and constraints"),
536
- Step(description="Design high-level architecture"),
537
- Step(description="Identify dependencies and risks"),
538
- Step(description="Create implementation plan")
539
- ],
540
- content=f"<p>{context}</p>" if context else "",
541
- edges={},
542
- properties={}
543
- )
544
-
545
- self._graph.add(spike)
546
- return spike
547
-
548
- def create_track_from_plan(
549
- self,
550
- title: str,
551
- description: str,
552
- spike_id: str | None = None,
553
- priority: str = "high",
554
- requirements: list[str | tuple[str, str]] | None = None,
555
- phases: list[tuple[str, list[str]]] | None = None
556
- ) -> dict[str, Any]:
557
- """
558
- Create a track with spec and plan from planning results.
559
-
560
- Args:
561
- title: Track title
562
- description: Track description
563
- spike_id: Optional spike ID that led to this track
564
- priority: Track priority (default: "high")
565
- requirements: List of requirements (strings or (req, priority) tuples)
566
- phases: List of (phase_name, tasks) tuples for the plan
567
-
568
- Returns:
569
- Dict with track, spec, and plan details
570
-
571
- Example:
572
- >>> sdk = SDK(agent="claude")
573
- >>> track_info = sdk.create_track_from_plan(
574
- ... title="User Authentication System",
575
- ... description="OAuth 2.0 with JWT tokens",
576
- ... requirements=[
577
- ... ("OAuth 2.0 integration", "must-have"),
578
- ... ("JWT token management", "must-have"),
579
- ... "Password reset flow"
580
- ... ],
581
- ... phases=[
582
- ... ("Phase 1: OAuth", ["Setup providers (2h)", "Callback (2h)"]),
583
- ... ("Phase 2: JWT", ["Token signing (2h)", "Refresh (1.5h)"])
584
- ... ]
585
- ... )
586
- """
587
- from htmlgraph.track_builder import TrackBuilder
588
-
589
- builder = self.tracks.builder() \
590
- .title(title) \
591
- .description(description) \
592
- .priority(priority)
593
-
594
- # Add reference to planning spike if provided
595
- if spike_id:
596
- builder._data["properties"]["planning_spike"] = spike_id
597
-
598
- # Add spec if requirements provided
599
- if requirements:
600
- # Convert simple strings to (requirement, "must-have") tuples
601
- req_list = []
602
- for req in requirements:
603
- if isinstance(req, str):
604
- req_list.append((req, "must-have"))
605
- else:
606
- req_list.append(req)
607
-
608
- builder.with_spec(
609
- overview=description,
610
- context=f"Track created from planning spike: {spike_id}" if spike_id else "",
611
- requirements=req_list,
612
- acceptance_criteria=[]
613
- )
614
-
615
- # Add plan if phases provided
616
- if phases:
617
- builder.with_plan_phases(phases)
618
-
619
- track = builder.create()
620
-
621
- return {
622
- "track_id": track.id,
623
- "title": track.title,
624
- "has_spec": bool(requirements),
625
- "has_plan": bool(phases),
626
- "spike_id": spike_id,
627
- "priority": priority
628
- }
629
-
630
- def smart_plan(
631
- self,
632
- description: str,
633
- create_spike: bool = True,
634
- timebox_hours: float = 4.0
635
- ) -> dict[str, Any]:
636
- """
637
- Smart planning workflow: analyzes project context and creates spike or track.
638
-
639
- This is the main entry point for planning new work. It:
640
- 1. Checks current project state
641
- 2. Provides context from strategic analytics
642
- 3. Creates a planning spike or track as appropriate
643
-
644
- Args:
645
- description: What you want to plan (e.g., "User authentication system")
646
- create_spike: Create a spike for research (default: True)
647
- timebox_hours: If creating spike, time limit (default: 4 hours)
648
-
649
- Returns:
650
- Dict with planning context and created spike/track info
651
-
652
- Example:
653
- >>> sdk = SDK(agent="claude")
654
- >>> plan = sdk.smart_plan(
655
- ... "Real-time notifications system",
656
- ... create_spike=True
657
- ... )
658
- >>> print(f"Created: {plan['spike_id']}")
659
- >>> print(f"Context: {plan['project_context']}")
660
- """
661
- # Get project context from strategic analytics
662
- bottlenecks = self.find_bottlenecks(top_n=3)
663
- risks = self.assess_risks()
664
- parallel = self.get_parallel_work(max_agents=5)
665
-
666
- context = {
667
- "bottlenecks_count": len(bottlenecks),
668
- "high_risk_count": risks["high_risk_count"],
669
- "parallel_capacity": parallel["max_parallelism"],
670
- "description": description
671
- }
672
-
673
- if create_spike:
674
- spike = self.start_planning_spike(
675
- title=f"Plan: {description}",
676
- context=f"Project context:\n- {len(bottlenecks)} bottlenecks\n- {risks['high_risk_count']} high-risk items\n- {parallel['max_parallelism']} parallel capacity",
677
- timebox_hours=timebox_hours
678
- )
679
-
680
- return {
681
- "type": "spike",
682
- "spike_id": spike.id,
683
- "title": spike.title,
684
- "status": spike.status,
685
- "timebox_hours": timebox_hours,
686
- "project_context": context,
687
- "next_steps": [
688
- "Research and design the solution",
689
- "Complete spike steps",
690
- "Use SDK.create_track_from_plan() to create track"
691
- ]
692
- }
693
- else:
694
- # Direct track creation (for when you already know what to do)
695
- track_info = self.create_track_from_plan(
696
- title=description,
697
- description=f"Planned with context: {context}"
698
- )
699
-
700
- return {
701
- "type": "track",
702
- **track_info,
703
- "project_context": context,
704
- "next_steps": [
705
- "Create features from track plan",
706
- "Link features to track",
707
- "Start implementation"
708
- ]
709
- }