htmlgraph 0.26.24__py3-none-any.whl → 0.27.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 (155) hide show
  1. htmlgraph/__init__.py +23 -1
  2. htmlgraph/__init__.pyi +123 -0
  3. htmlgraph/agent_registry.py +2 -1
  4. htmlgraph/analytics/cli.py +3 -3
  5. htmlgraph/analytics/cost_analyzer.py +5 -1
  6. htmlgraph/analytics/cross_session.py +13 -9
  7. htmlgraph/analytics/dependency.py +10 -6
  8. htmlgraph/analytics/work_type.py +15 -11
  9. htmlgraph/analytics_index.py +2 -1
  10. htmlgraph/api/main.py +114 -51
  11. htmlgraph/api/templates/dashboard-redesign.html +3 -3
  12. htmlgraph/api/templates/dashboard.html +3 -3
  13. htmlgraph/api/templates/partials/work-items.html +613 -0
  14. htmlgraph/attribute_index.py +2 -1
  15. htmlgraph/builders/base.py +2 -1
  16. htmlgraph/builders/bug.py +2 -1
  17. htmlgraph/builders/chore.py +2 -1
  18. htmlgraph/builders/epic.py +2 -1
  19. htmlgraph/builders/feature.py +2 -1
  20. htmlgraph/builders/insight.py +2 -1
  21. htmlgraph/builders/metric.py +2 -1
  22. htmlgraph/builders/pattern.py +2 -1
  23. htmlgraph/builders/phase.py +2 -1
  24. htmlgraph/builders/spike.py +2 -1
  25. htmlgraph/builders/track.py +28 -1
  26. htmlgraph/cli/analytics.py +2 -1
  27. htmlgraph/cli/base.py +33 -8
  28. htmlgraph/cli/core.py +2 -1
  29. htmlgraph/cli/main.py +2 -1
  30. htmlgraph/cli/models.py +2 -1
  31. htmlgraph/cli/templates/cost_dashboard.py +2 -1
  32. htmlgraph/cli/work/__init__.py +76 -1
  33. htmlgraph/cli/work/browse.py +115 -0
  34. htmlgraph/cli/work/features.py +2 -1
  35. htmlgraph/cli/work/orchestration.py +2 -1
  36. htmlgraph/cli/work/report.py +2 -1
  37. htmlgraph/cli/work/sessions.py +2 -1
  38. htmlgraph/cli/work/snapshot.py +559 -0
  39. htmlgraph/cli/work/tracks.py +2 -1
  40. htmlgraph/collections/base.py +43 -4
  41. htmlgraph/collections/bug.py +2 -1
  42. htmlgraph/collections/chore.py +2 -1
  43. htmlgraph/collections/epic.py +2 -1
  44. htmlgraph/collections/feature.py +2 -1
  45. htmlgraph/collections/insight.py +2 -1
  46. htmlgraph/collections/metric.py +2 -1
  47. htmlgraph/collections/pattern.py +2 -1
  48. htmlgraph/collections/phase.py +2 -1
  49. htmlgraph/collections/session.py +12 -7
  50. htmlgraph/collections/spike.py +6 -1
  51. htmlgraph/collections/task_delegation.py +7 -2
  52. htmlgraph/collections/todo.py +14 -1
  53. htmlgraph/collections/traces.py +15 -10
  54. htmlgraph/context_analytics.py +2 -1
  55. htmlgraph/converter.py +11 -0
  56. htmlgraph/dependency_models.py +2 -1
  57. htmlgraph/edge_index.py +2 -1
  58. htmlgraph/event_log.py +81 -66
  59. htmlgraph/event_migration.py +2 -1
  60. htmlgraph/file_watcher.py +12 -8
  61. htmlgraph/find_api.py +2 -1
  62. htmlgraph/git_events.py +6 -2
  63. htmlgraph/hooks/cigs_pretool_enforcer.py +5 -1
  64. htmlgraph/hooks/drift_handler.py +3 -3
  65. htmlgraph/hooks/event_tracker.py +40 -61
  66. htmlgraph/hooks/installer.py +5 -1
  67. htmlgraph/hooks/orchestrator.py +92 -14
  68. htmlgraph/hooks/orchestrator_reflector.py +4 -0
  69. htmlgraph/hooks/post_tool_use_failure.py +7 -3
  70. htmlgraph/hooks/posttooluse.py +4 -0
  71. htmlgraph/hooks/prompt_analyzer.py +5 -5
  72. htmlgraph/hooks/session_handler.py +5 -2
  73. htmlgraph/hooks/session_summary.py +6 -2
  74. htmlgraph/hooks/validator.py +8 -4
  75. htmlgraph/ids.py +2 -1
  76. htmlgraph/learning.py +2 -1
  77. htmlgraph/mcp_server.py +2 -1
  78. htmlgraph/models.py +18 -1
  79. htmlgraph/operations/analytics.py +2 -1
  80. htmlgraph/operations/bootstrap.py +2 -1
  81. htmlgraph/operations/events.py +2 -1
  82. htmlgraph/operations/fastapi_server.py +2 -1
  83. htmlgraph/operations/hooks.py +2 -1
  84. htmlgraph/operations/initialization.py +2 -1
  85. htmlgraph/operations/server.py +2 -1
  86. htmlgraph/orchestration/__init__.py +4 -0
  87. htmlgraph/orchestration/claude_launcher.py +23 -20
  88. htmlgraph/orchestration/command_builder.py +2 -1
  89. htmlgraph/orchestration/headless_spawner.py +6 -2
  90. htmlgraph/orchestration/model_selection.py +7 -3
  91. htmlgraph/orchestration/plugin_manager.py +25 -21
  92. htmlgraph/orchestration/spawner_event_tracker.py +383 -0
  93. htmlgraph/orchestration/spawners/claude.py +5 -2
  94. htmlgraph/orchestration/spawners/codex.py +12 -19
  95. htmlgraph/orchestration/spawners/copilot.py +13 -18
  96. htmlgraph/orchestration/spawners/gemini.py +12 -19
  97. htmlgraph/orchestration/subprocess_runner.py +6 -3
  98. htmlgraph/orchestration/task_coordination.py +16 -8
  99. htmlgraph/orchestrator.py +2 -1
  100. htmlgraph/parallel.py +2 -1
  101. htmlgraph/query_builder.py +2 -1
  102. htmlgraph/reflection.py +2 -1
  103. htmlgraph/refs.py +344 -0
  104. htmlgraph/repo_hash.py +2 -1
  105. htmlgraph/sdk/__init__.py +398 -0
  106. htmlgraph/sdk/__init__.pyi +14 -0
  107. htmlgraph/sdk/analytics/__init__.py +19 -0
  108. htmlgraph/sdk/analytics/engine.py +155 -0
  109. htmlgraph/sdk/analytics/helpers.py +178 -0
  110. htmlgraph/sdk/analytics/registry.py +109 -0
  111. htmlgraph/sdk/base.py +484 -0
  112. htmlgraph/sdk/constants.py +216 -0
  113. htmlgraph/sdk/core.pyi +308 -0
  114. htmlgraph/sdk/discovery.py +120 -0
  115. htmlgraph/sdk/help/__init__.py +12 -0
  116. htmlgraph/sdk/help/mixin.py +699 -0
  117. htmlgraph/sdk/mixins/__init__.py +15 -0
  118. htmlgraph/sdk/mixins/attribution.py +113 -0
  119. htmlgraph/sdk/mixins/mixin.py +410 -0
  120. htmlgraph/sdk/operations/__init__.py +12 -0
  121. htmlgraph/sdk/operations/mixin.py +427 -0
  122. htmlgraph/sdk/orchestration/__init__.py +17 -0
  123. htmlgraph/sdk/orchestration/coordinator.py +203 -0
  124. htmlgraph/sdk/orchestration/spawner.py +204 -0
  125. htmlgraph/sdk/planning/__init__.py +19 -0
  126. htmlgraph/sdk/planning/bottlenecks.py +93 -0
  127. htmlgraph/sdk/planning/mixin.py +211 -0
  128. htmlgraph/sdk/planning/parallel.py +186 -0
  129. htmlgraph/sdk/planning/queue.py +210 -0
  130. htmlgraph/sdk/planning/recommendations.py +87 -0
  131. htmlgraph/sdk/planning/smart_planning.py +319 -0
  132. htmlgraph/sdk/session/__init__.py +19 -0
  133. htmlgraph/sdk/session/continuity.py +57 -0
  134. htmlgraph/sdk/session/handoff.py +110 -0
  135. htmlgraph/sdk/session/info.py +309 -0
  136. htmlgraph/sdk/session/manager.py +103 -0
  137. htmlgraph/server.py +21 -17
  138. htmlgraph/session_manager.py +1 -7
  139. htmlgraph/session_warning.py +2 -1
  140. htmlgraph/sessions/handoff.py +10 -3
  141. htmlgraph/system_prompts.py +2 -1
  142. htmlgraph/track_builder.py +14 -1
  143. htmlgraph/transcript.py +2 -1
  144. htmlgraph/watch.py +2 -1
  145. htmlgraph/work_type_utils.py +2 -1
  146. {htmlgraph-0.26.24.dist-info → htmlgraph-0.27.0.dist-info}/METADATA +15 -1
  147. {htmlgraph-0.26.24.dist-info → htmlgraph-0.27.0.dist-info}/RECORD +154 -117
  148. htmlgraph/sdk.py +0 -3430
  149. {htmlgraph-0.26.24.data → htmlgraph-0.27.0.data}/data/htmlgraph/dashboard.html +0 -0
  150. {htmlgraph-0.26.24.data → htmlgraph-0.27.0.data}/data/htmlgraph/styles.css +0 -0
  151. {htmlgraph-0.26.24.data → htmlgraph-0.27.0.data}/data/htmlgraph/templates/AGENTS.md.template +0 -0
  152. {htmlgraph-0.26.24.data → htmlgraph-0.27.0.data}/data/htmlgraph/templates/CLAUDE.md.template +0 -0
  153. {htmlgraph-0.26.24.data → htmlgraph-0.27.0.data}/data/htmlgraph/templates/GEMINI.md.template +0 -0
  154. {htmlgraph-0.26.24.dist-info → htmlgraph-0.27.0.dist-info}/WHEEL +0 -0
  155. {htmlgraph-0.26.24.dist-info → htmlgraph-0.27.0.dist-info}/entry_points.txt +0 -0
