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.
- htmlgraph/.htmlgraph/.session-warning-state.json +6 -0
- htmlgraph/.htmlgraph/agents.json +72 -0
- htmlgraph/.htmlgraph/htmlgraph.db +0 -0
- htmlgraph/__init__.py +51 -1
- htmlgraph/__init__.pyi +123 -0
- htmlgraph/agent_detection.py +26 -10
- htmlgraph/agent_registry.py +2 -1
- htmlgraph/analytics/__init__.py +8 -1
- htmlgraph/analytics/cli.py +86 -20
- htmlgraph/analytics/cost_analyzer.py +391 -0
- htmlgraph/analytics/cost_monitor.py +664 -0
- htmlgraph/analytics/cost_reporter.py +675 -0
- htmlgraph/analytics/cross_session.py +617 -0
- htmlgraph/analytics/dependency.py +10 -6
- htmlgraph/analytics/pattern_learning.py +771 -0
- htmlgraph/analytics/session_graph.py +707 -0
- htmlgraph/analytics/strategic/__init__.py +80 -0
- htmlgraph/analytics/strategic/cost_optimizer.py +611 -0
- htmlgraph/analytics/strategic/pattern_detector.py +876 -0
- htmlgraph/analytics/strategic/preference_manager.py +709 -0
- htmlgraph/analytics/strategic/suggestion_engine.py +747 -0
- htmlgraph/analytics/work_type.py +67 -27
- htmlgraph/analytics_index.py +53 -20
- htmlgraph/api/__init__.py +3 -0
- htmlgraph/api/cost_alerts_websocket.py +416 -0
- htmlgraph/api/main.py +2498 -0
- htmlgraph/api/static/htmx.min.js +1 -0
- htmlgraph/api/static/style-redesign.css +1344 -0
- htmlgraph/api/static/style.css +1079 -0
- htmlgraph/api/templates/dashboard-redesign.html +1366 -0
- htmlgraph/api/templates/dashboard.html +794 -0
- htmlgraph/api/templates/partials/activity-feed-hierarchical.html +326 -0
- htmlgraph/api/templates/partials/activity-feed.html +1100 -0
- htmlgraph/api/templates/partials/agents-redesign.html +317 -0
- htmlgraph/api/templates/partials/agents.html +317 -0
- htmlgraph/api/templates/partials/event-traces.html +373 -0
- htmlgraph/api/templates/partials/features-kanban-redesign.html +509 -0
- htmlgraph/api/templates/partials/features.html +578 -0
- htmlgraph/api/templates/partials/metrics-redesign.html +346 -0
- htmlgraph/api/templates/partials/metrics.html +346 -0
- htmlgraph/api/templates/partials/orchestration-redesign.html +443 -0
- htmlgraph/api/templates/partials/orchestration.html +198 -0
- htmlgraph/api/templates/partials/spawners.html +375 -0
- htmlgraph/api/templates/partials/work-items.html +613 -0
- htmlgraph/api/websocket.py +538 -0
- htmlgraph/archive/__init__.py +24 -0
- htmlgraph/archive/bloom.py +234 -0
- htmlgraph/archive/fts.py +297 -0
- htmlgraph/archive/manager.py +583 -0
- htmlgraph/archive/search.py +244 -0
- htmlgraph/atomic_ops.py +560 -0
- htmlgraph/attribute_index.py +2 -1
- htmlgraph/bounded_paths.py +539 -0
- htmlgraph/builders/base.py +57 -2
- htmlgraph/builders/bug.py +19 -3
- htmlgraph/builders/chore.py +19 -3
- htmlgraph/builders/epic.py +19 -3
- htmlgraph/builders/feature.py +27 -3
- htmlgraph/builders/insight.py +2 -1
- htmlgraph/builders/metric.py +2 -1
- htmlgraph/builders/pattern.py +2 -1
- htmlgraph/builders/phase.py +19 -3
- htmlgraph/builders/spike.py +29 -3
- htmlgraph/builders/track.py +42 -1
- htmlgraph/cigs/__init__.py +81 -0
- htmlgraph/cigs/autonomy.py +385 -0
- htmlgraph/cigs/cost.py +475 -0
- htmlgraph/cigs/messages_basic.py +472 -0
- htmlgraph/cigs/messaging.py +365 -0
- htmlgraph/cigs/models.py +771 -0
- htmlgraph/cigs/pattern_storage.py +427 -0
- htmlgraph/cigs/patterns.py +503 -0
- htmlgraph/cigs/posttool_analyzer.py +234 -0
- htmlgraph/cigs/reporter.py +818 -0
- htmlgraph/cigs/tracker.py +317 -0
- htmlgraph/cli/.htmlgraph/.session-warning-state.json +6 -0
- htmlgraph/cli/.htmlgraph/agents.json +72 -0
- htmlgraph/cli/.htmlgraph/htmlgraph.db +0 -0
- htmlgraph/cli/__init__.py +42 -0
- htmlgraph/cli/__main__.py +6 -0
- htmlgraph/cli/analytics.py +1424 -0
- htmlgraph/cli/base.py +685 -0
- htmlgraph/cli/constants.py +206 -0
- htmlgraph/cli/core.py +954 -0
- htmlgraph/cli/main.py +147 -0
- htmlgraph/cli/models.py +475 -0
- htmlgraph/cli/templates/__init__.py +1 -0
- htmlgraph/cli/templates/cost_dashboard.py +399 -0
- htmlgraph/cli/work/__init__.py +239 -0
- htmlgraph/cli/work/browse.py +115 -0
- htmlgraph/cli/work/features.py +568 -0
- htmlgraph/cli/work/orchestration.py +676 -0
- htmlgraph/cli/work/report.py +728 -0
- htmlgraph/cli/work/sessions.py +466 -0
- htmlgraph/cli/work/snapshot.py +559 -0
- htmlgraph/cli/work/tracks.py +486 -0
- htmlgraph/cli_commands/__init__.py +1 -0
- htmlgraph/cli_commands/feature.py +195 -0
- htmlgraph/cli_framework.py +115 -0
- htmlgraph/collections/__init__.py +2 -0
- htmlgraph/collections/base.py +197 -14
- htmlgraph/collections/bug.py +2 -1
- htmlgraph/collections/chore.py +2 -1
- htmlgraph/collections/epic.py +2 -1
- htmlgraph/collections/feature.py +2 -1
- htmlgraph/collections/insight.py +2 -1
- htmlgraph/collections/metric.py +2 -1
- htmlgraph/collections/pattern.py +2 -1
- htmlgraph/collections/phase.py +2 -1
- htmlgraph/collections/session.py +194 -0
- htmlgraph/collections/spike.py +13 -2
- htmlgraph/collections/task_delegation.py +241 -0
- htmlgraph/collections/todo.py +14 -1
- htmlgraph/collections/traces.py +487 -0
- htmlgraph/config/cost_models.json +56 -0
- htmlgraph/config.py +190 -0
- htmlgraph/context_analytics.py +2 -1
- htmlgraph/converter.py +116 -7
- htmlgraph/cost_analysis/__init__.py +5 -0
- htmlgraph/cost_analysis/analyzer.py +438 -0
- htmlgraph/dashboard.html +2246 -248
- htmlgraph/dashboard.html.backup +6592 -0
- htmlgraph/dashboard.html.bak +7181 -0
- htmlgraph/dashboard.html.bak2 +7231 -0
- htmlgraph/dashboard.html.bak3 +7232 -0
- htmlgraph/db/__init__.py +38 -0
- htmlgraph/db/queries.py +790 -0
- htmlgraph/db/schema.py +1788 -0
- htmlgraph/decorators.py +317 -0
- htmlgraph/dependency_models.py +2 -1
- htmlgraph/deploy.py +26 -27
- htmlgraph/docs/API_REFERENCE.md +841 -0
- htmlgraph/docs/HTTP_API.md +750 -0
- htmlgraph/docs/INTEGRATION_GUIDE.md +752 -0
- htmlgraph/docs/ORCHESTRATION_PATTERNS.md +717 -0
- htmlgraph/docs/README.md +532 -0
- htmlgraph/docs/__init__.py +77 -0
- htmlgraph/docs/docs_version.py +55 -0
- htmlgraph/docs/metadata.py +93 -0
- htmlgraph/docs/migrations.py +232 -0
- htmlgraph/docs/template_engine.py +143 -0
- htmlgraph/docs/templates/_sections/cli_reference.md.j2 +52 -0
- htmlgraph/docs/templates/_sections/core_concepts.md.j2 +29 -0
- htmlgraph/docs/templates/_sections/sdk_basics.md.j2 +69 -0
- htmlgraph/docs/templates/base_agents.md.j2 +78 -0
- htmlgraph/docs/templates/example_user_override.md.j2 +47 -0
- htmlgraph/docs/version_check.py +163 -0
- htmlgraph/edge_index.py +2 -1
- htmlgraph/error_handler.py +544 -0
- htmlgraph/event_log.py +86 -37
- htmlgraph/event_migration.py +2 -1
- htmlgraph/file_watcher.py +12 -8
- htmlgraph/find_api.py +2 -1
- htmlgraph/git_events.py +67 -9
- htmlgraph/hooks/.htmlgraph/.session-warning-state.json +6 -0
- htmlgraph/hooks/.htmlgraph/agents.json +72 -0
- htmlgraph/hooks/.htmlgraph/index.sqlite +0 -0
- htmlgraph/hooks/__init__.py +8 -0
- htmlgraph/hooks/bootstrap.py +169 -0
- htmlgraph/hooks/cigs_pretool_enforcer.py +354 -0
- htmlgraph/hooks/concurrent_sessions.py +208 -0
- htmlgraph/hooks/context.py +350 -0
- htmlgraph/hooks/drift_handler.py +525 -0
- htmlgraph/hooks/event_tracker.py +790 -99
- htmlgraph/hooks/git_commands.py +175 -0
- htmlgraph/hooks/installer.py +5 -1
- htmlgraph/hooks/orchestrator.py +327 -76
- htmlgraph/hooks/orchestrator_reflector.py +31 -4
- htmlgraph/hooks/post_tool_use_failure.py +32 -7
- htmlgraph/hooks/post_tool_use_handler.py +257 -0
- htmlgraph/hooks/posttooluse.py +92 -19
- htmlgraph/hooks/pretooluse.py +527 -7
- htmlgraph/hooks/prompt_analyzer.py +637 -0
- htmlgraph/hooks/session_handler.py +668 -0
- htmlgraph/hooks/session_summary.py +395 -0
- htmlgraph/hooks/state_manager.py +504 -0
- htmlgraph/hooks/subagent_detection.py +202 -0
- htmlgraph/hooks/subagent_stop.py +369 -0
- htmlgraph/hooks/task_enforcer.py +99 -4
- htmlgraph/hooks/validator.py +212 -91
- htmlgraph/ids.py +2 -1
- htmlgraph/learning.py +125 -100
- htmlgraph/mcp_server.py +2 -1
- htmlgraph/models.py +217 -18
- htmlgraph/operations/README.md +62 -0
- htmlgraph/operations/__init__.py +79 -0
- htmlgraph/operations/analytics.py +339 -0
- htmlgraph/operations/bootstrap.py +289 -0
- htmlgraph/operations/events.py +244 -0
- htmlgraph/operations/fastapi_server.py +231 -0
- htmlgraph/operations/hooks.py +350 -0
- htmlgraph/operations/initialization.py +597 -0
- htmlgraph/operations/initialization.py.backup +228 -0
- htmlgraph/operations/server.py +303 -0
- htmlgraph/orchestration/__init__.py +58 -0
- htmlgraph/orchestration/claude_launcher.py +179 -0
- htmlgraph/orchestration/command_builder.py +72 -0
- htmlgraph/orchestration/headless_spawner.py +281 -0
- htmlgraph/orchestration/live_events.py +377 -0
- htmlgraph/orchestration/model_selection.py +327 -0
- htmlgraph/orchestration/plugin_manager.py +140 -0
- htmlgraph/orchestration/prompts.py +137 -0
- htmlgraph/orchestration/spawner_event_tracker.py +383 -0
- htmlgraph/orchestration/spawners/__init__.py +16 -0
- htmlgraph/orchestration/spawners/base.py +194 -0
- htmlgraph/orchestration/spawners/claude.py +173 -0
- htmlgraph/orchestration/spawners/codex.py +435 -0
- htmlgraph/orchestration/spawners/copilot.py +294 -0
- htmlgraph/orchestration/spawners/gemini.py +471 -0
- htmlgraph/orchestration/subprocess_runner.py +36 -0
- htmlgraph/{orchestration.py → orchestration/task_coordination.py} +16 -8
- htmlgraph/orchestration.md +563 -0
- htmlgraph/orchestrator-system-prompt-optimized.txt +863 -0
- htmlgraph/orchestrator.py +2 -1
- htmlgraph/orchestrator_config.py +357 -0
- htmlgraph/orchestrator_mode.py +115 -4
- htmlgraph/parallel.py +2 -1
- htmlgraph/parser.py +86 -6
- htmlgraph/path_query.py +608 -0
- htmlgraph/pattern_matcher.py +636 -0
- htmlgraph/pydantic_models.py +476 -0
- htmlgraph/quality_gates.py +350 -0
- htmlgraph/query_builder.py +2 -1
- htmlgraph/query_composer.py +509 -0
- htmlgraph/reflection.py +443 -0
- htmlgraph/refs.py +344 -0
- htmlgraph/repo_hash.py +512 -0
- htmlgraph/repositories/__init__.py +292 -0
- htmlgraph/repositories/analytics_repository.py +455 -0
- htmlgraph/repositories/analytics_repository_standard.py +628 -0
- htmlgraph/repositories/feature_repository.py +581 -0
- htmlgraph/repositories/feature_repository_htmlfile.py +668 -0
- htmlgraph/repositories/feature_repository_memory.py +607 -0
- htmlgraph/repositories/feature_repository_sqlite.py +858 -0
- htmlgraph/repositories/filter_service.py +620 -0
- htmlgraph/repositories/filter_service_standard.py +445 -0
- htmlgraph/repositories/shared_cache.py +621 -0
- htmlgraph/repositories/shared_cache_memory.py +395 -0
- htmlgraph/repositories/track_repository.py +552 -0
- htmlgraph/repositories/track_repository_htmlfile.py +619 -0
- htmlgraph/repositories/track_repository_memory.py +508 -0
- htmlgraph/repositories/track_repository_sqlite.py +711 -0
- htmlgraph/sdk/__init__.py +398 -0
- htmlgraph/sdk/__init__.pyi +14 -0
- htmlgraph/sdk/analytics/__init__.py +19 -0
- htmlgraph/sdk/analytics/engine.py +155 -0
- htmlgraph/sdk/analytics/helpers.py +178 -0
- htmlgraph/sdk/analytics/registry.py +109 -0
- htmlgraph/sdk/base.py +484 -0
- htmlgraph/sdk/constants.py +216 -0
- htmlgraph/sdk/core.pyi +308 -0
- htmlgraph/sdk/discovery.py +120 -0
- htmlgraph/sdk/help/__init__.py +12 -0
- htmlgraph/sdk/help/mixin.py +699 -0
- htmlgraph/sdk/mixins/__init__.py +15 -0
- htmlgraph/sdk/mixins/attribution.py +113 -0
- htmlgraph/sdk/mixins/mixin.py +410 -0
- htmlgraph/sdk/operations/__init__.py +12 -0
- htmlgraph/sdk/operations/mixin.py +427 -0
- htmlgraph/sdk/orchestration/__init__.py +17 -0
- htmlgraph/sdk/orchestration/coordinator.py +203 -0
- htmlgraph/sdk/orchestration/spawner.py +204 -0
- htmlgraph/sdk/planning/__init__.py +19 -0
- htmlgraph/sdk/planning/bottlenecks.py +93 -0
- htmlgraph/sdk/planning/mixin.py +211 -0
- htmlgraph/sdk/planning/parallel.py +186 -0
- htmlgraph/sdk/planning/queue.py +210 -0
- htmlgraph/sdk/planning/recommendations.py +87 -0
- htmlgraph/sdk/planning/smart_planning.py +319 -0
- htmlgraph/sdk/session/__init__.py +19 -0
- htmlgraph/sdk/session/continuity.py +57 -0
- htmlgraph/sdk/session/handoff.py +110 -0
- htmlgraph/sdk/session/info.py +309 -0
- htmlgraph/sdk/session/manager.py +103 -0
- htmlgraph/sdk/strategic/__init__.py +26 -0
- htmlgraph/sdk/strategic/mixin.py +563 -0
- htmlgraph/server.py +295 -107
- htmlgraph/session_hooks.py +300 -0
- htmlgraph/session_manager.py +285 -3
- htmlgraph/session_registry.py +587 -0
- htmlgraph/session_state.py +436 -0
- htmlgraph/session_warning.py +2 -1
- htmlgraph/sessions/__init__.py +23 -0
- htmlgraph/sessions/handoff.py +756 -0
- htmlgraph/system_prompts.py +450 -0
- htmlgraph/templates/orchestration-view.html +350 -0
- htmlgraph/track_builder.py +33 -1
- htmlgraph/track_manager.py +38 -0
- htmlgraph/transcript.py +18 -5
- htmlgraph/validation.py +115 -0
- htmlgraph/watch.py +2 -1
- htmlgraph/work_type_utils.py +2 -1
- {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/dashboard.html +2246 -248
- {htmlgraph-0.20.1.dist-info → htmlgraph-0.27.5.dist-info}/METADATA +95 -64
- htmlgraph-0.27.5.dist-info/RECORD +337 -0
- {htmlgraph-0.20.1.dist-info → htmlgraph-0.27.5.dist-info}/entry_points.txt +1 -1
- htmlgraph/cli.py +0 -4839
- htmlgraph/sdk.py +0 -2359
- htmlgraph-0.20.1.dist-info/RECORD +0 -118
- {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/styles.css +0 -0
- {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/AGENTS.md.template +0 -0
- {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/CLAUDE.md.template +0 -0
- {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/GEMINI.md.template +0 -0
- {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
|
+
)
|