htmlgraph 0.26.23__py3-none-any.whl → 0.26.25__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/__init__.py +1 -1
- htmlgraph/analytics/pattern_learning.py +771 -0
- htmlgraph/api/main.py +56 -23
- htmlgraph/api/templates/dashboard-redesign.html +3 -3
- htmlgraph/api/templates/dashboard.html +3 -3
- htmlgraph/api/templates/partials/work-items.html +613 -0
- htmlgraph/builders/track.py +26 -0
- htmlgraph/cli/base.py +31 -7
- htmlgraph/cli/work/__init__.py +74 -0
- htmlgraph/cli/work/browse.py +114 -0
- htmlgraph/cli/work/snapshot.py +558 -0
- htmlgraph/collections/base.py +34 -0
- htmlgraph/collections/todo.py +12 -0
- htmlgraph/converter.py +11 -0
- htmlgraph/db/schema.py +34 -1
- htmlgraph/hooks/orchestrator.py +88 -14
- htmlgraph/hooks/session_handler.py +3 -1
- htmlgraph/models.py +22 -2
- htmlgraph/orchestration/__init__.py +4 -0
- htmlgraph/orchestration/plugin_manager.py +1 -2
- htmlgraph/orchestration/spawner_event_tracker.py +383 -0
- htmlgraph/refs.py +343 -0
- htmlgraph/sdk.py +162 -1
- htmlgraph/session_manager.py +154 -2
- htmlgraph/sessions/__init__.py +23 -0
- htmlgraph/sessions/handoff.py +755 -0
- htmlgraph/track_builder.py +12 -0
- {htmlgraph-0.26.23.dist-info → htmlgraph-0.26.25.dist-info}/METADATA +1 -1
- {htmlgraph-0.26.23.dist-info → htmlgraph-0.26.25.dist-info}/RECORD +36 -28
- {htmlgraph-0.26.23.data → htmlgraph-0.26.25.data}/data/htmlgraph/dashboard.html +0 -0
- {htmlgraph-0.26.23.data → htmlgraph-0.26.25.data}/data/htmlgraph/styles.css +0 -0
- {htmlgraph-0.26.23.data → htmlgraph-0.26.25.data}/data/htmlgraph/templates/AGENTS.md.template +0 -0
- {htmlgraph-0.26.23.data → htmlgraph-0.26.25.data}/data/htmlgraph/templates/CLAUDE.md.template +0 -0
- {htmlgraph-0.26.23.data → htmlgraph-0.26.25.data}/data/htmlgraph/templates/GEMINI.md.template +0 -0
- {htmlgraph-0.26.23.dist-info → htmlgraph-0.26.25.dist-info}/WHEEL +0 -0
- {htmlgraph-0.26.23.dist-info → htmlgraph-0.26.25.dist-info}/entry_points.txt +0 -0
htmlgraph/session_manager.py
CHANGED
|
@@ -186,7 +186,7 @@ class SessionManager:
|
|
|
186
186
|
"""Mark a session as stale (kept for history but not considered active)."""
|
|
187
187
|
if session.status != "active":
|
|
188
188
|
return
|
|
189
|
-
now = datetime.now()
|
|
189
|
+
now = datetime.now(timezone.utc)
|
|
190
190
|
session.status = "stale"
|
|
191
191
|
session.ended_at = now
|
|
192
192
|
session.last_activity = now
|
|
@@ -742,7 +742,7 @@ class SessionManager:
|
|
|
742
742
|
ActivityEntry(
|
|
743
743
|
tool="SessionEnd",
|
|
744
744
|
summary="Session ended",
|
|
745
|
-
timestamp=datetime.now(),
|
|
745
|
+
timestamp=datetime.now(timezone.utc),
|
|
746
746
|
)
|
|
747
747
|
)
|
|
748
748
|
|
|
@@ -792,6 +792,158 @@ class SessionManager:
|
|
|
792
792
|
|
|
793
793
|
return session
|
|
794
794
|
|
|
795
|
+
def continue_from_last(
|
|
796
|
+
self,
|
|
797
|
+
agent: str | None = None,
|
|
798
|
+
auto_create_session: bool = True,
|
|
799
|
+
) -> tuple[Session | None, Any]: # Returns (new_session, resume_info)
|
|
800
|
+
"""
|
|
801
|
+
Continue work from the last completed session.
|
|
802
|
+
|
|
803
|
+
Loads context from the previous session including:
|
|
804
|
+
- Handoff notes and next focus
|
|
805
|
+
- Blockers
|
|
806
|
+
- Recommended context files
|
|
807
|
+
- Recent commits
|
|
808
|
+
- Features worked on
|
|
809
|
+
|
|
810
|
+
Args:
|
|
811
|
+
agent: Filter by agent (None = current agent)
|
|
812
|
+
auto_create_session: Create new session if True
|
|
813
|
+
|
|
814
|
+
Returns:
|
|
815
|
+
Tuple of (new_session, resume_info) or (None, None) if no previous session
|
|
816
|
+
|
|
817
|
+
Example:
|
|
818
|
+
>>> manager = SessionManager(".htmlgraph")
|
|
819
|
+
>>> new_session, resume = manager.continue_from_last(agent="claude")
|
|
820
|
+
>>> if resume:
|
|
821
|
+
... print(resume.summary)
|
|
822
|
+
... print(resume.recommended_files)
|
|
823
|
+
"""
|
|
824
|
+
# Import handoff module
|
|
825
|
+
from typing import Any
|
|
826
|
+
|
|
827
|
+
from htmlgraph.sessions.handoff import SessionResume
|
|
828
|
+
|
|
829
|
+
# Create a minimal SDK-like object with just the directory
|
|
830
|
+
# to avoid circular dependency and database initialization issues
|
|
831
|
+
class MinimalSDK:
|
|
832
|
+
def __init__(self, directory: Path) -> None:
|
|
833
|
+
self._directory = directory
|
|
834
|
+
|
|
835
|
+
sdk: Any = MinimalSDK(self.graph_dir)
|
|
836
|
+
resume = SessionResume(sdk)
|
|
837
|
+
|
|
838
|
+
# Get last session
|
|
839
|
+
last_session = resume.get_last_session(agent=agent)
|
|
840
|
+
if not last_session:
|
|
841
|
+
return None, None
|
|
842
|
+
|
|
843
|
+
# Build resume info
|
|
844
|
+
resume_info = resume.build_resume_info(last_session)
|
|
845
|
+
|
|
846
|
+
# Create new session if requested
|
|
847
|
+
new_session = None
|
|
848
|
+
if auto_create_session:
|
|
849
|
+
from htmlgraph.ids import generate_id
|
|
850
|
+
|
|
851
|
+
session_id = generate_id("sess")
|
|
852
|
+
new_session = self.start_session(
|
|
853
|
+
session_id=session_id,
|
|
854
|
+
agent=agent or last_session.agent,
|
|
855
|
+
title=f"Continuing from {last_session.id}",
|
|
856
|
+
)
|
|
857
|
+
|
|
858
|
+
# Link to previous session
|
|
859
|
+
new_session.continued_from = last_session.id
|
|
860
|
+
self.session_converter.save(new_session)
|
|
861
|
+
|
|
862
|
+
return new_session, resume_info
|
|
863
|
+
|
|
864
|
+
def end_session_with_handoff(
|
|
865
|
+
self,
|
|
866
|
+
session_id: str,
|
|
867
|
+
summary: str | None = None,
|
|
868
|
+
next_focus: str | None = None,
|
|
869
|
+
blockers: list[str] | None = None,
|
|
870
|
+
keep_context: list[str] | None = None,
|
|
871
|
+
auto_recommend_context: bool = True,
|
|
872
|
+
) -> Session | None:
|
|
873
|
+
"""
|
|
874
|
+
End session with handoff information for next session.
|
|
875
|
+
|
|
876
|
+
Args:
|
|
877
|
+
session_id: Session to end
|
|
878
|
+
summary: What was accomplished (handoff notes)
|
|
879
|
+
next_focus: What should be done next
|
|
880
|
+
blockers: List of blockers preventing progress
|
|
881
|
+
keep_context: List of files to keep context for
|
|
882
|
+
auto_recommend_context: Auto-recommend files from git history
|
|
883
|
+
|
|
884
|
+
Returns:
|
|
885
|
+
Updated session or None
|
|
886
|
+
|
|
887
|
+
Example:
|
|
888
|
+
>>> manager.end_session_with_handoff(
|
|
889
|
+
... session_id="sess-123",
|
|
890
|
+
... summary="Completed OAuth integration",
|
|
891
|
+
... next_focus="Implement JWT token refresh",
|
|
892
|
+
... blockers=["Waiting for security review"],
|
|
893
|
+
... keep_context=["src/auth/oauth.py"]
|
|
894
|
+
... )
|
|
895
|
+
"""
|
|
896
|
+
from htmlgraph.sessions.handoff import (
|
|
897
|
+
ContextRecommender,
|
|
898
|
+
HandoffBuilder,
|
|
899
|
+
)
|
|
900
|
+
|
|
901
|
+
# Get session
|
|
902
|
+
session = self.get_session(session_id)
|
|
903
|
+
if not session:
|
|
904
|
+
return None
|
|
905
|
+
|
|
906
|
+
# Build handoff using HandoffBuilder
|
|
907
|
+
builder = HandoffBuilder(session)
|
|
908
|
+
|
|
909
|
+
if summary:
|
|
910
|
+
builder.add_summary(summary)
|
|
911
|
+
|
|
912
|
+
if next_focus:
|
|
913
|
+
builder.add_next_focus(next_focus)
|
|
914
|
+
|
|
915
|
+
if blockers:
|
|
916
|
+
builder.add_blockers(blockers)
|
|
917
|
+
|
|
918
|
+
if keep_context:
|
|
919
|
+
builder.add_context_files(keep_context)
|
|
920
|
+
|
|
921
|
+
# Auto-recommend context files
|
|
922
|
+
if auto_recommend_context:
|
|
923
|
+
recommender = ContextRecommender()
|
|
924
|
+
builder.auto_recommend_context(recommender, max_files=10)
|
|
925
|
+
|
|
926
|
+
handoff_data = builder.build()
|
|
927
|
+
|
|
928
|
+
# Update session with handoff data
|
|
929
|
+
session.handoff_notes = handoff_data["handoff_notes"]
|
|
930
|
+
session.recommended_next = handoff_data["recommended_next"]
|
|
931
|
+
session.blockers = handoff_data["blockers"]
|
|
932
|
+
session.recommended_context = handoff_data["recommended_context"]
|
|
933
|
+
|
|
934
|
+
# Persist handoff data to database before ending session
|
|
935
|
+
self.session_converter.save(session)
|
|
936
|
+
|
|
937
|
+
# End the session
|
|
938
|
+
self.end_session(session_id)
|
|
939
|
+
|
|
940
|
+
# Track handoff effectiveness (optional - only if database available)
|
|
941
|
+
# Note: SessionManager doesn't have direct database access,
|
|
942
|
+
# handoff tracking is primarily done through SDK
|
|
943
|
+
# Users should use SDK.end_session_with_handoff() for full tracking
|
|
944
|
+
|
|
945
|
+
return session
|
|
946
|
+
|
|
795
947
|
def release_session_features(self, session_id: str) -> list[str]:
|
|
796
948
|
"""
|
|
797
949
|
Release all features claimed by a specific session.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Session management and continuity.
|
|
3
|
+
|
|
4
|
+
Provides session lifecycle, handoff, and resumption features.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from htmlgraph.sessions.handoff import (
|
|
8
|
+
ContextRecommender,
|
|
9
|
+
HandoffBuilder,
|
|
10
|
+
HandoffMetrics,
|
|
11
|
+
HandoffTracker,
|
|
12
|
+
SessionResume,
|
|
13
|
+
SessionResumeInfo,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"HandoffBuilder",
|
|
18
|
+
"SessionResume",
|
|
19
|
+
"SessionResumeInfo",
|
|
20
|
+
"HandoffTracker",
|
|
21
|
+
"HandoffMetrics",
|
|
22
|
+
"ContextRecommender",
|
|
23
|
+
]
|