htmlgraph/sdk/core.pyi ADDED
@@ -0,0 +1,308 @@
1
+ """
2
+ Type stub for htmlgraph.sdk.core module.
3
+
4
+ Contains the SDK class type definitions.
5
+ """
6
+
7
+ from pathlib import Path
8
+ from typing import Any
9
+
10
+ from htmlgraph.agents import AgentInterface
11
+ from htmlgraph.analytics import Analytics, CrossSessionAnalytics, DependencyAnalytics
12
+ from htmlgraph.collections import (
13
+ BaseCollection,
14
+ BugCollection,
15
+ ChoreCollection,
16
+ EpicCollection,
17
+ FeatureCollection,
18
+ PhaseCollection,
19
+ SpikeCollection,
20
+ TaskDelegationCollection,
21
+ TodoCollection,
22
+ )
23
+ from htmlgraph.collections.insight import InsightCollection
24
+ from htmlgraph.collections.metric import MetricCollection
25
+ from htmlgraph.collections.pattern import PatternCollection
26
+ from htmlgraph.collections.session import SessionCollection
27
+ from htmlgraph.context_analytics import ContextAnalytics
28
+ from htmlgraph.db.schema import HtmlGraphDB
29
+ from htmlgraph.graph import HtmlGraph
30
+ from htmlgraph.models import Node
31
+ from htmlgraph.refs import RefManager
32
+ from htmlgraph.sdk.analytics import AnalyticsEngine
33
+ from htmlgraph.session_manager import SessionManager
34
+ from htmlgraph.system_prompts import SystemPromptManager
35
+ from htmlgraph.track_builder import TrackCollection
36
+ from htmlgraph.types import (
37
+ ActiveWorkItem,
38
+ AggregateResultsDict,
39
+ BottleneckDict,
40
+ ImpactAnalysisDict,
41
+ ParallelPlanResult,
42
+ RiskAssessmentDict,
43
+ SessionStartInfo,
44
+ SmartPlanResult,
45
+ TrackCreationResult,
46
+ WorkQueueItem,
47
+ WorkRecommendation,
48
+ )
49
+
50
+ class SDK:
51
+ """
52
+ Main SDK interface for AI agents.
53
+
54
+ Type stub to provide static type information for mypy.
55
+ The actual implementation is in sdk/core.py.
56
+ """
57
+
58
+ # Core attributes
59
+ _directory: Path
60
+ _agent_id: str | None
61
+ _parent_session: str | None
62
+ _db: HtmlGraphDB
63
+ _graph: HtmlGraph
64
+ _bugs_graph: HtmlGraph
65
+ _agent_interface: AgentInterface
66
+ _orchestrator: Any
67
+ _system_prompts: SystemPromptManager | None
68
+ _analytics_engine: AnalyticsEngine
69
+
70
+ # Collection interfaces
71
+ features: FeatureCollection
72
+ bugs: BugCollection
73
+ chores: ChoreCollection
74
+ spikes: SpikeCollection
75
+ epics: EpicCollection
76
+ phases: PhaseCollection
77
+ sessions: SessionCollection
78
+ tracks: TrackCollection
79
+ agents: BaseCollection[Any]
80
+ patterns: PatternCollection
81
+ insights: InsightCollection
82
+ metrics: MetricCollection
83
+ todos: TodoCollection
84
+ task_delegations: TaskDelegationCollection
85
+
86
+ # Session manager
87
+ session_manager: SessionManager
88
+
89
+ # Refs manager
90
+ refs: RefManager
91
+
92
+ def __init__(
93
+ self,
94
+ directory: Path | str | None = None,
95
+ agent: str | None = None,
96
+ parent_session: str | None = None,
97
+ db_path: str | None = None,
98
+ ) -> None: ...
99
+ @property
100
+ def agent(self) -> str | None: ...
101
+ @property
102
+ def system_prompts(self) -> SystemPromptManager: ...
103
+ @property
104
+ def analytics(self) -> Analytics: ...
105
+ @property
106
+ def dep_analytics(self) -> DependencyAnalytics: ...
107
+ @property
108
+ def cross_session_analytics(self) -> CrossSessionAnalytics: ...
109
+ @property
110
+ def context(self) -> ContextAnalytics: ...
111
+ @property
112
+ def pattern_learning(self) -> Any: ...
113
+ @property
114
+ def orchestrator(self) -> Any: ...
115
+ def dismiss_session_warning(self) -> bool: ...
116
+ def get_warning_status(self) -> dict[str, Any]: ...
117
+ def ref(self, short_ref: str) -> Node | None: ...
118
+ def db(self) -> HtmlGraphDB: ...
119
+ def query(self, sql: str, params: tuple[Any, ...] = ()) -> list[dict[str, Any]]: ...
120
+ def execute_query_builder(
121
+ self, sql: str, params: tuple[Any, ...] = ()
122
+ ) -> list[dict[str, Any]]: ...
123
+ def export_to_html(
124
+ self,
125
+ output_dir: str | None = None,
126
+ include_features: bool = True,
127
+ include_sessions: bool = True,
128
+ include_events: bool = False,
129
+ ) -> dict[str, int]: ...
130
+ def _log_event(
131
+ self,
132
+ event_type: str,
133
+ tool_name: str | None = None,
134
+ input_summary: str | None = None,
135
+ output_summary: str | None = None,
136
+ context: dict[str, Any] | None = None,
137
+ cost_tokens: int = 0,
138
+ ) -> bool: ...
139
+ def reload(self) -> None: ...
140
+ def summary(self, max_items: int = 10) -> str: ...
141
+ def my_work(self) -> dict[str, Any]: ...
142
+ def next_task(
143
+ self, priority: str | None = None, auto_claim: bool = True
144
+ ) -> Node | None: ...
145
+ def get_status(self) -> dict[str, Any]: ...
146
+ def dedupe_sessions(
147
+ self,
148
+ max_events: int = 1,
149
+ move_dir_name: str = "_orphans",
150
+ dry_run: bool = False,
151
+ stale_extra_active: bool = True,
152
+ ) -> dict[str, int]: ...
153
+ def track_activity(
154
+ self,
155
+ tool: str,
156
+ summary: str,
157
+ file_paths: list[str] | None = None,
158
+ success: bool = True,
159
+ feature_id: str | None = None,
160
+ session_id: str | None = None,
161
+ parent_activity_id: str | None = None,
162
+ payload: dict[str, Any] | None = None,
163
+ ) -> Any: ...
164
+ def spawn_explorer(
165
+ self,
166
+ task: str,
167
+ scope: str | None = None,
168
+ patterns: list[str] | None = None,
169
+ questions: list[str] | None = None,
170
+ ) -> dict[str, Any]: ...
171
+ def spawn_coder(
172
+ self,
173
+ feature_id: str,
174
+ context: str | None = None,
175
+ files_to_modify: list[str] | None = None,
176
+ test_command: str | None = None,
177
+ ) -> dict[str, Any]: ...
178
+ def orchestrate(
179
+ self,
180
+ feature_id: str,
181
+ exploration_scope: str | None = None,
182
+ test_command: str | None = None,
183
+ ) -> dict[str, Any]: ...
184
+ def help(self, topic: str | None = None) -> str: ...
185
+
186
+ # Session management (from SessionManagerMixin)
187
+ def start_session(
188
+ self,
189
+ session_id: str | None = None,
190
+ title: str | None = None,
191
+ agent: str | None = None,
192
+ ) -> Any: ...
193
+ def end_session(
194
+ self,
195
+ session_id: str,
196
+ handoff_notes: str | None = None,
197
+ recommended_next: str | None = None,
198
+ blockers: list[str] | None = None,
199
+ ) -> Any: ...
200
+ def _ensure_session_exists(
201
+ self, session_id: str, parent_event_id: str | None = None
202
+ ) -> None: ...
203
+
204
+ # Session handoff (from SessionHandoffMixin)
205
+ def prepare_handoff(
206
+ self,
207
+ session_id: str | None = None,
208
+ notes: str | None = None,
209
+ recommended_next: str | None = None,
210
+ blockers: list[str] | None = None,
211
+ ) -> dict[str, Any]: ...
212
+ def receive_handoff(self, handoff_context: dict[str, Any]) -> dict[str, Any]: ...
213
+
214
+ # Session continuity (from SessionContinuityMixin)
215
+ def get_session_continuity(
216
+ self, session_id: str | None = None
217
+ ) -> dict[str, Any]: ...
218
+ def restore_session_context(self, continuity_data: dict[str, Any]) -> bool: ...
219
+
220
+ # Planning (from PlanningMixin)
221
+ def find_bottlenecks(self, top_n: int = 5) -> list[BottleneckDict]: ...
222
+ def get_parallel_work(self, max_agents: int = 5) -> dict[str, Any]: ...
223
+ def recommend_next_work(
224
+ self,
225
+ agent_count: int = 1,
226
+ include_reasons: bool = True,
227
+ ) -> list[WorkRecommendation]: ...
228
+ def assess_risks(self) -> RiskAssessmentDict: ...
229
+ def analyze_impact(self, node_id: str) -> ImpactAnalysisDict: ...
230
+ def get_work_queue(
231
+ self,
232
+ max_items: int = 10,
233
+ include_blocked: bool = False,
234
+ ) -> list[WorkQueueItem]: ...
235
+ def work_next(self) -> ActiveWorkItem | None: ...
236
+ def start_planning_spike(
237
+ self,
238
+ title: str,
239
+ questions: list[str] | None = None,
240
+ ) -> Any: ...
241
+ def create_track_from_plan(
242
+ self,
243
+ spike_id: str,
244
+ track_title: str | None = None,
245
+ ) -> TrackCreationResult: ...
246
+ def smart_plan(
247
+ self,
248
+ goal: str,
249
+ constraints: list[str] | None = None,
250
+ max_features: int = 10,
251
+ ) -> SmartPlanResult: ...
252
+ def plan_parallel_work(
253
+ self,
254
+ available_agents: int = 3,
255
+ work_items: list[str] | None = None,
256
+ ) -> ParallelPlanResult: ...
257
+ def aggregate_parallel_results(
258
+ self,
259
+ task_ids: list[str],
260
+ timeout_seconds: int = 300,
261
+ ) -> AggregateResultsDict: ...
262
+
263
+ # Session start info
264
+ def get_session_start_info(
265
+ self,
266
+ include_git_log: bool = True,
267
+ git_log_count: int = 5,
268
+ analytics_top_n: int = 3,
269
+ analytics_max_agents: int = 3,
270
+ ) -> SessionStartInfo: ...
271
+
272
+ # Active work item
273
+ def get_active_work_item(
274
+ self,
275
+ agent: str | None = None,
276
+ filter_by_agent: bool = False,
277
+ work_types: list[str] | None = None,
278
+ ) -> ActiveWorkItem | None: ...
279
+
280
+ # Operations
281
+ def start_server(
282
+ self,
283
+ port: int = 8080,
284
+ host: str = "localhost",
285
+ watch: bool = True,
286
+ auto_port: bool = False,
287
+ ) -> Any: ...
288
+ def stop_server(self, handle: Any) -> None: ...
289
+ def get_server_status(self, handle: Any | None = None) -> Any: ...
290
+ def install_hooks(self, use_copy: bool = False) -> Any: ...
291
+ def list_hooks(self) -> Any: ...
292
+ def validate_hook_config(self) -> Any: ...
293
+ def export_sessions(self, overwrite: bool = False) -> Any: ...
294
+ def rebuild_event_index(self) -> Any: ...
295
+ def query_events(
296
+ self,
297
+ session_id: str | None = None,
298
+ tool: str | None = None,
299
+ feature_id: str | None = None,
300
+ since: str | None = None,
301
+ limit: int | None = None,
302
+ ) -> Any: ...
303
+ def get_event_stats(self) -> Any: ...
304
+ def analyze_session(self, session_id: str) -> Any: ...
305
+ def analyze_project(self) -> Any: ...
306
+ def get_work_recommendations(self) -> Any: ...
307
+ def get_task_attribution(self, task_id: str) -> dict[str, Any]: ...
308
+ def get_subagent_work(self, session_id: str) -> dict[str, list[dict[str, Any]]]: ...
@@ -0,0 +1,120 @@
1
+ from __future__ import annotations
2
+
3
+ """
4
+ Discovery Logic for HtmlGraph SDK
5
+
6
+ Auto-discovers project root and .htmlgraph directory.
7
+ """
8
+
9
+
10
+ import os
11
+ from pathlib import Path
12
+
13
+ from htmlgraph.agent_detection import detect_agent_name
14
+
15
+ # Default directory name for HtmlGraph data
16
+ HTMLGRAPH_DIR = ".htmlgraph"
17
+
18
+
19
+ def find_project_root(start_path: Path | None = None) -> Path:
20
+ """
21
+ Find project root by searching for .htmlgraph directory.
22
+
23
+ Searches current directory and all parent directories.
24
+
25
+ Args:
26
+ start_path: Starting path for search (defaults to cwd)
27
+
28
+ Returns:
29
+ Path to directory containing .htmlgraph
30
+
31
+ Raises:
32
+ FileNotFoundError: If no .htmlgraph directory found
33
+ """
34
+ current = start_path or Path.cwd()
35
+
36
+ # Check current directory
37
+ if (current / HTMLGRAPH_DIR).exists():
38
+ return current
39
+
40
+ # Check parent directories
41
+ for parent in current.parents:
42
+ if (parent / HTMLGRAPH_DIR).exists():
43
+ return parent
44
+
45
+ # Not found
46
+ raise FileNotFoundError(
47
+ f"Could not find {HTMLGRAPH_DIR} directory in {current} or any parent directory"
48
+ )
49
+
50
+
51
+ def discover_htmlgraph_dir(start_path: Path | None = None) -> Path:
52
+ """
53
+ Auto-discover .htmlgraph directory.
54
+
55
+ Searches current directory and parents. If not found, returns
56
+ path to .htmlgraph in current directory (may not exist yet).
57
+
58
+ Args:
59
+ start_path: Starting path for search (defaults to cwd)
60
+
61
+ Returns:
62
+ Path to .htmlgraph directory
63
+ """
64
+ current = start_path or Path.cwd()
65
+
66
+ # Check current directory
67
+ if (current / HTMLGRAPH_DIR).exists():
68
+ return current / HTMLGRAPH_DIR
69
+
70
+ # Check parent directories
71
+ for parent in current.parents:
72
+ if (parent / HTMLGRAPH_DIR).exists():
73
+ return parent / HTMLGRAPH_DIR
74
+
75
+ # Default to current directory (may not exist yet)
76
+ return current / HTMLGRAPH_DIR
77
+
78
+
79
+ def auto_discover_agent() -> str:
80
+ """
81
+ Auto-discover agent identifier from environment.
82
+
83
+ Detection order:
84
+ 1. CLAUDE_AGENT_NAME environment variable
85
+ 2. detect_agent_name() from agent_detection module
86
+ 3. Raises ValueError if no valid agent found
87
+
88
+ Returns:
89
+ Agent identifier string
90
+
91
+ Raises:
92
+ ValueError: If agent cannot be detected
93
+ """
94
+ # Try environment variable first
95
+ agent = os.getenv("CLAUDE_AGENT_NAME")
96
+ if agent:
97
+ return agent
98
+
99
+ # Try automatic detection
100
+ detected = detect_agent_name()
101
+ if detected and detected != "cli":
102
+ # Only accept detected if it's not the default fallback
103
+ return detected
104
+
105
+ # No valid agent found - fail fast with helpful error message
106
+ raise ValueError(
107
+ "Agent identifier is required for work attribution. "
108
+ "Pass agent='name' to SDK() initialization. "
109
+ "Examples: SDK(agent='explorer'), SDK(agent='coder'), SDK(agent='tester')\n"
110
+ "Alternatively, set CLAUDE_AGENT_NAME environment variable.\n"
111
+ "Critical for: Work attribution, result retrieval, orchestrator tracking"
112
+ )
113
+
114
+
115
+ __all__ = [
116
+ "HTMLGRAPH_DIR",
117
+ "find_project_root",
118
+ "discover_htmlgraph_dir",
119
+ "auto_discover_agent",
120
+ ]
@@ -0,0 +1,12 @@
1
+ """
2
+ Help module for SDK - documentation and discoverability.
3
+
4
+ Provides:
5
+ - HelpMixin: Help system and discoverability
6
+ """
7
+
8
+ from htmlgraph.sdk.help.mixin import HelpMixin
9
+
10
+ __all__ = [
11
+ "HelpMixin",
12
+ ]