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
@@ -0,0 +1,186 @@
1
+ """Parallel work detection and orchestration."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Any
6
+
7
+ if TYPE_CHECKING:
8
+ pass
9
+
10
+
11
+ def get_parallel_work(sdk: Any, max_agents: int = 5) -> dict[str, Any]:
12
+ """
13
+ Find tasks that can be worked on simultaneously.
14
+
15
+ Note: Prefer using sdk.dep_analytics.find_parallelizable_work() directly.
16
+ This method exists for backward compatibility.
17
+
18
+ Args:
19
+ sdk: SDK instance
20
+ max_agents: Maximum number of parallel agents to plan for
21
+
22
+ Returns:
23
+ Dict with parallelization opportunities
24
+
25
+ Example:
26
+ >>> sdk = SDK(agent="claude")
27
+ >>> # Preferred approach
28
+ >>> report = sdk.dep_analytics.find_parallelizable_work(status="todo")
29
+ >>> # Or via SDK (backward compatibility)
30
+ >>> parallel = sdk.get_parallel_work(max_agents=3)
31
+ >>> logger.info(f"Can work on {parallel['max_parallelism']} tasks at once")
32
+ >>> logger.info(f"Ready now: {parallel['ready_now']}")
33
+ """
34
+ report = sdk.dep_analytics.find_parallelizable_work(status="todo")
35
+
36
+ ready_now = report.dependency_levels[0].nodes if report.dependency_levels else []
37
+
38
+ return {
39
+ "max_parallelism": report.max_parallelism,
40
+ "ready_now": ready_now[:max_agents],
41
+ "total_ready": len(ready_now),
42
+ "level_count": len(report.dependency_levels),
43
+ "next_level": report.dependency_levels[1].nodes
44
+ if len(report.dependency_levels) > 1
45
+ else [],
46
+ }
47
+
48
+
49
+ def plan_parallel_work(
50
+ sdk: Any,
51
+ max_agents: int = 5,
52
+ shared_files: list[str] | None = None,
53
+ ) -> dict[str, Any]:
54
+ """
55
+ Plan and prepare parallel work execution.
56
+
57
+ This integrates with smart_plan to enable parallel agent dispatch.
58
+ Uses the 6-phase ParallelWorkflow:
59
+ 1. Pre-flight analysis (dependencies, risks)
60
+ 2. Context preparation (shared file caching)
61
+ 3. Prompt generation (for Task tool)
62
+
63
+ Args:
64
+ sdk: SDK instance
65
+ max_agents: Maximum parallel agents (default: 5)
66
+ shared_files: Files to pre-cache for all agents
67
+
68
+ Returns:
69
+ Dict with parallel execution plan:
70
+ - can_parallelize: Whether parallelization is recommended
71
+ - analysis: Pre-flight analysis results
72
+ - prompts: Ready-to-use Task tool prompts
73
+ - recommendations: Optimization suggestions
74
+
75
+ Example:
76
+ >>> sdk = SDK(agent="orchestrator")
77
+ >>> plan = sdk.plan_parallel_work(max_agents=3)
78
+ >>> if plan["can_parallelize"]:
79
+ ... # Use prompts with Task tool
80
+ ... for p in plan["prompts"]:
81
+ ... Task(prompt=p["prompt"], description=p["description"])
82
+ """
83
+ from htmlgraph.parallel import ParallelWorkflow
84
+
85
+ workflow = ParallelWorkflow(sdk)
86
+
87
+ # Phase 1: Pre-flight analysis
88
+ analysis = workflow.analyze(max_agents=max_agents)
89
+
90
+ result = {
91
+ "can_parallelize": analysis.can_parallelize,
92
+ "max_parallelism": analysis.max_parallelism,
93
+ "ready_tasks": analysis.ready_tasks,
94
+ "blocked_tasks": analysis.blocked_tasks,
95
+ "speedup_factor": analysis.speedup_factor,
96
+ "recommendation": analysis.recommendation,
97
+ "warnings": analysis.warnings,
98
+ "prompts": [],
99
+ }
100
+
101
+ if not analysis.can_parallelize:
102
+ result["reason"] = analysis.recommendation
103
+ return result
104
+
105
+ # Phase 2 & 3: Prepare tasks and generate prompts
106
+ tasks = workflow.prepare_tasks(
107
+ analysis.ready_tasks[:max_agents],
108
+ shared_files=shared_files,
109
+ )
110
+ prompts = workflow.generate_prompts(tasks)
111
+
112
+ result["prompts"] = prompts
113
+ result["task_count"] = len(prompts)
114
+
115
+ # Add efficiency guidelines
116
+ result["guidelines"] = {
117
+ "dispatch": "Send ALL Task calls in a SINGLE message for true parallelism",
118
+ "patterns": [
119
+ "Grep → Read (search before reading)",
120
+ "Read → Edit → Bash (read, modify, test)",
121
+ "Glob → Read (find files first)",
122
+ ],
123
+ "avoid": [
124
+ "Sequential Task calls (loses parallelism)",
125
+ "Read → Read → Read (cache instead)",
126
+ "Edit → Edit → Edit (batch edits)",
127
+ ],
128
+ }
129
+
130
+ return result
131
+
132
+
133
+ def aggregate_parallel_results(
134
+ sdk: Any,
135
+ agent_ids: list[str],
136
+ ) -> dict[str, Any]:
137
+ """
138
+ Aggregate results from parallel agent execution.
139
+
140
+ Call this after parallel agents complete to:
141
+ - Collect health metrics
142
+ - Detect anti-patterns
143
+ - Identify conflicts
144
+ - Generate recommendations
145
+
146
+ Args:
147
+ sdk: SDK instance
148
+ agent_ids: List of agent/transcript IDs to analyze
149
+
150
+ Returns:
151
+ Dict with aggregated results and validation
152
+
153
+ Example:
154
+ >>> # After parallel work completes
155
+ >>> results = sdk.aggregate_parallel_results([
156
+ ... "agent-abc123",
157
+ ... "agent-def456",
158
+ ... "agent-ghi789",
159
+ ... ])
160
+ >>> logger.info(f"Health: {results['avg_health_score']:.0%}")
161
+ >>> logger.info(f"Conflicts: {results['conflicts']}")
162
+ """
163
+ from htmlgraph.parallel import ParallelWorkflow
164
+
165
+ workflow = ParallelWorkflow(sdk)
166
+
167
+ # Phase 5: Aggregate
168
+ aggregate = workflow.aggregate(agent_ids)
169
+
170
+ # Phase 6: Validate
171
+ validation = workflow.validate(aggregate)
172
+
173
+ return {
174
+ "total_agents": aggregate.total_agents,
175
+ "successful": aggregate.successful,
176
+ "failed": aggregate.failed,
177
+ "total_duration_seconds": aggregate.total_duration_seconds,
178
+ "parallel_speedup": aggregate.parallel_speedup,
179
+ "avg_health_score": aggregate.avg_health_score,
180
+ "total_anti_patterns": aggregate.total_anti_patterns,
181
+ "files_modified": aggregate.files_modified,
182
+ "conflicts": aggregate.conflicts,
183
+ "recommendations": aggregate.recommendations,
184
+ "validation": validation,
185
+ "all_passed": all(validation.values()),
186
+ }
@@ -0,0 +1,210 @@
1
+ """Work queue management."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Any
6
+
7
+ if TYPE_CHECKING:
8
+ from htmlgraph.models import Node
9
+
10
+
11
+ def get_work_queue(
12
+ sdk: Any, agent_id: str | None = None, limit: int = 10, min_score: float = 0.0
13
+ ) -> list[dict[str, Any]]:
14
+ """
15
+ Get prioritized work queue showing recommended work, active work, and dependencies.
16
+
17
+ This method provides a comprehensive view of:
18
+ 1. Recommended next work (using smart analytics)
19
+ 2. Active work by all agents
20
+ 3. Blocked items and what's blocking them
21
+ 4. Priority-based scoring
22
+
23
+ Args:
24
+ sdk: SDK instance
25
+ agent_id: Agent to get queue for (defaults to SDK agent)
26
+ limit: Maximum number of items to return (default: 10)
27
+ min_score: Minimum score threshold (default: 0.0)
28
+
29
+ Returns:
30
+ List of work queue items with scoring and metadata:
31
+ - task_id: Work item ID
32
+ - title: Work item title
33
+ - status: Current status
34
+ - priority: Priority level
35
+ - score: Routing score
36
+ - complexity: Complexity level (if set)
37
+ - effort: Estimated effort (if set)
38
+ - blocks_count: Number of tasks this blocks (if any)
39
+ - blocked_by: List of blocking task IDs (if blocked)
40
+ - agent_assigned: Current assignee (if any)
41
+ - type: Work item type (feature, bug, spike, etc.)
42
+
43
+ Example:
44
+ >>> sdk = SDK(agent="claude")
45
+ >>> queue = sdk.get_work_queue(limit=5)
46
+ >>> for item in queue:
47
+ ... logger.info(f"{item['score']:.1f} - {item['title']}")
48
+ ... if item.get('blocked_by'):
49
+ ... logger.info(f" ⚠️ Blocked by: {', '.join(item['blocked_by'])}")
50
+ """
51
+ from htmlgraph.routing import AgentCapabilityRegistry, CapabilityMatcher
52
+
53
+ agent = agent_id or sdk._agent_id or "cli"
54
+
55
+ # Get all work item types
56
+ all_work = []
57
+ for collection_name in ["features", "bugs", "spikes", "chores", "epics"]:
58
+ collection = getattr(sdk, collection_name, None)
59
+ if collection:
60
+ # Get todo and blocked items
61
+ for item in collection.where(status="todo"):
62
+ all_work.append(item)
63
+ for item in collection.where(status="blocked"):
64
+ all_work.append(item)
65
+
66
+ if not all_work:
67
+ return []
68
+
69
+ # Get recommendations from analytics (uses strategic scoring)
70
+ from htmlgraph.sdk.planning.recommendations import recommend_next_work
71
+
72
+ recommendations = recommend_next_work(sdk, agent_count=limit * 2)
73
+ rec_scores = {rec["id"]: rec["score"] for rec in recommendations}
74
+
75
+ # Build routing registry
76
+ registry = AgentCapabilityRegistry()
77
+
78
+ # Register current agent
79
+ registry.register_agent(agent, capabilities=[], wip_limit=5)
80
+
81
+ # Get current WIP count for agent
82
+ wip_count = len(sdk.features.where(status="in-progress", agent_assigned=agent))
83
+ registry.set_wip(agent, wip_count)
84
+
85
+ # Score each work item
86
+ queue_items = []
87
+ for item in all_work:
88
+ # Use strategic score if available, otherwise use routing score
89
+ if item.id in rec_scores:
90
+ score = rec_scores[item.id]
91
+ else:
92
+ # Fallback to routing score
93
+ agent_profile = registry.get_agent(agent)
94
+ if agent_profile:
95
+ score = CapabilityMatcher.score_agent_task_fit(agent_profile, item)
96
+ else:
97
+ score = 0.0
98
+
99
+ # Apply minimum score filter
100
+ if score < min_score:
101
+ continue
102
+
103
+ # Build queue item
104
+ queue_item = {
105
+ "task_id": item.id,
106
+ "title": item.title,
107
+ "status": item.status,
108
+ "priority": item.priority,
109
+ "score": score,
110
+ "type": item.type,
111
+ "complexity": getattr(item, "complexity", None),
112
+ "effort": getattr(item, "estimated_effort", None),
113
+ "agent_assigned": getattr(item, "agent_assigned", None),
114
+ "blocks_count": 0,
115
+ "blocked_by": [],
116
+ }
117
+
118
+ # Add dependency information
119
+ if hasattr(item, "edges"):
120
+ # Check if this item blocks others
121
+ blocks = item.edges.get("blocks", [])
122
+ queue_item["blocks_count"] = len(blocks)
123
+
124
+ # Check if this item is blocked
125
+ blocked_by = item.edges.get("blocked_by", [])
126
+ queue_item["blocked_by"] = blocked_by
127
+
128
+ queue_items.append(queue_item)
129
+
130
+ # Sort by score (descending)
131
+ queue_items.sort(key=lambda x: x["score"], reverse=True)
132
+
133
+ # Limit results
134
+ return queue_items[:limit]
135
+
136
+
137
+ def work_next(
138
+ sdk: Any,
139
+ agent_id: str | None = None,
140
+ auto_claim: bool = False,
141
+ min_score: float = 0.0,
142
+ ) -> Node | None:
143
+ """
144
+ Get the next best task for an agent using smart routing.
145
+
146
+ Uses both strategic analytics and capability-based routing to find
147
+ the optimal next task.
148
+
149
+ Args:
150
+ sdk: SDK instance
151
+ agent_id: Agent to get task for (defaults to SDK agent)
152
+ auto_claim: Automatically claim the task (default: False)
153
+ min_score: Minimum score threshold (default: 0.0)
154
+
155
+ Returns:
156
+ Next best Node or None if no suitable task found
157
+
158
+ Example:
159
+ >>> sdk = SDK(agent="claude")
160
+ >>> task = sdk.work_next(auto_claim=True)
161
+ >>> if task:
162
+ ... logger.info(f"Working on: {task.title}")
163
+ ... # Task is automatically claimed and assigned
164
+ """
165
+ agent = agent_id or sdk._agent_id or "cli"
166
+
167
+ # Get work queue - get more items since we filter for actionable (todo) only
168
+ queue = get_work_queue(sdk, agent_id=agent, limit=20, min_score=min_score)
169
+
170
+ if not queue:
171
+ return None
172
+
173
+ # Find the first actionable (todo) task - blocked tasks are not actionable
174
+ top_item = None
175
+ for item in queue:
176
+ if item["status"] == "todo":
177
+ top_item = item
178
+ break
179
+
180
+ if top_item is None:
181
+ return None
182
+
183
+ # Fetch the actual node
184
+ task = None
185
+ for collection_name in ["features", "bugs", "spikes", "chores", "epics"]:
186
+ collection = getattr(sdk, collection_name, None)
187
+ if collection:
188
+ try:
189
+ task = collection.get(top_item["task_id"])
190
+ if task:
191
+ break
192
+ except (ValueError, FileNotFoundError):
193
+ continue
194
+
195
+ if not task:
196
+ return None
197
+
198
+ # Auto-claim if requested
199
+ if auto_claim and task.status == "todo" and collection is not None:
200
+ # Claim the task
201
+ # collection.edit returns context manager or None
202
+ task_editor: Any = collection.edit(task.id)
203
+ if task_editor is not None:
204
+ # collection.edit returns context manager
205
+ with task_editor as t:
206
+ t.status = "in-progress"
207
+ t.agent_assigned = agent
208
+
209
+ result: Node | None = task
210
+ return result
@@ -0,0 +1,87 @@
1
+ """Smart work recommendations."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import TYPE_CHECKING, Any
6
+
7
+ if TYPE_CHECKING:
8
+ pass
9
+
10
+
11
+ def recommend_next_work(sdk: Any, agent_count: int = 1) -> list[dict[str, Any]]:
12
+ """
13
+ Get smart recommendations for what to work on next.
14
+
15
+ Note: Prefer using sdk.dep_analytics.recommend_next_tasks() directly.
16
+ This method exists for backward compatibility.
17
+
18
+ Considers priority, dependencies, and transitive impact.
19
+
20
+ Args:
21
+ sdk: SDK instance
22
+ agent_count: Number of agents/tasks to recommend
23
+
24
+ Returns:
25
+ List of recommended tasks with reasoning
26
+
27
+ Example:
28
+ >>> sdk = SDK(agent="claude")
29
+ >>> # Preferred approach
30
+ >>> recs = sdk.dep_analytics.recommend_next_tasks(agent_count=3)
31
+ >>> # Or via SDK (backward compatibility)
32
+ >>> recs = sdk.recommend_next_work(agent_count=3)
33
+ >>> for rec in recs:
34
+ ... logger.info(f"{rec['title']} (score: {rec['score']})")
35
+ ... logger.info(f" Reasons: {rec['reasons']}")
36
+ """
37
+ recommendations = sdk.dep_analytics.recommend_next_tasks(
38
+ agent_count=agent_count, lookahead=5
39
+ )
40
+
41
+ return [
42
+ {
43
+ "id": rec.id,
44
+ "title": rec.title,
45
+ "priority": rec.priority,
46
+ "score": rec.score,
47
+ "reasons": rec.reasons,
48
+ "estimated_hours": rec.estimated_effort,
49
+ "unlocks_count": len(rec.unlocks),
50
+ "unlocks": rec.unlocks[:3],
51
+ }
52
+ for rec in recommendations.recommendations
53
+ ]
54
+
55
+
56
+ def analyze_impact(sdk: Any, node_id: str) -> dict[str, Any]:
57
+ """
58
+ Analyze the impact of completing a specific task.
59
+
60
+ Note: Prefer using sdk.dep_analytics.impact_analysis() directly.
61
+ This method exists for backward compatibility.
62
+
63
+ Args:
64
+ sdk: SDK instance
65
+ node_id: Task to analyze
66
+
67
+ Returns:
68
+ Dict with impact analysis
69
+
70
+ Example:
71
+ >>> sdk = SDK(agent="claude")
72
+ >>> # Preferred approach
73
+ >>> impact = sdk.dep_analytics.impact_analysis("feature-001")
74
+ >>> # Or via SDK (backward compatibility)
75
+ >>> impact = sdk.analyze_impact("feature-001")
76
+ >>> logger.info(f"Completing this unlocks {impact['unlocks_count']} tasks")
77
+ """
78
+ impact = sdk.dep_analytics.impact_analysis(node_id)
79
+
80
+ return {
81
+ "node_id": node_id,
82
+ "direct_dependents": impact.direct_dependents,
83
+ "total_impact": impact.transitive_dependents,
84
+ "completion_impact": impact.completion_impact,
85
+ "unlocks_count": len(impact.affected_nodes),
86
+ "affected_tasks": impact.affected_nodes[:10],
87
+ }