htmlgraph 0.20.1__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 (304) 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 +51 -1
  5. htmlgraph/__init__.pyi +123 -0
  6. htmlgraph/agent_detection.py +26 -10
  7. htmlgraph/agent_registry.py +2 -1
  8. htmlgraph/analytics/__init__.py +8 -1
  9. htmlgraph/analytics/cli.py +86 -20
  10. htmlgraph/analytics/cost_analyzer.py +391 -0
  11. htmlgraph/analytics/cost_monitor.py +664 -0
  12. htmlgraph/analytics/cost_reporter.py +675 -0
  13. htmlgraph/analytics/cross_session.py +617 -0
  14. htmlgraph/analytics/dependency.py +10 -6
  15. htmlgraph/analytics/pattern_learning.py +771 -0
  16. htmlgraph/analytics/session_graph.py +707 -0
  17. htmlgraph/analytics/strategic/__init__.py +80 -0
  18. htmlgraph/analytics/strategic/cost_optimizer.py +611 -0
  19. htmlgraph/analytics/strategic/pattern_detector.py +876 -0
  20. htmlgraph/analytics/strategic/preference_manager.py +709 -0
  21. htmlgraph/analytics/strategic/suggestion_engine.py +747 -0
  22. htmlgraph/analytics/work_type.py +67 -27
  23. htmlgraph/analytics_index.py +53 -20
  24. htmlgraph/api/__init__.py +3 -0
  25. htmlgraph/api/cost_alerts_websocket.py +416 -0
  26. htmlgraph/api/main.py +2498 -0
  27. htmlgraph/api/static/htmx.min.js +1 -0
  28. htmlgraph/api/static/style-redesign.css +1344 -0
  29. htmlgraph/api/static/style.css +1079 -0
  30. htmlgraph/api/templates/dashboard-redesign.html +1366 -0
  31. htmlgraph/api/templates/dashboard.html +794 -0
  32. htmlgraph/api/templates/partials/activity-feed-hierarchical.html +326 -0
  33. htmlgraph/api/templates/partials/activity-feed.html +1100 -0
  34. htmlgraph/api/templates/partials/agents-redesign.html +317 -0
  35. htmlgraph/api/templates/partials/agents.html +317 -0
  36. htmlgraph/api/templates/partials/event-traces.html +373 -0
  37. htmlgraph/api/templates/partials/features-kanban-redesign.html +509 -0
  38. htmlgraph/api/templates/partials/features.html +578 -0
  39. htmlgraph/api/templates/partials/metrics-redesign.html +346 -0
  40. htmlgraph/api/templates/partials/metrics.html +346 -0
  41. htmlgraph/api/templates/partials/orchestration-redesign.html +443 -0
  42. htmlgraph/api/templates/partials/orchestration.html +198 -0
  43. htmlgraph/api/templates/partials/spawners.html +375 -0
  44. htmlgraph/api/templates/partials/work-items.html +613 -0
  45. htmlgraph/api/websocket.py +538 -0
  46. htmlgraph/archive/__init__.py +24 -0
  47. htmlgraph/archive/bloom.py +234 -0
  48. htmlgraph/archive/fts.py +297 -0
  49. htmlgraph/archive/manager.py +583 -0
  50. htmlgraph/archive/search.py +244 -0
  51. htmlgraph/atomic_ops.py +560 -0
  52. htmlgraph/attribute_index.py +2 -1
  53. htmlgraph/bounded_paths.py +539 -0
  54. htmlgraph/builders/base.py +57 -2
  55. htmlgraph/builders/bug.py +19 -3
  56. htmlgraph/builders/chore.py +19 -3
  57. htmlgraph/builders/epic.py +19 -3
  58. htmlgraph/builders/feature.py +27 -3
  59. htmlgraph/builders/insight.py +2 -1
  60. htmlgraph/builders/metric.py +2 -1
  61. htmlgraph/builders/pattern.py +2 -1
  62. htmlgraph/builders/phase.py +19 -3
  63. htmlgraph/builders/spike.py +29 -3
  64. htmlgraph/builders/track.py +42 -1
  65. htmlgraph/cigs/__init__.py +81 -0
  66. htmlgraph/cigs/autonomy.py +385 -0
  67. htmlgraph/cigs/cost.py +475 -0
  68. htmlgraph/cigs/messages_basic.py +472 -0
  69. htmlgraph/cigs/messaging.py +365 -0
  70. htmlgraph/cigs/models.py +771 -0
  71. htmlgraph/cigs/pattern_storage.py +427 -0
  72. htmlgraph/cigs/patterns.py +503 -0
  73. htmlgraph/cigs/posttool_analyzer.py +234 -0
  74. htmlgraph/cigs/reporter.py +818 -0
  75. htmlgraph/cigs/tracker.py +317 -0
  76. htmlgraph/cli/.htmlgraph/.session-warning-state.json +6 -0
  77. htmlgraph/cli/.htmlgraph/agents.json +72 -0
  78. htmlgraph/cli/.htmlgraph/htmlgraph.db +0 -0
  79. htmlgraph/cli/__init__.py +42 -0
  80. htmlgraph/cli/__main__.py +6 -0
  81. htmlgraph/cli/analytics.py +1424 -0
  82. htmlgraph/cli/base.py +685 -0
  83. htmlgraph/cli/constants.py +206 -0
  84. htmlgraph/cli/core.py +954 -0
  85. htmlgraph/cli/main.py +147 -0
  86. htmlgraph/cli/models.py +475 -0
  87. htmlgraph/cli/templates/__init__.py +1 -0
  88. htmlgraph/cli/templates/cost_dashboard.py +399 -0
  89. htmlgraph/cli/work/__init__.py +239 -0
  90. htmlgraph/cli/work/browse.py +115 -0
  91. htmlgraph/cli/work/features.py +568 -0
  92. htmlgraph/cli/work/orchestration.py +676 -0
  93. htmlgraph/cli/work/report.py +728 -0
  94. htmlgraph/cli/work/sessions.py +466 -0
  95. htmlgraph/cli/work/snapshot.py +559 -0
  96. htmlgraph/cli/work/tracks.py +486 -0
  97. htmlgraph/cli_commands/__init__.py +1 -0
  98. htmlgraph/cli_commands/feature.py +195 -0
  99. htmlgraph/cli_framework.py +115 -0
  100. htmlgraph/collections/__init__.py +2 -0
  101. htmlgraph/collections/base.py +197 -14
  102. htmlgraph/collections/bug.py +2 -1
  103. htmlgraph/collections/chore.py +2 -1
  104. htmlgraph/collections/epic.py +2 -1
  105. htmlgraph/collections/feature.py +2 -1
  106. htmlgraph/collections/insight.py +2 -1
  107. htmlgraph/collections/metric.py +2 -1
  108. htmlgraph/collections/pattern.py +2 -1
  109. htmlgraph/collections/phase.py +2 -1
  110. htmlgraph/collections/session.py +194 -0
  111. htmlgraph/collections/spike.py +13 -2
  112. htmlgraph/collections/task_delegation.py +241 -0
  113. htmlgraph/collections/todo.py +14 -1
  114. htmlgraph/collections/traces.py +487 -0
  115. htmlgraph/config/cost_models.json +56 -0
  116. htmlgraph/config.py +190 -0
  117. htmlgraph/context_analytics.py +2 -1
  118. htmlgraph/converter.py +116 -7
  119. htmlgraph/cost_analysis/__init__.py +5 -0
  120. htmlgraph/cost_analysis/analyzer.py +438 -0
  121. htmlgraph/dashboard.html +2246 -248
  122. htmlgraph/dashboard.html.backup +6592 -0
  123. htmlgraph/dashboard.html.bak +7181 -0
  124. htmlgraph/dashboard.html.bak2 +7231 -0
  125. htmlgraph/dashboard.html.bak3 +7232 -0
  126. htmlgraph/db/__init__.py +38 -0
  127. htmlgraph/db/queries.py +790 -0
  128. htmlgraph/db/schema.py +1788 -0
  129. htmlgraph/decorators.py +317 -0
  130. htmlgraph/dependency_models.py +2 -1
  131. htmlgraph/deploy.py +26 -27
  132. htmlgraph/docs/API_REFERENCE.md +841 -0
  133. htmlgraph/docs/HTTP_API.md +750 -0
  134. htmlgraph/docs/INTEGRATION_GUIDE.md +752 -0
  135. htmlgraph/docs/ORCHESTRATION_PATTERNS.md +717 -0
  136. htmlgraph/docs/README.md +532 -0
  137. htmlgraph/docs/__init__.py +77 -0
  138. htmlgraph/docs/docs_version.py +55 -0
  139. htmlgraph/docs/metadata.py +93 -0
  140. htmlgraph/docs/migrations.py +232 -0
  141. htmlgraph/docs/template_engine.py +143 -0
  142. htmlgraph/docs/templates/_sections/cli_reference.md.j2 +52 -0
  143. htmlgraph/docs/templates/_sections/core_concepts.md.j2 +29 -0
  144. htmlgraph/docs/templates/_sections/sdk_basics.md.j2 +69 -0
  145. htmlgraph/docs/templates/base_agents.md.j2 +78 -0
  146. htmlgraph/docs/templates/example_user_override.md.j2 +47 -0
  147. htmlgraph/docs/version_check.py +163 -0
  148. htmlgraph/edge_index.py +2 -1
  149. htmlgraph/error_handler.py +544 -0
  150. htmlgraph/event_log.py +86 -37
  151. htmlgraph/event_migration.py +2 -1
  152. htmlgraph/file_watcher.py +12 -8
  153. htmlgraph/find_api.py +2 -1
  154. htmlgraph/git_events.py +67 -9
  155. htmlgraph/hooks/.htmlgraph/.session-warning-state.json +6 -0
  156. htmlgraph/hooks/.htmlgraph/agents.json +72 -0
  157. htmlgraph/hooks/.htmlgraph/index.sqlite +0 -0
  158. htmlgraph/hooks/__init__.py +8 -0
  159. htmlgraph/hooks/bootstrap.py +169 -0
  160. htmlgraph/hooks/cigs_pretool_enforcer.py +354 -0
  161. htmlgraph/hooks/concurrent_sessions.py +208 -0
  162. htmlgraph/hooks/context.py +350 -0
  163. htmlgraph/hooks/drift_handler.py +525 -0
  164. htmlgraph/hooks/event_tracker.py +790 -99
  165. htmlgraph/hooks/git_commands.py +175 -0
  166. htmlgraph/hooks/installer.py +5 -1
  167. htmlgraph/hooks/orchestrator.py +327 -76
  168. htmlgraph/hooks/orchestrator_reflector.py +31 -4
  169. htmlgraph/hooks/post_tool_use_failure.py +32 -7
  170. htmlgraph/hooks/post_tool_use_handler.py +257 -0
  171. htmlgraph/hooks/posttooluse.py +92 -19
  172. htmlgraph/hooks/pretooluse.py +527 -7
  173. htmlgraph/hooks/prompt_analyzer.py +637 -0
  174. htmlgraph/hooks/session_handler.py +668 -0
  175. htmlgraph/hooks/session_summary.py +395 -0
  176. htmlgraph/hooks/state_manager.py +504 -0
  177. htmlgraph/hooks/subagent_detection.py +202 -0
  178. htmlgraph/hooks/subagent_stop.py +369 -0
  179. htmlgraph/hooks/task_enforcer.py +99 -4
  180. htmlgraph/hooks/validator.py +212 -91
  181. htmlgraph/ids.py +2 -1
  182. htmlgraph/learning.py +125 -100
  183. htmlgraph/mcp_server.py +2 -1
  184. htmlgraph/models.py +217 -18
  185. htmlgraph/operations/README.md +62 -0
  186. htmlgraph/operations/__init__.py +79 -0
  187. htmlgraph/operations/analytics.py +339 -0
  188. htmlgraph/operations/bootstrap.py +289 -0
  189. htmlgraph/operations/events.py +244 -0
  190. htmlgraph/operations/fastapi_server.py +231 -0
  191. htmlgraph/operations/hooks.py +350 -0
  192. htmlgraph/operations/initialization.py +597 -0
  193. htmlgraph/operations/initialization.py.backup +228 -0
  194. htmlgraph/operations/server.py +303 -0
  195. htmlgraph/orchestration/__init__.py +58 -0
  196. htmlgraph/orchestration/claude_launcher.py +179 -0
  197. htmlgraph/orchestration/command_builder.py +72 -0
  198. htmlgraph/orchestration/headless_spawner.py +281 -0
  199. htmlgraph/orchestration/live_events.py +377 -0
  200. htmlgraph/orchestration/model_selection.py +327 -0
  201. htmlgraph/orchestration/plugin_manager.py +140 -0
  202. htmlgraph/orchestration/prompts.py +137 -0
  203. htmlgraph/orchestration/spawner_event_tracker.py +383 -0
  204. htmlgraph/orchestration/spawners/__init__.py +16 -0
  205. htmlgraph/orchestration/spawners/base.py +194 -0
  206. htmlgraph/orchestration/spawners/claude.py +173 -0
  207. htmlgraph/orchestration/spawners/codex.py +435 -0
  208. htmlgraph/orchestration/spawners/copilot.py +294 -0
  209. htmlgraph/orchestration/spawners/gemini.py +471 -0
  210. htmlgraph/orchestration/subprocess_runner.py +36 -0
  211. htmlgraph/{orchestration.py → orchestration/task_coordination.py} +16 -8
  212. htmlgraph/orchestration.md +563 -0
  213. htmlgraph/orchestrator-system-prompt-optimized.txt +863 -0
  214. htmlgraph/orchestrator.py +2 -1
  215. htmlgraph/orchestrator_config.py +357 -0
  216. htmlgraph/orchestrator_mode.py +115 -4
  217. htmlgraph/parallel.py +2 -1
  218. htmlgraph/parser.py +86 -6
  219. htmlgraph/path_query.py +608 -0
  220. htmlgraph/pattern_matcher.py +636 -0
  221. htmlgraph/pydantic_models.py +476 -0
  222. htmlgraph/quality_gates.py +350 -0
  223. htmlgraph/query_builder.py +2 -1
  224. htmlgraph/query_composer.py +509 -0
  225. htmlgraph/reflection.py +443 -0
  226. htmlgraph/refs.py +344 -0
  227. htmlgraph/repo_hash.py +512 -0
  228. htmlgraph/repositories/__init__.py +292 -0
  229. htmlgraph/repositories/analytics_repository.py +455 -0
  230. htmlgraph/repositories/analytics_repository_standard.py +628 -0
  231. htmlgraph/repositories/feature_repository.py +581 -0
  232. htmlgraph/repositories/feature_repository_htmlfile.py +668 -0
  233. htmlgraph/repositories/feature_repository_memory.py +607 -0
  234. htmlgraph/repositories/feature_repository_sqlite.py +858 -0
  235. htmlgraph/repositories/filter_service.py +620 -0
  236. htmlgraph/repositories/filter_service_standard.py +445 -0
  237. htmlgraph/repositories/shared_cache.py +621 -0
  238. htmlgraph/repositories/shared_cache_memory.py +395 -0
  239. htmlgraph/repositories/track_repository.py +552 -0
  240. htmlgraph/repositories/track_repository_htmlfile.py +619 -0
  241. htmlgraph/repositories/track_repository_memory.py +508 -0
  242. htmlgraph/repositories/track_repository_sqlite.py +711 -0
  243. htmlgraph/sdk/__init__.py +398 -0
  244. htmlgraph/sdk/__init__.pyi +14 -0
  245. htmlgraph/sdk/analytics/__init__.py +19 -0
  246. htmlgraph/sdk/analytics/engine.py +155 -0
  247. htmlgraph/sdk/analytics/helpers.py +178 -0
  248. htmlgraph/sdk/analytics/registry.py +109 -0
  249. htmlgraph/sdk/base.py +484 -0
  250. htmlgraph/sdk/constants.py +216 -0
  251. htmlgraph/sdk/core.pyi +308 -0
  252. htmlgraph/sdk/discovery.py +120 -0
  253. htmlgraph/sdk/help/__init__.py +12 -0
  254. htmlgraph/sdk/help/mixin.py +699 -0
  255. htmlgraph/sdk/mixins/__init__.py +15 -0
  256. htmlgraph/sdk/mixins/attribution.py +113 -0
  257. htmlgraph/sdk/mixins/mixin.py +410 -0
  258. htmlgraph/sdk/operations/__init__.py +12 -0
  259. htmlgraph/sdk/operations/mixin.py +427 -0
  260. htmlgraph/sdk/orchestration/__init__.py +17 -0
  261. htmlgraph/sdk/orchestration/coordinator.py +203 -0
  262. htmlgraph/sdk/orchestration/spawner.py +204 -0
  263. htmlgraph/sdk/planning/__init__.py +19 -0
  264. htmlgraph/sdk/planning/bottlenecks.py +93 -0
  265. htmlgraph/sdk/planning/mixin.py +211 -0
  266. htmlgraph/sdk/planning/parallel.py +186 -0
  267. htmlgraph/sdk/planning/queue.py +210 -0
  268. htmlgraph/sdk/planning/recommendations.py +87 -0
  269. htmlgraph/sdk/planning/smart_planning.py +319 -0
  270. htmlgraph/sdk/session/__init__.py +19 -0
  271. htmlgraph/sdk/session/continuity.py +57 -0
  272. htmlgraph/sdk/session/handoff.py +110 -0
  273. htmlgraph/sdk/session/info.py +309 -0
  274. htmlgraph/sdk/session/manager.py +103 -0
  275. htmlgraph/sdk/strategic/__init__.py +26 -0
  276. htmlgraph/sdk/strategic/mixin.py +563 -0
  277. htmlgraph/server.py +295 -107
  278. htmlgraph/session_hooks.py +300 -0
  279. htmlgraph/session_manager.py +285 -3
  280. htmlgraph/session_registry.py +587 -0
  281. htmlgraph/session_state.py +436 -0
  282. htmlgraph/session_warning.py +2 -1
  283. htmlgraph/sessions/__init__.py +23 -0
  284. htmlgraph/sessions/handoff.py +756 -0
  285. htmlgraph/system_prompts.py +450 -0
  286. htmlgraph/templates/orchestration-view.html +350 -0
  287. htmlgraph/track_builder.py +33 -1
  288. htmlgraph/track_manager.py +38 -0
  289. htmlgraph/transcript.py +18 -5
  290. htmlgraph/validation.py +115 -0
  291. htmlgraph/watch.py +2 -1
  292. htmlgraph/work_type_utils.py +2 -1
  293. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/dashboard.html +2246 -248
  294. {htmlgraph-0.20.1.dist-info → htmlgraph-0.27.5.dist-info}/METADATA +95 -64
  295. htmlgraph-0.27.5.dist-info/RECORD +337 -0
  296. {htmlgraph-0.20.1.dist-info → htmlgraph-0.27.5.dist-info}/entry_points.txt +1 -1
  297. htmlgraph/cli.py +0 -4839
  298. htmlgraph/sdk.py +0 -2359
  299. htmlgraph-0.20.1.dist-info/RECORD +0 -118
  300. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/styles.css +0 -0
  301. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/AGENTS.md.template +0 -0
  302. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/CLAUDE.md.template +0 -0
  303. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/GEMINI.md.template +0 -0
  304. {htmlgraph-0.20.1.dist-info → htmlgraph-0.27.5.dist-info}/WHEEL +0 -0
@@ -0,0 +1,466 @@
1
+ from __future__ import annotations
2
+
3
+ """HtmlGraph CLI - Session management commands."""
4
+
5
+
6
+ import argparse
7
+ from typing import TYPE_CHECKING
8
+
9
+ from rich import box
10
+ from rich.console import Console
11
+ from rich.panel import Panel
12
+ from rich.table import Table
13
+
14
+ from htmlgraph.cli.base import BaseCommand, CommandError, CommandResult
15
+ from htmlgraph.cli.constants import DEFAULT_GRAPH_DIR
16
+
17
+ if TYPE_CHECKING:
18
+ from argparse import _SubParsersAction
19
+
20
+ console = Console()
21
+
22
+
23
+ def register_session_commands(subparsers: _SubParsersAction) -> None:
24
+ """Register session management commands."""
25
+ session_parser = subparsers.add_parser("session", help="Session management")
26
+ session_subparsers = session_parser.add_subparsers(
27
+ dest="session_command", help="Session command"
28
+ )
29
+
30
+ # session start
31
+ session_start = session_subparsers.add_parser("start", help="Start a new session")
32
+ session_start.add_argument(
33
+ "--id", help="Session ID (auto-generated if not provided)"
34
+ )
35
+ session_start.add_argument("--agent", default="claude-code", help="Agent name")
36
+ session_start.add_argument("--title", help="Session title")
37
+ session_start.add_argument(
38
+ "--graph-dir", "-g", default=DEFAULT_GRAPH_DIR, help="Graph directory"
39
+ )
40
+ session_start.add_argument(
41
+ "--format", choices=["json", "text"], default="text", help="Output format"
42
+ )
43
+ session_start.set_defaults(func=SessionStartCommand.from_args)
44
+
45
+ # session end
46
+ session_end = session_subparsers.add_parser("end", help="End a session")
47
+ session_end.add_argument("id", help="Session ID to end")
48
+ session_end.add_argument("--notes", help="Handoff notes for the next session")
49
+ session_end.add_argument("--recommend", help="Recommended next steps")
50
+ session_end.add_argument(
51
+ "--blocker", action="append", default=[], help="Blocker to record"
52
+ )
53
+ session_end.add_argument(
54
+ "--graph-dir", "-g", default=DEFAULT_GRAPH_DIR, help="Graph directory"
55
+ )
56
+ session_end.add_argument(
57
+ "--format", choices=["json", "text"], default="text", help="Output format"
58
+ )
59
+ session_end.set_defaults(func=SessionEndCommand.from_args)
60
+
61
+ # session list
62
+ session_list = session_subparsers.add_parser("list", help="List all sessions")
63
+ session_list.add_argument(
64
+ "--graph-dir", "-g", default=DEFAULT_GRAPH_DIR, help="Graph directory"
65
+ )
66
+ session_list.add_argument(
67
+ "--format", choices=["json", "text"], default="text", help="Output format"
68
+ )
69
+ session_list.set_defaults(func=SessionListCommand.from_args)
70
+
71
+ # session handoff
72
+ session_handoff = session_subparsers.add_parser(
73
+ "handoff", help="Get or set handoff context"
74
+ )
75
+ session_handoff.add_argument(
76
+ "--session-id", help="Session ID (defaults to last ended)"
77
+ )
78
+ session_handoff.add_argument("--notes", help="Handoff notes")
79
+ session_handoff.add_argument("--recommend", help="Recommended next steps")
80
+ session_handoff.add_argument(
81
+ "--blocker", action="append", default=[], help="Blocker to record"
82
+ )
83
+ session_handoff.add_argument(
84
+ "--show", action="store_true", help="Show handoff context"
85
+ )
86
+ session_handoff.add_argument("--agent", default="claude-code", help="Agent name")
87
+ session_handoff.add_argument(
88
+ "--graph-dir", "-g", default=DEFAULT_GRAPH_DIR, help="Graph directory"
89
+ )
90
+ session_handoff.add_argument(
91
+ "--format", choices=["json", "text"], default="text", help="Output format"
92
+ )
93
+ session_handoff.set_defaults(func=SessionHandoffCommand.from_args)
94
+
95
+ # session start-info
96
+ session_start_info = session_subparsers.add_parser(
97
+ "start-info", help="Get session start information"
98
+ )
99
+ session_start_info.add_argument("--agent", default="claude-code", help="Agent name")
100
+ session_start_info.add_argument(
101
+ "--no-git", action="store_true", help="Exclude git log"
102
+ )
103
+ session_start_info.add_argument(
104
+ "--git-count", type=int, default=5, help="Number of git commits"
105
+ )
106
+ session_start_info.add_argument(
107
+ "--top-n", type=int, default=3, help="Top N analytics items"
108
+ )
109
+ session_start_info.add_argument(
110
+ "--max-agents", type=int, default=3, help="Max agents in analytics"
111
+ )
112
+ session_start_info.add_argument(
113
+ "--graph-dir", "-g", default=DEFAULT_GRAPH_DIR, help="Graph directory"
114
+ )
115
+ session_start_info.add_argument(
116
+ "--format", choices=["json", "text"], default="text", help="Output format"
117
+ )
118
+ session_start_info.set_defaults(func=SessionStartInfoCommand.from_args)
119
+
120
+
121
+ # ============================================================================
122
+ # Session Commands
123
+ # ============================================================================
124
+
125
+
126
+ class SessionStartCommand(BaseCommand):
127
+ """Start a new session."""
128
+
129
+ def __init__(
130
+ self, *, session_id: str | None, agent: str, title: str | None
131
+ ) -> None:
132
+ super().__init__()
133
+ self.session_id = session_id
134
+ self.agent_name = agent
135
+ self.title = title
136
+
137
+ @classmethod
138
+ def from_args(cls, args: argparse.Namespace) -> SessionStartCommand:
139
+ return cls(
140
+ session_id=getattr(args, "id", None),
141
+ agent=args.agent,
142
+ title=getattr(args, "title", None),
143
+ )
144
+
145
+ def execute(self) -> CommandResult:
146
+ """Start a new session."""
147
+ from htmlgraph.cli.base import TextOutputBuilder
148
+ from htmlgraph.converter import session_to_dict
149
+
150
+ sdk = self.get_sdk()
151
+
152
+ with console.status("[blue]Starting session...", spinner="dots"):
153
+ session = sdk.start_session(
154
+ session_id=self.session_id,
155
+ title=self.title,
156
+ agent=self.agent_name,
157
+ )
158
+
159
+ output = TextOutputBuilder()
160
+ output.add_success(f"Session started: {session.id}")
161
+ output.add_field("Agent", session.agent)
162
+ output.add_field("Started", session.started_at.isoformat())
163
+ if session.title:
164
+ output.add_field("Title", session.title)
165
+
166
+ return CommandResult(
167
+ data=session_to_dict(session),
168
+ text=output.build(),
169
+ json_data=session_to_dict(session),
170
+ )
171
+
172
+
173
+ class SessionEndCommand(BaseCommand):
174
+ """End a session."""
175
+
176
+ def __init__(
177
+ self,
178
+ *,
179
+ session_id: str,
180
+ notes: str | None,
181
+ recommend: str | None,
182
+ blockers: list[str],
183
+ ) -> None:
184
+ super().__init__()
185
+ self.session_id = session_id
186
+ self.notes = notes
187
+ self.recommend = recommend
188
+ self.blockers = blockers
189
+
190
+ @classmethod
191
+ def from_args(cls, args: argparse.Namespace) -> SessionEndCommand:
192
+ return cls(
193
+ session_id=args.id,
194
+ notes=args.notes,
195
+ recommend=args.recommend,
196
+ blockers=args.blocker,
197
+ )
198
+
199
+ def execute(self) -> CommandResult:
200
+ """End a session."""
201
+ from htmlgraph.cli.base import TextOutputBuilder
202
+ from htmlgraph.converter import session_to_dict
203
+
204
+ sdk = self.get_sdk()
205
+ session = sdk.end_session(
206
+ self.session_id,
207
+ handoff_notes=self.notes,
208
+ recommended_next=self.recommend,
209
+ blockers=self.blockers,
210
+ )
211
+
212
+ self.require_node(session, "session", self.session_id)
213
+
214
+ duration = session.ended_at - session.started_at if session.ended_at else None
215
+ output = TextOutputBuilder()
216
+ output.add_success(f"Session ended: {session.id}")
217
+ output.add_field("Duration", duration)
218
+ output.add_field("Events", session.event_count)
219
+ if session.worked_on:
220
+ output.add_field("Worked on", ", ".join(session.worked_on))
221
+
222
+ return CommandResult(
223
+ data=session_to_dict(session),
224
+ text=output.build(),
225
+ json_data=session_to_dict(session),
226
+ )
227
+
228
+
229
+ class SessionListCommand(BaseCommand):
230
+ """List all sessions."""
231
+
232
+ def __init__(self, *, status: str | None = None, agent: str | None = None) -> None:
233
+ super().__init__()
234
+ self.status = status
235
+ self.agent_filter = agent
236
+
237
+ @classmethod
238
+ def from_args(cls, args: argparse.Namespace) -> SessionListCommand:
239
+ # Validate inputs using SessionFilter model
240
+ from htmlgraph.cli.models import SessionFilter
241
+
242
+ # Get optional filter arguments
243
+ status = getattr(args, "status", None)
244
+ agent = getattr(args, "agent", None)
245
+
246
+ try:
247
+ filter_model = SessionFilter(status=status, agent=agent)
248
+ except ValueError as e:
249
+ raise CommandError(str(e))
250
+
251
+ return cls(status=filter_model.status, agent=filter_model.agent)
252
+
253
+ def execute(self) -> CommandResult:
254
+ """List all sessions."""
255
+ from pathlib import Path
256
+
257
+ from htmlgraph.converter import SessionConverter, session_to_dict
258
+
259
+ if self.graph_dir is None:
260
+ raise CommandError("Missing graph directory")
261
+
262
+ sessions_dir = Path(self.graph_dir) / "sessions"
263
+ if not sessions_dir.exists():
264
+ from htmlgraph.cli.base import TextOutputBuilder
265
+
266
+ output = TextOutputBuilder()
267
+ output.add_warning("No sessions found.")
268
+ return CommandResult(
269
+ text=output.build(),
270
+ json_data={"sessions": []},
271
+ )
272
+
273
+ converter = SessionConverter(sessions_dir)
274
+
275
+ with console.status("[blue]Loading sessions...", spinner="dots"):
276
+ sessions = converter.load_all()
277
+
278
+ # Convert to display models for type-safe filtering and sorting
279
+ from htmlgraph.cli.models import SessionDisplay
280
+
281
+ display_sessions = [SessionDisplay.from_node(s) for s in sessions]
282
+
283
+ # Apply filters if provided
284
+ if self.status:
285
+ display_sessions = [
286
+ s for s in display_sessions if s.status == self.status
287
+ ]
288
+ if self.agent_filter:
289
+ display_sessions = [
290
+ s for s in display_sessions if s.agent == self.agent_filter
291
+ ]
292
+
293
+ # Sort by started_at descending using display model's sort_key
294
+ display_sessions.sort(key=lambda s: s.sort_key(), reverse=True)
295
+
296
+ if not display_sessions:
297
+ from htmlgraph.cli.base import TextOutputBuilder
298
+
299
+ output = TextOutputBuilder()
300
+ output.add_warning("No sessions found.")
301
+ return CommandResult(
302
+ text=output.build(),
303
+ json_data={"sessions": []},
304
+ )
305
+
306
+ # Create Rich table
307
+ table = Table(
308
+ title="Sessions",
309
+ show_header=True,
310
+ header_style="bold magenta",
311
+ box=box.ROUNDED,
312
+ )
313
+ table.add_column("ID", style="cyan", no_wrap=False, max_width=30)
314
+ table.add_column("Status", style="green", width=10)
315
+ table.add_column("Agent", style="blue", width=15)
316
+ table.add_column("Events", justify="right", style="yellow", width=8)
317
+ table.add_column("Started", style="white")
318
+
319
+ for session in display_sessions:
320
+ table.add_row(
321
+ session.id,
322
+ session.status,
323
+ session.agent,
324
+ str(session.event_count),
325
+ session.started_str,
326
+ )
327
+
328
+ # Return table object directly - TextFormatter will print it properly
329
+ return CommandResult(
330
+ data=table,
331
+ json_data=[session_to_dict(s) for s in sessions],
332
+ )
333
+
334
+
335
+ class SessionHandoffCommand(BaseCommand):
336
+ """Get or set session handoff context."""
337
+
338
+ def __init__(
339
+ self,
340
+ *,
341
+ session_id: str | None,
342
+ notes: str | None,
343
+ recommend: str | None,
344
+ blockers: list[str],
345
+ show: bool,
346
+ agent: str,
347
+ ) -> None:
348
+ super().__init__()
349
+ self.session_id = session_id
350
+ self.notes = notes
351
+ self.recommend = recommend
352
+ self.blockers = blockers
353
+ self.show = show
354
+ self.agent_name = agent
355
+
356
+ @classmethod
357
+ def from_args(cls, args: argparse.Namespace) -> SessionHandoffCommand:
358
+ return cls(
359
+ session_id=args.session_id,
360
+ notes=args.notes,
361
+ recommend=args.recommend,
362
+ blockers=args.blocker,
363
+ show=args.show,
364
+ agent=args.agent,
365
+ )
366
+
367
+ def execute(self) -> CommandResult:
368
+ """Get or set session handoff context."""
369
+ from htmlgraph.converter import session_to_dict
370
+
371
+ sdk = self.get_sdk()
372
+
373
+ if self.show:
374
+ # Show handoff context
375
+ if self.session_id:
376
+ session = sdk.session_manager.get_session(self.session_id)
377
+ else:
378
+ session = sdk.session_manager.get_last_ended_session(
379
+ agent=self.agent_name
380
+ )
381
+
382
+ if not session:
383
+ return CommandResult(
384
+ text="No handoff context found.",
385
+ json_data={},
386
+ )
387
+
388
+ from htmlgraph.cli.base import TextOutputBuilder
389
+
390
+ output = TextOutputBuilder()
391
+ output.add_line(f"Session: {session.id}")
392
+ if session.handoff_notes:
393
+ output.add_field("Notes", session.handoff_notes)
394
+ if session.recommended_next:
395
+ output.add_field("Recommended next", session.recommended_next)
396
+ if session.blockers:
397
+ output.add_field("Blockers", ", ".join(session.blockers))
398
+
399
+ return CommandResult(
400
+ data=session_to_dict(session),
401
+ text=output.build(),
402
+ json_data=session_to_dict(session),
403
+ )
404
+
405
+ # Set handoff context (not implemented in old CLI, just return error)
406
+ raise CommandError("Setting handoff context is not yet implemented")
407
+
408
+
409
+ class SessionStartInfoCommand(BaseCommand):
410
+ """Get comprehensive session start information."""
411
+
412
+ def __init__(
413
+ self,
414
+ *,
415
+ agent: str,
416
+ no_git: bool,
417
+ git_count: int,
418
+ top_n: int,
419
+ max_agents: int,
420
+ ) -> None:
421
+ super().__init__()
422
+ self.agent_name = agent
423
+ self.no_git = no_git
424
+ self.git_count = git_count
425
+ self.top_n = top_n
426
+ self.max_agents = max_agents
427
+
428
+ @classmethod
429
+ def from_args(cls, args: argparse.Namespace) -> SessionStartInfoCommand:
430
+ return cls(
431
+ agent=args.agent,
432
+ no_git=args.no_git,
433
+ git_count=args.git_count,
434
+ top_n=args.top_n,
435
+ max_agents=args.max_agents,
436
+ )
437
+
438
+ def execute(self) -> CommandResult:
439
+ """Get comprehensive session start information."""
440
+ sdk = self.get_sdk()
441
+
442
+ info = sdk.get_session_start_info(
443
+ include_git_log=not self.no_git,
444
+ git_log_count=self.git_count,
445
+ analytics_top_n=self.top_n,
446
+ analytics_max_agents=self.max_agents,
447
+ )
448
+
449
+ # Human-readable format
450
+ status: dict = info["status"] # type: ignore
451
+ by_status = status.get("by_status", {})
452
+
453
+ project_info = (
454
+ f"Project: {status.get('project_name', 'HtmlGraph')}\n"
455
+ f"Total features: {status.get('total_features', 0)}\n"
456
+ f"In progress: {status.get('wip_count', 0)}\n"
457
+ f"Completed: {by_status.get('done', 0)}"
458
+ )
459
+
460
+ panel = Panel(project_info, title="SESSION START INFO", border_style="cyan")
461
+
462
+ # Return panel object directly - TextFormatter will print it properly
463
+ return CommandResult(
464
+ data=panel,
465
+ json_data=info,
466
+ )