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.
Files changed (40) hide show
  1. htmlgraph/__init__.py +1 -1
  2. htmlgraph/agent_detection.py +41 -2
  3. htmlgraph/analytics/cli.py +86 -20
  4. htmlgraph/cli.py +519 -87
  5. htmlgraph/collections/base.py +68 -4
  6. htmlgraph/docs/__init__.py +77 -0
  7. htmlgraph/docs/docs_version.py +55 -0
  8. htmlgraph/docs/metadata.py +93 -0
  9. htmlgraph/docs/migrations.py +232 -0
  10. htmlgraph/docs/template_engine.py +143 -0
  11. htmlgraph/docs/templates/_sections/cli_reference.md.j2 +52 -0
  12. htmlgraph/docs/templates/_sections/core_concepts.md.j2 +29 -0
  13. htmlgraph/docs/templates/_sections/sdk_basics.md.j2 +69 -0
  14. htmlgraph/docs/templates/base_agents.md.j2 +78 -0
  15. htmlgraph/docs/templates/example_user_override.md.j2 +47 -0
  16. htmlgraph/docs/version_check.py +161 -0
  17. htmlgraph/git_events.py +61 -7
  18. htmlgraph/operations/README.md +62 -0
  19. htmlgraph/operations/__init__.py +61 -0
  20. htmlgraph/operations/analytics.py +338 -0
  21. htmlgraph/operations/events.py +243 -0
  22. htmlgraph/operations/hooks.py +349 -0
  23. htmlgraph/operations/server.py +302 -0
  24. htmlgraph/orchestration/__init__.py +39 -0
  25. htmlgraph/orchestration/headless_spawner.py +566 -0
  26. htmlgraph/orchestration/model_selection.py +323 -0
  27. htmlgraph/orchestrator-system-prompt-optimized.txt +47 -0
  28. htmlgraph/parser.py +56 -1
  29. htmlgraph/sdk.py +529 -7
  30. htmlgraph/server.py +153 -60
  31. {htmlgraph-0.21.0.dist-info → htmlgraph-0.23.0.dist-info}/METADATA +3 -1
  32. {htmlgraph-0.21.0.dist-info → htmlgraph-0.23.0.dist-info}/RECORD +40 -19
  33. /htmlgraph/{orchestration.py → orchestration/task_coordination.py} +0 -0
  34. {htmlgraph-0.21.0.data → htmlgraph-0.23.0.data}/data/htmlgraph/dashboard.html +0 -0
  35. {htmlgraph-0.21.0.data → htmlgraph-0.23.0.data}/data/htmlgraph/styles.css +0 -0
  36. {htmlgraph-0.21.0.data → htmlgraph-0.23.0.data}/data/htmlgraph/templates/AGENTS.md.template +0 -0
  37. {htmlgraph-0.21.0.data → htmlgraph-0.23.0.data}/data/htmlgraph/templates/CLAUDE.md.template +0 -0
  38. {htmlgraph-0.21.0.data → htmlgraph-0.23.0.data}/data/htmlgraph/templates/GEMINI.md.template +0 -0
  39. {htmlgraph-0.21.0.dist-info → htmlgraph-0.23.0.dist-info}/WHEEL +0 -0
  40. {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 Count):
135
- Batch operations return count of successful items.
136
- Silently skip items that fail.
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
- >>> count = sdk.features.mark_done(["feat-1", "missing", "feat-2"])
139
- >>> print(f"Completed {count} of 3") # Outputs: Completed 2 of 3
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 Count | .mark_done([ids]) |
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 count of successful operations
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: