htmlgraph 0.21.0__py3-none-any.whl → 0.23.0__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/agent_detection.py +41 -2
- htmlgraph/analytics/cli.py +86 -20
- htmlgraph/cli.py +519 -87
- htmlgraph/collections/base.py +68 -4
- 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 +161 -0
- htmlgraph/git_events.py +61 -7
- htmlgraph/operations/README.md +62 -0
- htmlgraph/operations/__init__.py +61 -0
- htmlgraph/operations/analytics.py +338 -0
- htmlgraph/operations/events.py +243 -0
- htmlgraph/operations/hooks.py +349 -0
- htmlgraph/operations/server.py +302 -0
- htmlgraph/orchestration/__init__.py +39 -0
- htmlgraph/orchestration/headless_spawner.py +566 -0
- htmlgraph/orchestration/model_selection.py +323 -0
- htmlgraph/orchestrator-system-prompt-optimized.txt +47 -0
- htmlgraph/parser.py +56 -1
- htmlgraph/sdk.py +529 -7
- htmlgraph/server.py +153 -60
- {htmlgraph-0.21.0.dist-info → htmlgraph-0.23.0.dist-info}/METADATA +3 -1
- {htmlgraph-0.21.0.dist-info → htmlgraph-0.23.0.dist-info}/RECORD +40 -19
- /htmlgraph/{orchestration.py → orchestration/task_coordination.py} +0 -0
- {htmlgraph-0.21.0.data → htmlgraph-0.23.0.data}/data/htmlgraph/dashboard.html +0 -0
- {htmlgraph-0.21.0.data → htmlgraph-0.23.0.data}/data/htmlgraph/styles.css +0 -0
- {htmlgraph-0.21.0.data → htmlgraph-0.23.0.data}/data/htmlgraph/templates/AGENTS.md.template +0 -0
- {htmlgraph-0.21.0.data → htmlgraph-0.23.0.data}/data/htmlgraph/templates/CLAUDE.md.template +0 -0
- {htmlgraph-0.21.0.data → htmlgraph-0.23.0.data}/data/htmlgraph/templates/GEMINI.md.template +0 -0
- {htmlgraph-0.21.0.dist-info → htmlgraph-0.23.0.dist-info}/WHEEL +0 -0
- {htmlgraph-0.21.0.dist-info → htmlgraph-0.23.0.dist-info}/entry_points.txt +0 -0
htmlgraph/sdk.py
CHANGED
|
@@ -88,6 +88,31 @@ class SDK:
|
|
|
88
88
|
- tracks: Work tracks
|
|
89
89
|
- agents: Agent information
|
|
90
90
|
- todos: Persistent task tracking (mirrors TodoWrite API)
|
|
91
|
+
- patterns: Workflow patterns (optimal/anti-pattern)
|
|
92
|
+
- insights: Session health insights
|
|
93
|
+
- metrics: Aggregated time-series metrics
|
|
94
|
+
|
|
95
|
+
Analytics & Decision Support:
|
|
96
|
+
sdk.dep_analytics - Dependency analysis
|
|
97
|
+
.find_bottlenecks(top_n=5) - Find blocking tasks
|
|
98
|
+
.get_parallel_work(max_agents=5) - Find parallelizable work
|
|
99
|
+
.recommend_next_tasks(agent_count=1) - Smart recommendations
|
|
100
|
+
.assess_dependency_risk() - Check for circular deps
|
|
101
|
+
.impact_analysis(node_id) - See what task unlocks
|
|
102
|
+
|
|
103
|
+
sdk.analytics - Work analytics
|
|
104
|
+
.get_work_type_distribution() - Breakdown by type
|
|
105
|
+
.get_spike_to_feature_ratio() - Investigation vs implementation
|
|
106
|
+
.get_maintenance_burden() - Chore vs feature ratio
|
|
107
|
+
|
|
108
|
+
sdk.context - Context tracking
|
|
109
|
+
.get_context_usage() - Session context metrics
|
|
110
|
+
.get_context_efficiency() - Efficiency score
|
|
111
|
+
|
|
112
|
+
Discovery & Help:
|
|
113
|
+
sdk.help() - Get structured help for all operations
|
|
114
|
+
sdk.help('analytics') - Get analytics-specific help
|
|
115
|
+
sdk.help('features') - Get feature collection help
|
|
91
116
|
|
|
92
117
|
Error Handling Patterns
|
|
93
118
|
=======================
|
|
@@ -131,12 +156,15 @@ class SDK:
|
|
|
131
156
|
... except ValidationError:
|
|
132
157
|
... print("Title required")
|
|
133
158
|
|
|
134
|
-
BATCH OPERATIONS (Return
|
|
135
|
-
Batch operations return
|
|
136
|
-
|
|
159
|
+
BATCH OPERATIONS (Return Results Dict):
|
|
160
|
+
Batch operations return dict with success_count, failed_ids, and warnings.
|
|
161
|
+
Provides detailed feedback for partial failures.
|
|
137
162
|
|
|
138
|
-
>>>
|
|
139
|
-
>>> print(f"Completed {
|
|
163
|
+
>>> result = sdk.features.mark_done(["feat-1", "missing", "feat-2"])
|
|
164
|
+
>>> print(f"Completed {result['success_count']} of 3")
|
|
165
|
+
>>> if result['failed_ids']:
|
|
166
|
+
... print(f"Failed: {result['failed_ids']}")
|
|
167
|
+
... print(f"Reasons: {result['warnings']}")
|
|
140
168
|
|
|
141
169
|
Pattern Summary:
|
|
142
170
|
| Operation Type | Error Behavior | Example Method |
|
|
@@ -145,7 +173,7 @@ class SDK:
|
|
|
145
173
|
| Query | Return [] | .where(), .all() |
|
|
146
174
|
| Edit | Raise Exception | .edit(id) |
|
|
147
175
|
| Create | Raise on Invalid | .create(title) |
|
|
148
|
-
| Batch | Return
|
|
176
|
+
| Batch | Return Results Dict| .mark_done([ids]) |
|
|
149
177
|
| Delete | Return Bool | .delete(id) |
|
|
150
178
|
|
|
151
179
|
Available Exceptions:
|
|
@@ -1775,6 +1803,398 @@ class SDK:
|
|
|
1775
1803
|
|
|
1776
1804
|
return None
|
|
1777
1805
|
|
|
1806
|
+
# =========================================================================
|
|
1807
|
+
# Operations Layer - Server, Hooks, Events, Analytics
|
|
1808
|
+
# =========================================================================
|
|
1809
|
+
|
|
1810
|
+
def start_server(
|
|
1811
|
+
self,
|
|
1812
|
+
port: int = 8080,
|
|
1813
|
+
host: str = "localhost",
|
|
1814
|
+
watch: bool = True,
|
|
1815
|
+
auto_port: bool = False,
|
|
1816
|
+
) -> Any:
|
|
1817
|
+
"""
|
|
1818
|
+
Start HtmlGraph server for browsing graph via web UI.
|
|
1819
|
+
|
|
1820
|
+
Args:
|
|
1821
|
+
port: Port to listen on (default: 8080)
|
|
1822
|
+
host: Host to bind to (default: "localhost")
|
|
1823
|
+
watch: Enable file watching for auto-reload (default: True)
|
|
1824
|
+
auto_port: Automatically find available port if specified port is in use (default: False)
|
|
1825
|
+
|
|
1826
|
+
Returns:
|
|
1827
|
+
ServerStartResult with handle, warnings, and config used
|
|
1828
|
+
|
|
1829
|
+
Raises:
|
|
1830
|
+
PortInUseError: If port is in use and auto_port=False
|
|
1831
|
+
ServerStartError: If server fails to start
|
|
1832
|
+
|
|
1833
|
+
Example:
|
|
1834
|
+
>>> sdk = SDK(agent="claude")
|
|
1835
|
+
>>> result = sdk.start_server(port=8080, watch=True)
|
|
1836
|
+
>>> print(f"Server running at {result.handle.url}")
|
|
1837
|
+
>>> # Open browser to http://localhost:8080
|
|
1838
|
+
>>>
|
|
1839
|
+
>>> # Stop server when done
|
|
1840
|
+
>>> sdk.stop_server(result.handle)
|
|
1841
|
+
|
|
1842
|
+
See also:
|
|
1843
|
+
stop_server: Stop running server
|
|
1844
|
+
get_server_status: Check if server is running
|
|
1845
|
+
"""
|
|
1846
|
+
from htmlgraph.operations import server
|
|
1847
|
+
|
|
1848
|
+
return server.start_server(
|
|
1849
|
+
port=port,
|
|
1850
|
+
graph_dir=self._directory,
|
|
1851
|
+
static_dir=self._directory.parent, # Project root for index.html
|
|
1852
|
+
host=host,
|
|
1853
|
+
watch=watch,
|
|
1854
|
+
auto_port=auto_port,
|
|
1855
|
+
)
|
|
1856
|
+
|
|
1857
|
+
def stop_server(self, handle: Any) -> None:
|
|
1858
|
+
"""
|
|
1859
|
+
Stop a running HtmlGraph server.
|
|
1860
|
+
|
|
1861
|
+
Args:
|
|
1862
|
+
handle: ServerHandle returned from start_server()
|
|
1863
|
+
|
|
1864
|
+
Raises:
|
|
1865
|
+
ServerStartError: If shutdown fails
|
|
1866
|
+
|
|
1867
|
+
Example:
|
|
1868
|
+
>>> sdk = SDK(agent="claude")
|
|
1869
|
+
>>> result = sdk.start_server()
|
|
1870
|
+
>>> # Work with server...
|
|
1871
|
+
>>> sdk.stop_server(result.handle)
|
|
1872
|
+
"""
|
|
1873
|
+
from htmlgraph.operations import server
|
|
1874
|
+
|
|
1875
|
+
server.stop_server(handle)
|
|
1876
|
+
|
|
1877
|
+
def get_server_status(self, handle: Any | None = None) -> Any:
|
|
1878
|
+
"""
|
|
1879
|
+
Check server status.
|
|
1880
|
+
|
|
1881
|
+
Args:
|
|
1882
|
+
handle: Optional ServerHandle to check
|
|
1883
|
+
|
|
1884
|
+
Returns:
|
|
1885
|
+
ServerStatus indicating whether server is running
|
|
1886
|
+
|
|
1887
|
+
Example:
|
|
1888
|
+
>>> sdk = SDK(agent="claude")
|
|
1889
|
+
>>> result = sdk.start_server()
|
|
1890
|
+
>>> status = sdk.get_server_status(result.handle)
|
|
1891
|
+
>>> print(f"Running: {status.running}")
|
|
1892
|
+
"""
|
|
1893
|
+
from htmlgraph.operations import server
|
|
1894
|
+
|
|
1895
|
+
return server.get_server_status(handle)
|
|
1896
|
+
|
|
1897
|
+
def install_hooks(self, use_copy: bool = False) -> Any:
|
|
1898
|
+
"""
|
|
1899
|
+
Install Git hooks for automatic tracking.
|
|
1900
|
+
|
|
1901
|
+
Installs hooks that automatically track sessions, activities, and features
|
|
1902
|
+
as you work.
|
|
1903
|
+
|
|
1904
|
+
Args:
|
|
1905
|
+
use_copy: Force copy instead of symlink (default: False)
|
|
1906
|
+
|
|
1907
|
+
Returns:
|
|
1908
|
+
HookInstallResult with installation details
|
|
1909
|
+
|
|
1910
|
+
Raises:
|
|
1911
|
+
HookInstallError: If installation fails
|
|
1912
|
+
HookConfigError: If configuration is invalid
|
|
1913
|
+
|
|
1914
|
+
Example:
|
|
1915
|
+
>>> sdk = SDK(agent="claude")
|
|
1916
|
+
>>> result = sdk.install_hooks()
|
|
1917
|
+
>>> print(f"Installed: {result.installed}")
|
|
1918
|
+
>>> print(f"Skipped: {result.skipped}")
|
|
1919
|
+
>>> if result.warnings:
|
|
1920
|
+
... print(f"Warnings: {result.warnings}")
|
|
1921
|
+
|
|
1922
|
+
See also:
|
|
1923
|
+
list_hooks: List installed hooks
|
|
1924
|
+
validate_hook_config: Validate hook configuration
|
|
1925
|
+
"""
|
|
1926
|
+
from htmlgraph.operations import hooks
|
|
1927
|
+
|
|
1928
|
+
return hooks.install_hooks(
|
|
1929
|
+
project_dir=self._directory.parent,
|
|
1930
|
+
use_copy=use_copy,
|
|
1931
|
+
)
|
|
1932
|
+
|
|
1933
|
+
def list_hooks(self) -> Any:
|
|
1934
|
+
"""
|
|
1935
|
+
List Git hooks status (enabled/disabled/missing).
|
|
1936
|
+
|
|
1937
|
+
Returns:
|
|
1938
|
+
HookListResult with enabled, disabled, and missing hooks
|
|
1939
|
+
|
|
1940
|
+
Example:
|
|
1941
|
+
>>> sdk = SDK(agent="claude")
|
|
1942
|
+
>>> result = sdk.list_hooks()
|
|
1943
|
+
>>> print(f"Enabled: {result.enabled}")
|
|
1944
|
+
>>> print(f"Disabled: {result.disabled}")
|
|
1945
|
+
>>> print(f"Missing: {result.missing}")
|
|
1946
|
+
"""
|
|
1947
|
+
from htmlgraph.operations import hooks
|
|
1948
|
+
|
|
1949
|
+
return hooks.list_hooks(project_dir=self._directory.parent)
|
|
1950
|
+
|
|
1951
|
+
def validate_hook_config(self) -> Any:
|
|
1952
|
+
"""
|
|
1953
|
+
Validate hook configuration.
|
|
1954
|
+
|
|
1955
|
+
Returns:
|
|
1956
|
+
HookValidationResult with validation status
|
|
1957
|
+
|
|
1958
|
+
Example:
|
|
1959
|
+
>>> sdk = SDK(agent="claude")
|
|
1960
|
+
>>> result = sdk.validate_hook_config()
|
|
1961
|
+
>>> if not result.valid:
|
|
1962
|
+
... print(f"Errors: {result.errors}")
|
|
1963
|
+
>>> if result.warnings:
|
|
1964
|
+
... print(f"Warnings: {result.warnings}")
|
|
1965
|
+
"""
|
|
1966
|
+
from htmlgraph.operations import hooks
|
|
1967
|
+
|
|
1968
|
+
return hooks.validate_hook_config(project_dir=self._directory.parent)
|
|
1969
|
+
|
|
1970
|
+
def export_sessions(self, overwrite: bool = False) -> Any:
|
|
1971
|
+
"""
|
|
1972
|
+
Export legacy session HTML logs to JSONL events.
|
|
1973
|
+
|
|
1974
|
+
Converts HTML session files to JSONL format for efficient querying.
|
|
1975
|
+
|
|
1976
|
+
Args:
|
|
1977
|
+
overwrite: Whether to overwrite existing JSONL files (default: False)
|
|
1978
|
+
|
|
1979
|
+
Returns:
|
|
1980
|
+
EventExportResult with counts of written, skipped, failed files
|
|
1981
|
+
|
|
1982
|
+
Raises:
|
|
1983
|
+
EventOperationError: If export fails
|
|
1984
|
+
|
|
1985
|
+
Example:
|
|
1986
|
+
>>> sdk = SDK(agent="claude")
|
|
1987
|
+
>>> result = sdk.export_sessions()
|
|
1988
|
+
>>> print(f"Exported {result.written} sessions")
|
|
1989
|
+
>>> print(f"Skipped {result.skipped} (already exist)")
|
|
1990
|
+
>>> if result.failed > 0:
|
|
1991
|
+
... print(f"Failed {result.failed} sessions")
|
|
1992
|
+
|
|
1993
|
+
See also:
|
|
1994
|
+
rebuild_event_index: Rebuild SQLite index from JSONL
|
|
1995
|
+
query_events: Query exported events
|
|
1996
|
+
"""
|
|
1997
|
+
from htmlgraph.operations import events
|
|
1998
|
+
|
|
1999
|
+
return events.export_sessions(
|
|
2000
|
+
graph_dir=self._directory,
|
|
2001
|
+
overwrite=overwrite,
|
|
2002
|
+
)
|
|
2003
|
+
|
|
2004
|
+
def rebuild_event_index(self) -> Any:
|
|
2005
|
+
"""
|
|
2006
|
+
Rebuild SQLite analytics index from JSONL events.
|
|
2007
|
+
|
|
2008
|
+
Creates an optimized SQLite index for fast analytics queries.
|
|
2009
|
+
|
|
2010
|
+
Returns:
|
|
2011
|
+
EventRebuildResult with db_path and counts of inserted/skipped events
|
|
2012
|
+
|
|
2013
|
+
Raises:
|
|
2014
|
+
EventOperationError: If rebuild fails
|
|
2015
|
+
|
|
2016
|
+
Example:
|
|
2017
|
+
>>> sdk = SDK(agent="claude")
|
|
2018
|
+
>>> result = sdk.rebuild_event_index()
|
|
2019
|
+
>>> print(f"Rebuilt index: {result.db_path}")
|
|
2020
|
+
>>> print(f"Inserted {result.inserted} events")
|
|
2021
|
+
>>> print(f"Skipped {result.skipped} (duplicates)")
|
|
2022
|
+
|
|
2023
|
+
See also:
|
|
2024
|
+
export_sessions: Export HTML sessions to JSONL first
|
|
2025
|
+
"""
|
|
2026
|
+
from htmlgraph.operations import events
|
|
2027
|
+
|
|
2028
|
+
return events.rebuild_index(graph_dir=self._directory)
|
|
2029
|
+
|
|
2030
|
+
def query_events(
|
|
2031
|
+
self,
|
|
2032
|
+
session_id: str | None = None,
|
|
2033
|
+
tool: str | None = None,
|
|
2034
|
+
feature_id: str | None = None,
|
|
2035
|
+
since: str | None = None,
|
|
2036
|
+
limit: int | None = None,
|
|
2037
|
+
) -> Any:
|
|
2038
|
+
"""
|
|
2039
|
+
Query events from JSONL logs with optional filters.
|
|
2040
|
+
|
|
2041
|
+
Args:
|
|
2042
|
+
session_id: Filter by session ID (None = all sessions)
|
|
2043
|
+
tool: Filter by tool name (e.g., 'Bash', 'Edit')
|
|
2044
|
+
feature_id: Filter by attributed feature ID
|
|
2045
|
+
since: Only events after this timestamp (ISO string)
|
|
2046
|
+
limit: Maximum number of events to return
|
|
2047
|
+
|
|
2048
|
+
Returns:
|
|
2049
|
+
EventQueryResult with matching events and total count
|
|
2050
|
+
|
|
2051
|
+
Raises:
|
|
2052
|
+
EventOperationError: If query fails
|
|
2053
|
+
|
|
2054
|
+
Example:
|
|
2055
|
+
>>> sdk = SDK(agent="claude")
|
|
2056
|
+
>>> # Get all events for a session
|
|
2057
|
+
>>> result = sdk.query_events(session_id="sess-123")
|
|
2058
|
+
>>> print(f"Found {result.total} events")
|
|
2059
|
+
>>>
|
|
2060
|
+
>>> # Get recent Bash events
|
|
2061
|
+
>>> result = sdk.query_events(
|
|
2062
|
+
... tool="Bash",
|
|
2063
|
+
... since="2025-01-01T00:00:00Z",
|
|
2064
|
+
... limit=10
|
|
2065
|
+
... )
|
|
2066
|
+
>>> for event in result.events:
|
|
2067
|
+
... print(f"{event['timestamp']}: {event['summary']}")
|
|
2068
|
+
|
|
2069
|
+
See also:
|
|
2070
|
+
export_sessions: Export sessions to JSONL first
|
|
2071
|
+
get_event_stats: Get event statistics
|
|
2072
|
+
"""
|
|
2073
|
+
from htmlgraph.operations import events
|
|
2074
|
+
|
|
2075
|
+
return events.query_events(
|
|
2076
|
+
graph_dir=self._directory,
|
|
2077
|
+
session_id=session_id,
|
|
2078
|
+
tool=tool,
|
|
2079
|
+
feature_id=feature_id,
|
|
2080
|
+
since=since,
|
|
2081
|
+
limit=limit,
|
|
2082
|
+
)
|
|
2083
|
+
|
|
2084
|
+
def get_event_stats(self) -> Any:
|
|
2085
|
+
"""
|
|
2086
|
+
Get statistics about events in the system.
|
|
2087
|
+
|
|
2088
|
+
Returns:
|
|
2089
|
+
EventStats with counts of total events, sessions, and files
|
|
2090
|
+
|
|
2091
|
+
Example:
|
|
2092
|
+
>>> sdk = SDK(agent="claude")
|
|
2093
|
+
>>> stats = sdk.get_event_stats()
|
|
2094
|
+
>>> print(f"Total events: {stats.total_events}")
|
|
2095
|
+
>>> print(f"Sessions: {stats.session_count}")
|
|
2096
|
+
>>> print(f"JSONL files: {stats.file_count}")
|
|
2097
|
+
"""
|
|
2098
|
+
from htmlgraph.operations import events
|
|
2099
|
+
|
|
2100
|
+
return events.get_event_stats(graph_dir=self._directory)
|
|
2101
|
+
|
|
2102
|
+
def analyze_session(self, session_id: str) -> Any:
|
|
2103
|
+
"""
|
|
2104
|
+
Compute detailed analytics for a single session.
|
|
2105
|
+
|
|
2106
|
+
Analyzes work distribution, spike-to-feature ratio, maintenance burden,
|
|
2107
|
+
transition metrics, and more.
|
|
2108
|
+
|
|
2109
|
+
Args:
|
|
2110
|
+
session_id: ID of the session to analyze
|
|
2111
|
+
|
|
2112
|
+
Returns:
|
|
2113
|
+
AnalyticsSessionResult with session metrics and warnings
|
|
2114
|
+
|
|
2115
|
+
Raises:
|
|
2116
|
+
AnalyticsOperationError: If session cannot be analyzed
|
|
2117
|
+
|
|
2118
|
+
Example:
|
|
2119
|
+
>>> sdk = SDK(agent="claude")
|
|
2120
|
+
>>> result = sdk.analyze_session("sess-123")
|
|
2121
|
+
>>> print(f"Primary work type: {result.metrics['primary_work_type']}")
|
|
2122
|
+
>>> print(f"Total events: {result.metrics['total_events']}")
|
|
2123
|
+
>>> print(f"Work distribution: {result.metrics['work_distribution']}")
|
|
2124
|
+
>>> if result.warnings:
|
|
2125
|
+
... print(f"Warnings: {result.warnings}")
|
|
2126
|
+
|
|
2127
|
+
See also:
|
|
2128
|
+
analyze_project: Analyze entire project
|
|
2129
|
+
"""
|
|
2130
|
+
from htmlgraph.operations import analytics
|
|
2131
|
+
|
|
2132
|
+
return analytics.analyze_session(
|
|
2133
|
+
graph_dir=self._directory,
|
|
2134
|
+
session_id=session_id,
|
|
2135
|
+
)
|
|
2136
|
+
|
|
2137
|
+
def analyze_project(self) -> Any:
|
|
2138
|
+
"""
|
|
2139
|
+
Compute project-wide analytics.
|
|
2140
|
+
|
|
2141
|
+
Analyzes all sessions, work distribution, spike-to-feature ratios,
|
|
2142
|
+
maintenance burden, and session types across the entire project.
|
|
2143
|
+
|
|
2144
|
+
Returns:
|
|
2145
|
+
AnalyticsProjectResult with project metrics and warnings
|
|
2146
|
+
|
|
2147
|
+
Raises:
|
|
2148
|
+
AnalyticsOperationError: If project cannot be analyzed
|
|
2149
|
+
|
|
2150
|
+
Example:
|
|
2151
|
+
>>> sdk = SDK(agent="claude")
|
|
2152
|
+
>>> result = sdk.analyze_project()
|
|
2153
|
+
>>> print(f"Total sessions: {result.metrics['total_sessions']}")
|
|
2154
|
+
>>> print(f"Work distribution: {result.metrics['work_distribution']}")
|
|
2155
|
+
>>> print(f"Spike-to-feature ratio: {result.metrics['spike_to_feature_ratio']}")
|
|
2156
|
+
>>> print(f"Session types: {result.metrics['session_types']}")
|
|
2157
|
+
>>> for session in result.metrics['recent_sessions']:
|
|
2158
|
+
... print(f" {session['session_id']}: {session['primary_work_type']}")
|
|
2159
|
+
|
|
2160
|
+
See also:
|
|
2161
|
+
analyze_session: Analyze a single session
|
|
2162
|
+
get_work_recommendations: Get work recommendations
|
|
2163
|
+
"""
|
|
2164
|
+
from htmlgraph.operations import analytics
|
|
2165
|
+
|
|
2166
|
+
return analytics.analyze_project(graph_dir=self._directory)
|
|
2167
|
+
|
|
2168
|
+
def get_work_recommendations(self) -> Any:
|
|
2169
|
+
"""
|
|
2170
|
+
Get smart work recommendations based on project state.
|
|
2171
|
+
|
|
2172
|
+
Uses dependency analytics to recommend next tasks based on priority,
|
|
2173
|
+
dependencies, and impact.
|
|
2174
|
+
|
|
2175
|
+
Returns:
|
|
2176
|
+
RecommendationsResult with recommendations, reasoning, and warnings
|
|
2177
|
+
|
|
2178
|
+
Raises:
|
|
2179
|
+
AnalyticsOperationError: If recommendations cannot be generated
|
|
2180
|
+
|
|
2181
|
+
Example:
|
|
2182
|
+
>>> sdk = SDK(agent="claude")
|
|
2183
|
+
>>> result = sdk.get_work_recommendations()
|
|
2184
|
+
>>> for rec in result.recommendations:
|
|
2185
|
+
... print(f"{rec['title']} (score: {rec['score']})")
|
|
2186
|
+
... print(f" Reasons: {rec['reasons']}")
|
|
2187
|
+
... print(f" Unlocks: {rec['unlocks']}")
|
|
2188
|
+
>>> print(f"Reasoning: {result.reasoning}")
|
|
2189
|
+
|
|
2190
|
+
See also:
|
|
2191
|
+
recommend_next_work: Legacy method (backward compatibility)
|
|
2192
|
+
get_work_queue: Get prioritized work queue
|
|
2193
|
+
"""
|
|
2194
|
+
from htmlgraph.operations import analytics
|
|
2195
|
+
|
|
2196
|
+
return analytics.get_recommendations(graph_dir=self._directory)
|
|
2197
|
+
|
|
1778
2198
|
# =========================================================================
|
|
1779
2199
|
# Help & Documentation
|
|
1780
2200
|
# =========================================================================
|
|
@@ -1870,11 +2290,24 @@ ANALYTICS INTERFACES:
|
|
|
1870
2290
|
sdk.dep_analytics - Dependency analytics
|
|
1871
2291
|
sdk.context - Context analytics
|
|
1872
2292
|
|
|
2293
|
+
OPERATIONS (Server, Hooks, Events):
|
|
2294
|
+
sdk.start_server() - Start web server for graph browsing
|
|
2295
|
+
sdk.stop_server() - Stop running server
|
|
2296
|
+
sdk.install_hooks() - Install Git hooks for tracking
|
|
2297
|
+
sdk.list_hooks() - List Git hooks status
|
|
2298
|
+
sdk.export_sessions() - Export HTML sessions to JSONL
|
|
2299
|
+
sdk.rebuild_event_index() - Rebuild SQLite index from events
|
|
2300
|
+
sdk.query_events() - Query JSONL event logs
|
|
2301
|
+
sdk.get_event_stats() - Get event statistics
|
|
2302
|
+
sdk.analyze_session() - Analyze single session metrics
|
|
2303
|
+
sdk.analyze_project() - Analyze project-wide metrics
|
|
2304
|
+
sdk.get_work_recommendations() - Get work recommendations
|
|
2305
|
+
|
|
1873
2306
|
ERROR HANDLING:
|
|
1874
2307
|
Lookup (.get) - Returns None if not found
|
|
1875
2308
|
Query (.where) - Returns empty list on no matches
|
|
1876
2309
|
Edit (.edit) - Raises NodeNotFoundError if missing
|
|
1877
|
-
Batch (.mark_done) - Returns
|
|
2310
|
+
Batch (.mark_done) - Returns dict with success_count, failed_ids, warnings
|
|
1878
2311
|
|
|
1879
2312
|
For detailed help on a topic:
|
|
1880
2313
|
sdk.help('features') - Feature collection methods
|
|
@@ -1882,6 +2315,7 @@ For detailed help on a topic:
|
|
|
1882
2315
|
sdk.help('sessions') - Session management
|
|
1883
2316
|
sdk.help('orchestration') - Subagent orchestration
|
|
1884
2317
|
sdk.help('planning') - Planning workflow
|
|
2318
|
+
sdk.help('operations') - Server, hooks, events operations
|
|
1885
2319
|
"""
|
|
1886
2320
|
|
|
1887
2321
|
def __dir__(self) -> list[str]:
|
|
@@ -1917,6 +2351,11 @@ For detailed help on a topic:
|
|
|
1917
2351
|
# Work queue
|
|
1918
2352
|
"get_work_queue",
|
|
1919
2353
|
"work_next",
|
|
2354
|
+
# Operations
|
|
2355
|
+
"start_server",
|
|
2356
|
+
"install_hooks",
|
|
2357
|
+
"export_sessions",
|
|
2358
|
+
"analyze_project",
|
|
1920
2359
|
# Help
|
|
1921
2360
|
"help",
|
|
1922
2361
|
]
|
|
@@ -1964,6 +2403,18 @@ CONTEXT MANAGER:
|
|
|
1964
2403
|
f.complete_step(0)
|
|
1965
2404
|
# Auto-saves on exit
|
|
1966
2405
|
|
|
2406
|
+
BATCH OPERATIONS:
|
|
2407
|
+
result = sdk.features.mark_done(["feat-001", "feat-002"])
|
|
2408
|
+
print(f"Completed {result['success_count']} features")
|
|
2409
|
+
if result['failed_ids']:
|
|
2410
|
+
print(f"Failed: {result['failed_ids']}")
|
|
2411
|
+
|
|
2412
|
+
COMMON MISTAKES:
|
|
2413
|
+
❌ sdk.features.mark_complete([ids]) → ✅ sdk.features.mark_done([ids])
|
|
2414
|
+
❌ sdk.feature.create(...) → ✅ sdk.features.create(...)
|
|
2415
|
+
❌ claim(id, agent_id=...) → ✅ claim(id, agent=...)
|
|
2416
|
+
❌ builder.status = "done" → ✅ builder.save(); then edit()
|
|
2417
|
+
|
|
1967
2418
|
See also: sdk.help('bugs'), sdk.help('spikes'), sdk.help('chores')
|
|
1968
2419
|
"""
|
|
1969
2420
|
|
|
@@ -2344,6 +2795,77 @@ BENEFITS:
|
|
|
2344
2795
|
- All context in one place
|
|
2345
2796
|
|
|
2346
2797
|
See also: sdk.help('sessions')
|
|
2798
|
+
"""
|
|
2799
|
+
|
|
2800
|
+
elif topic in ["operation", "operations", "server", "hooks", "events"]:
|
|
2801
|
+
return """OPERATIONS - Server, Hooks, Events
|
|
2802
|
+
|
|
2803
|
+
Infrastructure operations for running HtmlGraph.
|
|
2804
|
+
|
|
2805
|
+
SERVER OPERATIONS:
|
|
2806
|
+
# Start server for web UI
|
|
2807
|
+
result = sdk.start_server(port=8080, watch=True)
|
|
2808
|
+
print(f"Server at {result.handle.url}")
|
|
2809
|
+
|
|
2810
|
+
# Stop server
|
|
2811
|
+
sdk.stop_server(result.handle)
|
|
2812
|
+
|
|
2813
|
+
# Check status
|
|
2814
|
+
status = sdk.get_server_status(result.handle)
|
|
2815
|
+
|
|
2816
|
+
HOOK OPERATIONS:
|
|
2817
|
+
# Install Git hooks for automatic tracking
|
|
2818
|
+
result = sdk.install_hooks()
|
|
2819
|
+
print(f"Installed: {result.installed}")
|
|
2820
|
+
|
|
2821
|
+
# List hook status
|
|
2822
|
+
result = sdk.list_hooks()
|
|
2823
|
+
print(f"Enabled: {result.enabled}")
|
|
2824
|
+
print(f"Missing: {result.missing}")
|
|
2825
|
+
|
|
2826
|
+
# Validate configuration
|
|
2827
|
+
result = sdk.validate_hook_config()
|
|
2828
|
+
if not result.valid:
|
|
2829
|
+
print(f"Errors: {result.errors}")
|
|
2830
|
+
|
|
2831
|
+
EVENT OPERATIONS:
|
|
2832
|
+
# Export HTML sessions to JSONL
|
|
2833
|
+
result = sdk.export_sessions()
|
|
2834
|
+
print(f"Exported {result.written} sessions")
|
|
2835
|
+
|
|
2836
|
+
# Rebuild SQLite index
|
|
2837
|
+
result = sdk.rebuild_event_index()
|
|
2838
|
+
print(f"Inserted {result.inserted} events")
|
|
2839
|
+
|
|
2840
|
+
# Query events
|
|
2841
|
+
result = sdk.query_events(
|
|
2842
|
+
session_id="sess-123",
|
|
2843
|
+
tool="Bash",
|
|
2844
|
+
limit=10
|
|
2845
|
+
)
|
|
2846
|
+
for event in result.events:
|
|
2847
|
+
print(f"{event['timestamp']}: {event['summary']}")
|
|
2848
|
+
|
|
2849
|
+
# Get statistics
|
|
2850
|
+
stats = sdk.get_event_stats()
|
|
2851
|
+
print(f"Total events: {stats.total_events}")
|
|
2852
|
+
|
|
2853
|
+
ANALYTICS OPERATIONS:
|
|
2854
|
+
# Analyze session
|
|
2855
|
+
result = sdk.analyze_session("sess-123")
|
|
2856
|
+
print(f"Primary work: {result.metrics['primary_work_type']}")
|
|
2857
|
+
|
|
2858
|
+
# Analyze project
|
|
2859
|
+
result = sdk.analyze_project()
|
|
2860
|
+
print(f"Total sessions: {result.metrics['total_sessions']}")
|
|
2861
|
+
print(f"Work distribution: {result.metrics['work_distribution']}")
|
|
2862
|
+
|
|
2863
|
+
# Get recommendations
|
|
2864
|
+
result = sdk.get_work_recommendations()
|
|
2865
|
+
for rec in result.recommendations:
|
|
2866
|
+
print(f"{rec['title']} (score: {rec['score']})")
|
|
2867
|
+
|
|
2868
|
+
See also: sdk.help('analytics'), sdk.help('sessions')
|
|
2347
2869
|
"""
|
|
2348
2870
|
|
|
2349
2871
|
else:
|