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.
Files changed (304) hide show
  1. htmlgraph/.htmlgraph/.session-warning-state.json +6 -0
  2. htmlgraph/.htmlgraph/agents.json +72 -0
  3. htmlgraph/.htmlgraph/htmlgraph.db +0 -0
  4. htmlgraph/__init__.py +51 -1
  5. htmlgraph/__init__.pyi +123 -0
  6. htmlgraph/agent_detection.py +26 -10
  7. htmlgraph/agent_registry.py +2 -1
  8. htmlgraph/analytics/__init__.py +8 -1
  9. htmlgraph/analytics/cli.py +86 -20
  10. htmlgraph/analytics/cost_analyzer.py +391 -0
  11. htmlgraph/analytics/cost_monitor.py +664 -0
  12. htmlgraph/analytics/cost_reporter.py +675 -0
  13. htmlgraph/analytics/cross_session.py +617 -0
  14. htmlgraph/analytics/dependency.py +10 -6
  15. htmlgraph/analytics/pattern_learning.py +771 -0
  16. htmlgraph/analytics/session_graph.py +707 -0
  17. htmlgraph/analytics/strategic/__init__.py +80 -0
  18. htmlgraph/analytics/strategic/cost_optimizer.py +611 -0
  19. htmlgraph/analytics/strategic/pattern_detector.py +876 -0
  20. htmlgraph/analytics/strategic/preference_manager.py +709 -0
  21. htmlgraph/analytics/strategic/suggestion_engine.py +747 -0
  22. htmlgraph/analytics/work_type.py +67 -27
  23. htmlgraph/analytics_index.py +53 -20
  24. htmlgraph/api/__init__.py +3 -0
  25. htmlgraph/api/cost_alerts_websocket.py +416 -0
  26. htmlgraph/api/main.py +2498 -0
  27. htmlgraph/api/static/htmx.min.js +1 -0
  28. htmlgraph/api/static/style-redesign.css +1344 -0
  29. htmlgraph/api/static/style.css +1079 -0
  30. htmlgraph/api/templates/dashboard-redesign.html +1366 -0
  31. htmlgraph/api/templates/dashboard.html +794 -0
  32. htmlgraph/api/templates/partials/activity-feed-hierarchical.html +326 -0
  33. htmlgraph/api/templates/partials/activity-feed.html +1100 -0
  34. htmlgraph/api/templates/partials/agents-redesign.html +317 -0
  35. htmlgraph/api/templates/partials/agents.html +317 -0
  36. htmlgraph/api/templates/partials/event-traces.html +373 -0
  37. htmlgraph/api/templates/partials/features-kanban-redesign.html +509 -0
  38. htmlgraph/api/templates/partials/features.html +578 -0
  39. htmlgraph/api/templates/partials/metrics-redesign.html +346 -0
  40. htmlgraph/api/templates/partials/metrics.html +346 -0
  41. htmlgraph/api/templates/partials/orchestration-redesign.html +443 -0
  42. htmlgraph/api/templates/partials/orchestration.html +198 -0
  43. htmlgraph/api/templates/partials/spawners.html +375 -0
  44. htmlgraph/api/templates/partials/work-items.html +613 -0
  45. htmlgraph/api/websocket.py +538 -0
  46. htmlgraph/archive/__init__.py +24 -0
  47. htmlgraph/archive/bloom.py +234 -0
  48. htmlgraph/archive/fts.py +297 -0
  49. htmlgraph/archive/manager.py +583 -0
  50. htmlgraph/archive/search.py +244 -0
  51. htmlgraph/atomic_ops.py +560 -0
  52. htmlgraph/attribute_index.py +2 -1
  53. htmlgraph/bounded_paths.py +539 -0
  54. htmlgraph/builders/base.py +57 -2
  55. htmlgraph/builders/bug.py +19 -3
  56. htmlgraph/builders/chore.py +19 -3
  57. htmlgraph/builders/epic.py +19 -3
  58. htmlgraph/builders/feature.py +27 -3
  59. htmlgraph/builders/insight.py +2 -1
  60. htmlgraph/builders/metric.py +2 -1
  61. htmlgraph/builders/pattern.py +2 -1
  62. htmlgraph/builders/phase.py +19 -3
  63. htmlgraph/builders/spike.py +29 -3
  64. htmlgraph/builders/track.py +42 -1
  65. htmlgraph/cigs/__init__.py +81 -0
  66. htmlgraph/cigs/autonomy.py +385 -0
  67. htmlgraph/cigs/cost.py +475 -0
  68. htmlgraph/cigs/messages_basic.py +472 -0
  69. htmlgraph/cigs/messaging.py +365 -0
  70. htmlgraph/cigs/models.py +771 -0
  71. htmlgraph/cigs/pattern_storage.py +427 -0
  72. htmlgraph/cigs/patterns.py +503 -0
  73. htmlgraph/cigs/posttool_analyzer.py +234 -0
  74. htmlgraph/cigs/reporter.py +818 -0
  75. htmlgraph/cigs/tracker.py +317 -0
  76. htmlgraph/cli/.htmlgraph/.session-warning-state.json +6 -0
  77. htmlgraph/cli/.htmlgraph/agents.json +72 -0
  78. htmlgraph/cli/.htmlgraph/htmlgraph.db +0 -0
  79. htmlgraph/cli/__init__.py +42 -0
  80. htmlgraph/cli/__main__.py +6 -0
  81. htmlgraph/cli/analytics.py +1424 -0
  82. htmlgraph/cli/base.py +685 -0
  83. htmlgraph/cli/constants.py +206 -0
  84. htmlgraph/cli/core.py +954 -0
  85. htmlgraph/cli/main.py +147 -0
  86. htmlgraph/cli/models.py +475 -0
  87. htmlgraph/cli/templates/__init__.py +1 -0
  88. htmlgraph/cli/templates/cost_dashboard.py +399 -0
  89. htmlgraph/cli/work/__init__.py +239 -0
  90. htmlgraph/cli/work/browse.py +115 -0
  91. htmlgraph/cli/work/features.py +568 -0
  92. htmlgraph/cli/work/orchestration.py +676 -0
  93. htmlgraph/cli/work/report.py +728 -0
  94. htmlgraph/cli/work/sessions.py +466 -0
  95. htmlgraph/cli/work/snapshot.py +559 -0
  96. htmlgraph/cli/work/tracks.py +486 -0
  97. htmlgraph/cli_commands/__init__.py +1 -0
  98. htmlgraph/cli_commands/feature.py +195 -0
  99. htmlgraph/cli_framework.py +115 -0
  100. htmlgraph/collections/__init__.py +2 -0
  101. htmlgraph/collections/base.py +197 -14
  102. htmlgraph/collections/bug.py +2 -1
  103. htmlgraph/collections/chore.py +2 -1
  104. htmlgraph/collections/epic.py +2 -1
  105. htmlgraph/collections/feature.py +2 -1
  106. htmlgraph/collections/insight.py +2 -1
  107. htmlgraph/collections/metric.py +2 -1
  108. htmlgraph/collections/pattern.py +2 -1
  109. htmlgraph/collections/phase.py +2 -1
  110. htmlgraph/collections/session.py +194 -0
  111. htmlgraph/collections/spike.py +13 -2
  112. htmlgraph/collections/task_delegation.py +241 -0
  113. htmlgraph/collections/todo.py +14 -1
  114. htmlgraph/collections/traces.py +487 -0
  115. htmlgraph/config/cost_models.json +56 -0
  116. htmlgraph/config.py +190 -0
  117. htmlgraph/context_analytics.py +2 -1
  118. htmlgraph/converter.py +116 -7
  119. htmlgraph/cost_analysis/__init__.py +5 -0
  120. htmlgraph/cost_analysis/analyzer.py +438 -0
  121. htmlgraph/dashboard.html +2246 -248
  122. htmlgraph/dashboard.html.backup +6592 -0
  123. htmlgraph/dashboard.html.bak +7181 -0
  124. htmlgraph/dashboard.html.bak2 +7231 -0
  125. htmlgraph/dashboard.html.bak3 +7232 -0
  126. htmlgraph/db/__init__.py +38 -0
  127. htmlgraph/db/queries.py +790 -0
  128. htmlgraph/db/schema.py +1788 -0
  129. htmlgraph/decorators.py +317 -0
  130. htmlgraph/dependency_models.py +2 -1
  131. htmlgraph/deploy.py +26 -27
  132. htmlgraph/docs/API_REFERENCE.md +841 -0
  133. htmlgraph/docs/HTTP_API.md +750 -0
  134. htmlgraph/docs/INTEGRATION_GUIDE.md +752 -0
  135. htmlgraph/docs/ORCHESTRATION_PATTERNS.md +717 -0
  136. htmlgraph/docs/README.md +532 -0
  137. htmlgraph/docs/__init__.py +77 -0
  138. htmlgraph/docs/docs_version.py +55 -0
  139. htmlgraph/docs/metadata.py +93 -0
  140. htmlgraph/docs/migrations.py +232 -0
  141. htmlgraph/docs/template_engine.py +143 -0
  142. htmlgraph/docs/templates/_sections/cli_reference.md.j2 +52 -0
  143. htmlgraph/docs/templates/_sections/core_concepts.md.j2 +29 -0
  144. htmlgraph/docs/templates/_sections/sdk_basics.md.j2 +69 -0
  145. htmlgraph/docs/templates/base_agents.md.j2 +78 -0
  146. htmlgraph/docs/templates/example_user_override.md.j2 +47 -0
  147. htmlgraph/docs/version_check.py +163 -0
  148. htmlgraph/edge_index.py +2 -1
  149. htmlgraph/error_handler.py +544 -0
  150. htmlgraph/event_log.py +86 -37
  151. htmlgraph/event_migration.py +2 -1
  152. htmlgraph/file_watcher.py +12 -8
  153. htmlgraph/find_api.py +2 -1
  154. htmlgraph/git_events.py +67 -9
  155. htmlgraph/hooks/.htmlgraph/.session-warning-state.json +6 -0
  156. htmlgraph/hooks/.htmlgraph/agents.json +72 -0
  157. htmlgraph/hooks/.htmlgraph/index.sqlite +0 -0
  158. htmlgraph/hooks/__init__.py +8 -0
  159. htmlgraph/hooks/bootstrap.py +169 -0
  160. htmlgraph/hooks/cigs_pretool_enforcer.py +354 -0
  161. htmlgraph/hooks/concurrent_sessions.py +208 -0
  162. htmlgraph/hooks/context.py +350 -0
  163. htmlgraph/hooks/drift_handler.py +525 -0
  164. htmlgraph/hooks/event_tracker.py +790 -99
  165. htmlgraph/hooks/git_commands.py +175 -0
  166. htmlgraph/hooks/installer.py +5 -1
  167. htmlgraph/hooks/orchestrator.py +327 -76
  168. htmlgraph/hooks/orchestrator_reflector.py +31 -4
  169. htmlgraph/hooks/post_tool_use_failure.py +32 -7
  170. htmlgraph/hooks/post_tool_use_handler.py +257 -0
  171. htmlgraph/hooks/posttooluse.py +92 -19
  172. htmlgraph/hooks/pretooluse.py +527 -7
  173. htmlgraph/hooks/prompt_analyzer.py +637 -0
  174. htmlgraph/hooks/session_handler.py +668 -0
  175. htmlgraph/hooks/session_summary.py +395 -0
  176. htmlgraph/hooks/state_manager.py +504 -0
  177. htmlgraph/hooks/subagent_detection.py +202 -0
  178. htmlgraph/hooks/subagent_stop.py +369 -0
  179. htmlgraph/hooks/task_enforcer.py +99 -4
  180. htmlgraph/hooks/validator.py +212 -91
  181. htmlgraph/ids.py +2 -1
  182. htmlgraph/learning.py +125 -100
  183. htmlgraph/mcp_server.py +2 -1
  184. htmlgraph/models.py +217 -18
  185. htmlgraph/operations/README.md +62 -0
  186. htmlgraph/operations/__init__.py +79 -0
  187. htmlgraph/operations/analytics.py +339 -0
  188. htmlgraph/operations/bootstrap.py +289 -0
  189. htmlgraph/operations/events.py +244 -0
  190. htmlgraph/operations/fastapi_server.py +231 -0
  191. htmlgraph/operations/hooks.py +350 -0
  192. htmlgraph/operations/initialization.py +597 -0
  193. htmlgraph/operations/initialization.py.backup +228 -0
  194. htmlgraph/operations/server.py +303 -0
  195. htmlgraph/orchestration/__init__.py +58 -0
  196. htmlgraph/orchestration/claude_launcher.py +179 -0
  197. htmlgraph/orchestration/command_builder.py +72 -0
  198. htmlgraph/orchestration/headless_spawner.py +281 -0
  199. htmlgraph/orchestration/live_events.py +377 -0
  200. htmlgraph/orchestration/model_selection.py +327 -0
  201. htmlgraph/orchestration/plugin_manager.py +140 -0
  202. htmlgraph/orchestration/prompts.py +137 -0
  203. htmlgraph/orchestration/spawner_event_tracker.py +383 -0
  204. htmlgraph/orchestration/spawners/__init__.py +16 -0
  205. htmlgraph/orchestration/spawners/base.py +194 -0
  206. htmlgraph/orchestration/spawners/claude.py +173 -0
  207. htmlgraph/orchestration/spawners/codex.py +435 -0
  208. htmlgraph/orchestration/spawners/copilot.py +294 -0
  209. htmlgraph/orchestration/spawners/gemini.py +471 -0
  210. htmlgraph/orchestration/subprocess_runner.py +36 -0
  211. htmlgraph/{orchestration.py → orchestration/task_coordination.py} +16 -8
  212. htmlgraph/orchestration.md +563 -0
  213. htmlgraph/orchestrator-system-prompt-optimized.txt +863 -0
  214. htmlgraph/orchestrator.py +2 -1
  215. htmlgraph/orchestrator_config.py +357 -0
  216. htmlgraph/orchestrator_mode.py +115 -4
  217. htmlgraph/parallel.py +2 -1
  218. htmlgraph/parser.py +86 -6
  219. htmlgraph/path_query.py +608 -0
  220. htmlgraph/pattern_matcher.py +636 -0
  221. htmlgraph/pydantic_models.py +476 -0
  222. htmlgraph/quality_gates.py +350 -0
  223. htmlgraph/query_builder.py +2 -1
  224. htmlgraph/query_composer.py +509 -0
  225. htmlgraph/reflection.py +443 -0
  226. htmlgraph/refs.py +344 -0
  227. htmlgraph/repo_hash.py +512 -0
  228. htmlgraph/repositories/__init__.py +292 -0
  229. htmlgraph/repositories/analytics_repository.py +455 -0
  230. htmlgraph/repositories/analytics_repository_standard.py +628 -0
  231. htmlgraph/repositories/feature_repository.py +581 -0
  232. htmlgraph/repositories/feature_repository_htmlfile.py +668 -0
  233. htmlgraph/repositories/feature_repository_memory.py +607 -0
  234. htmlgraph/repositories/feature_repository_sqlite.py +858 -0
  235. htmlgraph/repositories/filter_service.py +620 -0
  236. htmlgraph/repositories/filter_service_standard.py +445 -0
  237. htmlgraph/repositories/shared_cache.py +621 -0
  238. htmlgraph/repositories/shared_cache_memory.py +395 -0
  239. htmlgraph/repositories/track_repository.py +552 -0
  240. htmlgraph/repositories/track_repository_htmlfile.py +619 -0
  241. htmlgraph/repositories/track_repository_memory.py +508 -0
  242. htmlgraph/repositories/track_repository_sqlite.py +711 -0
  243. htmlgraph/sdk/__init__.py +398 -0
  244. htmlgraph/sdk/__init__.pyi +14 -0
  245. htmlgraph/sdk/analytics/__init__.py +19 -0
  246. htmlgraph/sdk/analytics/engine.py +155 -0
  247. htmlgraph/sdk/analytics/helpers.py +178 -0
  248. htmlgraph/sdk/analytics/registry.py +109 -0
  249. htmlgraph/sdk/base.py +484 -0
  250. htmlgraph/sdk/constants.py +216 -0
  251. htmlgraph/sdk/core.pyi +308 -0
  252. htmlgraph/sdk/discovery.py +120 -0
  253. htmlgraph/sdk/help/__init__.py +12 -0
  254. htmlgraph/sdk/help/mixin.py +699 -0
  255. htmlgraph/sdk/mixins/__init__.py +15 -0
  256. htmlgraph/sdk/mixins/attribution.py +113 -0
  257. htmlgraph/sdk/mixins/mixin.py +410 -0
  258. htmlgraph/sdk/operations/__init__.py +12 -0
  259. htmlgraph/sdk/operations/mixin.py +427 -0
  260. htmlgraph/sdk/orchestration/__init__.py +17 -0
  261. htmlgraph/sdk/orchestration/coordinator.py +203 -0
  262. htmlgraph/sdk/orchestration/spawner.py +204 -0
  263. htmlgraph/sdk/planning/__init__.py +19 -0
  264. htmlgraph/sdk/planning/bottlenecks.py +93 -0
  265. htmlgraph/sdk/planning/mixin.py +211 -0
  266. htmlgraph/sdk/planning/parallel.py +186 -0
  267. htmlgraph/sdk/planning/queue.py +210 -0
  268. htmlgraph/sdk/planning/recommendations.py +87 -0
  269. htmlgraph/sdk/planning/smart_planning.py +319 -0
  270. htmlgraph/sdk/session/__init__.py +19 -0
  271. htmlgraph/sdk/session/continuity.py +57 -0
  272. htmlgraph/sdk/session/handoff.py +110 -0
  273. htmlgraph/sdk/session/info.py +309 -0
  274. htmlgraph/sdk/session/manager.py +103 -0
  275. htmlgraph/sdk/strategic/__init__.py +26 -0
  276. htmlgraph/sdk/strategic/mixin.py +563 -0
  277. htmlgraph/server.py +295 -107
  278. htmlgraph/session_hooks.py +300 -0
  279. htmlgraph/session_manager.py +285 -3
  280. htmlgraph/session_registry.py +587 -0
  281. htmlgraph/session_state.py +436 -0
  282. htmlgraph/session_warning.py +2 -1
  283. htmlgraph/sessions/__init__.py +23 -0
  284. htmlgraph/sessions/handoff.py +756 -0
  285. htmlgraph/system_prompts.py +450 -0
  286. htmlgraph/templates/orchestration-view.html +350 -0
  287. htmlgraph/track_builder.py +33 -1
  288. htmlgraph/track_manager.py +38 -0
  289. htmlgraph/transcript.py +18 -5
  290. htmlgraph/validation.py +115 -0
  291. htmlgraph/watch.py +2 -1
  292. htmlgraph/work_type_utils.py +2 -1
  293. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/dashboard.html +2246 -248
  294. {htmlgraph-0.20.1.dist-info → htmlgraph-0.27.5.dist-info}/METADATA +95 -64
  295. htmlgraph-0.27.5.dist-info/RECORD +337 -0
  296. {htmlgraph-0.20.1.dist-info → htmlgraph-0.27.5.dist-info}/entry_points.txt +1 -1
  297. htmlgraph/cli.py +0 -4839
  298. htmlgraph/sdk.py +0 -2359
  299. htmlgraph-0.20.1.dist-info/RECORD +0 -118
  300. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/styles.css +0 -0
  301. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/AGENTS.md.template +0 -0
  302. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/CLAUDE.md.template +0 -0
  303. {htmlgraph-0.20.1.data → htmlgraph-0.27.5.data}/data/htmlgraph/templates/GEMINI.md.template +0 -0
  304. {htmlgraph-0.20.1.dist-info → htmlgraph-0.27.5.dist-info}/WHEEL +0 -0
@@ -0,0 +1,115 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import sys
5
+ from collections.abc import Iterable
6
+ from dataclasses import dataclass
7
+ from datetime import date, datetime
8
+ from typing import TYPE_CHECKING, Any, Protocol
9
+
10
+ from rich.console import Console
11
+
12
+ if TYPE_CHECKING:
13
+ from htmlgraph.sdk import SDK
14
+
15
+ _console = Console()
16
+
17
+
18
+ class CommandError(Exception):
19
+ """User-facing CLI error with an exit code."""
20
+
21
+ def __init__(self, message: str, exit_code: int = 1) -> None:
22
+ super().__init__(message)
23
+ self.exit_code = exit_code
24
+
25
+
26
+ @dataclass
27
+ class CommandResult:
28
+ data: Any = None
29
+ text: str | Iterable[str] | None = None
30
+ json_data: Any | None = None
31
+
32
+
33
+ class Formatter(Protocol):
34
+ def output(self, result: CommandResult) -> None: ...
35
+
36
+
37
+ def _serialize_json(value: Any) -> Any:
38
+ if value is None:
39
+ return None
40
+ if isinstance(value, (datetime, date)):
41
+ return value.isoformat()
42
+ if hasattr(value, "model_dump") and callable(getattr(value, "model_dump")):
43
+ return _serialize_json(value.model_dump())
44
+ if hasattr(value, "to_dict") and callable(getattr(value, "to_dict")):
45
+ return _serialize_json(value.to_dict())
46
+ if isinstance(value, dict):
47
+ return {key: _serialize_json(val) for key, val in value.items()}
48
+ if isinstance(value, (list, tuple, set)):
49
+ return [_serialize_json(item) for item in value]
50
+ return value
51
+
52
+
53
+ class JsonFormatter:
54
+ def output(self, result: CommandResult) -> None:
55
+ payload = result.json_data if result.json_data is not None else result.data
56
+ _console.print(json.dumps(_serialize_json(payload), indent=2))
57
+
58
+
59
+ class TextFormatter:
60
+ def output(self, result: CommandResult) -> None:
61
+ if result.text is None:
62
+ if result.data is not None:
63
+ _console.print(result.data)
64
+ return
65
+ if isinstance(result.text, str):
66
+ _console.print(result.text)
67
+ return
68
+ _console.print("\n".join(str(line) for line in result.text))
69
+
70
+
71
+ def get_formatter(format_name: str) -> Formatter:
72
+ if format_name == "json":
73
+ return JsonFormatter()
74
+ if format_name in ("text", "plain", ""):
75
+ return TextFormatter()
76
+ raise CommandError(f"Unknown output format '{format_name}'")
77
+
78
+
79
+ class BaseCommand:
80
+ def __init__(self) -> None:
81
+ self.graph_dir: str | None = None
82
+ self.agent: str | None = None
83
+ self._sdk: SDK | None = None
84
+
85
+ def validate(self) -> None:
86
+ return None
87
+
88
+ def execute(self) -> CommandResult:
89
+ raise NotImplementedError
90
+
91
+ def get_sdk(self) -> Any:
92
+ if self.graph_dir is None:
93
+ raise CommandError("Missing graph directory for command execution.")
94
+ if self._sdk is None:
95
+ from htmlgraph.sdk import SDK
96
+
97
+ self._sdk = SDK(directory=self.graph_dir, agent=self.agent)
98
+ return self._sdk
99
+
100
+ def run(self, *, graph_dir: str, agent: str | None, output_format: str) -> None:
101
+ self.graph_dir = graph_dir
102
+ self.agent = agent
103
+ try:
104
+ self.validate()
105
+ result = self.execute()
106
+ formatter = get_formatter(output_format)
107
+ formatter.output(result)
108
+ except CommandError as exc:
109
+ error_console = Console(file=sys.stderr)
110
+ error_console.print(f"[red]Error: {exc}[/red]")
111
+ sys.exit(exc.exit_code)
112
+ except ValueError as exc:
113
+ error_console = Console(file=sys.stderr)
114
+ error_console.print(f"[red]Error: {exc}[/red]")
115
+ sys.exit(1)
@@ -15,6 +15,7 @@ from htmlgraph.collections.metric import MetricCollection
15
15
  from htmlgraph.collections.pattern import PatternCollection
16
16
  from htmlgraph.collections.phase import PhaseCollection
17
17
  from htmlgraph.collections.spike import SpikeCollection
18
+ from htmlgraph.collections.task_delegation import TaskDelegationCollection
18
19
  from htmlgraph.collections.todo import TodoCollection
19
20
 
20
21
  __all__ = [
@@ -29,4 +30,5 @@ __all__ = [
29
30
  "InsightCollection",
30
31
  "MetricCollection",
31
32
  "TodoCollection",
33
+ "TaskDelegationCollection",
32
34
  ]
@@ -1,3 +1,9 @@
1
+ from __future__ import annotations
2
+
3
+ import logging
4
+
5
+ logger = logging.getLogger(__name__)
6
+
1
7
  """
2
8
  Base collection class for managing nodes.
3
9
 
@@ -5,7 +11,6 @@ Provides common collection functionality for all node types
5
11
  with lazy-loading, filtering, and batch operations.
6
12
  """
7
13
 
8
- from __future__ import annotations
9
14
 
10
15
  from collections.abc import Callable, Iterator
11
16
  from contextlib import contextmanager
@@ -69,9 +74,22 @@ class BaseCollection(Generic[CollectionT]):
69
74
  self._collection_name = collection_name or self._collection_name
70
75
  self._node_type = node_type or self._node_type
71
76
  self._graph: HtmlGraph | None = None # Lazy-loaded
77
+ self._ref_manager: Any = None # Set by SDK during initialization
72
78
 
73
79
  def _ensure_graph(self) -> HtmlGraph:
74
- """Get the graph for this collection, using SDK's shared instances where available."""
80
+ """
81
+ Get or initialize the graph for this collection.
82
+
83
+ Uses SDK's shared graph instances where available to avoid creating
84
+ multiple graph objects for the same collection. Creates a new instance
85
+ for unrecognized collections.
86
+
87
+ Returns:
88
+ HtmlGraph instance for this collection
89
+
90
+ Note:
91
+ This method is lazy - the graph is only loaded on first access.
92
+ """
75
93
  if self._graph is None:
76
94
  # Use SDK's shared graph instances to avoid multiple graph objects
77
95
  if self._collection_name == "features" and hasattr(self._sdk, "_graph"):
@@ -91,8 +109,72 @@ class BaseCollection(Generic[CollectionT]):
91
109
 
92
110
  return self._graph
93
111
 
112
+ def __getattribute__(self, name: str) -> Any:
113
+ """
114
+ Override attribute access to provide helpful error messages.
115
+
116
+ When an attribute doesn't exist, provides suggestions for common
117
+ mistakes and similar method names to improve discoverability.
118
+
119
+ Args:
120
+ name: Attribute name being accessed
121
+
122
+ Returns:
123
+ The requested attribute
124
+
125
+ Raises:
126
+ AttributeError: With helpful suggestions if attribute not found
127
+ """
128
+ try:
129
+ return object.__getattribute__(self, name)
130
+ except AttributeError as e:
131
+ # Get available methods
132
+ available = [m for m in dir(self) if not m.startswith("_")]
133
+
134
+ # Common mistakes mapping
135
+ common_mistakes = {
136
+ "mark_complete": "mark_done",
137
+ "complete": "Use complete(node_id) for single item or mark_done([ids]) for batch",
138
+ "finish": "mark_done",
139
+ "end": "mark_done",
140
+ "update_status": "edit() context manager or batch_update()",
141
+ "mark_as_done": "mark_done",
142
+ "set_done": "mark_done",
143
+ "complete_all": "mark_done",
144
+ }
145
+
146
+ suggestions = []
147
+ if name in common_mistakes:
148
+ suggestions.append(f"Did you mean: {common_mistakes[name]}")
149
+
150
+ # Find similar method names
151
+ similar = [
152
+ m
153
+ for m in available
154
+ if name.lower() in m.lower() or m.lower() in name.lower()
155
+ ]
156
+ if similar:
157
+ suggestions.append(f"Similar methods: {', '.join(similar[:5])}")
158
+
159
+ # Build helpful error message
160
+ error_msg = f"'{type(self).__name__}' has no attribute '{name}'."
161
+ if suggestions:
162
+ error_msg += "\n\n" + "\n".join(suggestions)
163
+ error_msg += f"\n\nAvailable methods: {', '.join(available[:15])}"
164
+ error_msg += "\n\nTip: Use sdk.help() to see all available operations."
165
+
166
+ raise AttributeError(error_msg) from e
167
+
94
168
  def __dir__(self) -> list[str]:
95
- """Return attributes with most useful ones first for discoverability."""
169
+ """
170
+ Return attributes with most useful ones first.
171
+
172
+ Orders attributes to show commonly-used methods first in auto-complete
173
+ and help() output, improving discoverability for new users.
174
+
175
+ Returns:
176
+ List of attribute names, ordered by priority then alphabetically
177
+ """
96
178
  priority = [
97
179
  # Creation and retrieval
98
180
  "create",
@@ -124,6 +206,39 @@ class BaseCollection(Generic[CollectionT]):
124
206
  # Return priority items first, then regular, then dunder
125
207
  return priority + regular + dunder
126
208
 
209
+ def set_ref_manager(self, ref_manager: Any) -> None:
210
+ """
211
+ Set the ref manager for this collection.
212
+
213
+ Called by SDK during initialization to enable short ref support.
214
+
215
+ Args:
216
+ ref_manager: RefManager instance from SDK
217
+ """
218
+ self._ref_manager = ref_manager
219
+
220
+ def get_ref(self, node_id: str) -> str | None:
221
+ """
222
+ Get short ref for a node in this collection.
223
+
224
+ Convenience method to get ref without accessing SDK directly.
225
+
226
+ Args:
227
+ node_id: Full node ID like "feat-a1b2c3d4"
228
+
229
+ Returns:
230
+ Short ref like "@f1", or None if ref manager not available
231
+
232
+ Example:
233
+ >>> feature = sdk.features.get("feat-abc123")
234
+ >>> ref = sdk.features.get_ref(feature.id)
235
+ >>> logger.info("%s", ref) # "@f1"
236
+ """
237
+ if self._ref_manager:
238
+ result = self._ref_manager.get_ref(node_id)
239
+ return cast(str | None, result)
240
+ return None
241
+
127
242
  def create(
128
243
  self, title: str, priority: str = "medium", status: str = "todo", **kwargs: Any
129
244
  ) -> Any:
@@ -356,7 +471,7 @@ class BaseCollection(Generic[CollectionT]):
356
471
 
357
472
  Example:
358
473
  >>> count = sdk.features.batch_delete(["feat-001", "feat-002", "feat-003"])
359
- >>> print(f"Deleted {count} features")
474
+ >>> logger.info(f"Deleted {count} features")
360
475
  """
361
476
  graph = self._ensure_graph()
362
477
  return cast(int, graph.batch_delete(node_ids))
@@ -418,7 +533,7 @@ class BaseCollection(Generic[CollectionT]):
418
533
 
419
534
  return count
420
535
 
421
- def mark_done(self, node_ids: list[str]) -> int:
536
+ def mark_done(self, node_ids: list[str]) -> dict[str, Any]:
422
537
  """
423
538
  Batch mark nodes as done.
424
539
 
@@ -426,12 +541,55 @@ class BaseCollection(Generic[CollectionT]):
426
541
  node_ids: List of node IDs to mark as done
427
542
 
428
543
  Returns:
429
- Number of nodes updated
544
+ Dict with 'success_count', 'failed_ids', and 'warnings'
430
545
 
431
546
  Example:
432
- >>> sdk.features.mark_done(["feat-001", "feat-002"])
547
+ >>> result = sdk.features.mark_done(["feat-001", "feat-002"])
548
+ >>> logger.info(f"Completed {result['success_count']} of {len(node_ids)}")
549
+ >>> if result['failed_ids']:
550
+ ... logger.info(f"Failed: {result['failed_ids']}")
433
551
  """
434
- return self.batch_update(node_ids, {"status": "done"})
552
+ graph = self._ensure_graph()
553
+ results: dict[str, Any] = {"success_count": 0, "failed_ids": [], "warnings": []}
554
+
555
+ for node_id in node_ids:
556
+ try:
557
+ node = graph.get(node_id)
558
+ if not node:
559
+ results["failed_ids"].append(node_id)
560
+ results["warnings"].append(f"Node {node_id} not found")
561
+ continue
562
+
563
+ node.status = "done"
564
+ node.updated = datetime.now()
565
+ graph.update(node)
566
+ results["success_count"] += 1
567
+
568
+ # Log completion event to SQLite
569
+ try:
570
+ self._sdk._log_event(
571
+ event_type="tool_call",
572
+ tool_name="SDK.mark_done",
573
+ input_summary=f"Mark {self._node_type} done: {node_id}",
574
+ output_summary=f"Marked {node_id} as done",
575
+ context={
576
+ "collection": self._collection_name,
577
+ "node_id": node_id,
578
+ "node_type": self._node_type,
579
+ "title": node.title,
580
+ },
581
+ cost_tokens=25,
582
+ )
583
+ except Exception as e:
584
+ import logging
585
+
586
+ logging.debug(f"Event logging failed for mark_done: {e}")
587
+
588
+ except Exception as e:
589
+ results["failed_ids"].append(node_id)
590
+ results["warnings"].append(f"Failed to mark {node_id}: {str(e)}")
591
+
592
+ return results
435
593
 
436
594
  def assign(self, node_ids: list[str], agent: str) -> int:
437
595
  """
@@ -454,13 +612,15 @@ class BaseCollection(Generic[CollectionT]):
454
612
  """
455
613
  Start working on a node (feature/bug/etc).
456
614
 
457
- Delegates to SessionManager to:
615
+ Delegates to SessionManager if available for smart tracking:
458
616
  1. Check WIP limits
459
617
  2. Ensure not claimed by others
460
618
  3. Auto-claim for agent
461
619
  4. Link to active session
462
620
  5. Log 'FeatureStart' event
463
621
 
622
+ Falls back to simple status update if SessionManager not available.
623
+
464
624
  Args:
465
625
  node_id: Node ID to start
466
626
  agent: Agent ID (defaults to SDK agent)
@@ -470,6 +630,10 @@ class BaseCollection(Generic[CollectionT]):
470
630
 
471
631
  Raises:
472
632
  NodeNotFoundError: If node not found
633
+
634
+ Example:
635
+ >>> sdk.features.start('feat-abc123')
636
+ >>> sdk.features.start('feat-xyz', agent='claude')
473
637
  """
474
638
  agent = agent or self._sdk.agent
475
639
 
@@ -502,14 +666,17 @@ class BaseCollection(Generic[CollectionT]):
502
666
  transcript_id: str | None = None,
503
667
  ) -> Node | None:
504
668
  """
505
- Complete a node.
669
+ Mark a node as complete.
506
670
 
507
- Delegates to SessionManager to:
508
- 1. Update status
671
+ Delegates to SessionManager if available for event logging and
672
+ transcript linking:
673
+ 1. Update status to 'done'
509
674
  2. Log 'FeatureComplete' event
510
675
  3. Release claim (optional behavior)
511
676
  4. Link transcript if provided (for parallel agent tracking)
512
677
 
678
+ Falls back to simple status update if SessionManager not available.
679
+
513
680
  Args:
514
681
  node_id: Node ID to complete
515
682
  agent: Agent ID (defaults to SDK agent)
@@ -521,6 +688,10 @@ class BaseCollection(Generic[CollectionT]):
521
688
 
522
689
  Raises:
523
690
  NodeNotFoundError: If node not found
691
+
692
+ Example:
693
+ >>> sdk.features.complete('feat-abc123')
694
+ >>> sdk.features.complete('feat-xyz', agent='claude', transcript_id='trans-123')
524
695
  """
525
696
  agent = agent or self._sdk.agent
526
697
 
@@ -551,11 +722,13 @@ class BaseCollection(Generic[CollectionT]):
551
722
  """
552
723
  Claim a node for an agent.
553
724
 
554
- Delegates to SessionManager to:
725
+ Delegates to SessionManager if available for ownership tracking:
555
726
  1. Check ownership rules
556
727
  2. Update assignment
557
728
  3. Log 'FeatureClaim' event
558
729
 
730
+ Falls back to simple assignment if SessionManager not available.
731
+
559
732
  Args:
560
733
  node_id: Node ID to claim
561
734
  agent: Agent ID (defaults to SDK agent)
@@ -567,6 +740,10 @@ class BaseCollection(Generic[CollectionT]):
567
740
  ValueError: If agent not provided and SDK has no agent
568
741
  NodeNotFoundError: If node not found
569
742
  ClaimConflictError: If node already claimed by different agent
743
+
744
+ Example:
745
+ >>> sdk.features.claim('feat-abc123')
746
+ >>> sdk.features.claim('feat-xyz', agent='claude')
570
747
  """
571
748
  agent = agent or self._sdk.agent
572
749
  if not agent:
@@ -601,11 +778,13 @@ class BaseCollection(Generic[CollectionT]):
601
778
  """
602
779
  Release a claimed node.
603
780
 
604
- Delegates to SessionManager to:
781
+ Delegates to SessionManager if available for ownership tracking:
605
782
  1. Verify ownership
606
783
  2. Clear assignment
607
784
  3. Log 'FeatureRelease' event
608
785
 
786
+ Falls back to simple assignment clearing if SessionManager not available.
787
+
609
788
  Args:
610
789
  node_id: Node ID to release
611
790
  agent: Agent ID (defaults to SDK agent)
@@ -615,6 +794,10 @@ class BaseCollection(Generic[CollectionT]):
615
794
 
616
795
  Raises:
617
796
  NodeNotFoundError: If node not found
797
+
798
+ Example:
799
+ >>> sdk.features.release('feat-abc123')
800
+ >>> sdk.features.release('feat-xyz', agent='claude')
618
801
  """
619
802
  # SessionManager.release_feature requires an agent to verify ownership
620
803
  agent = agent or self._sdk.agent
@@ -1,10 +1,11 @@
1
+ from __future__ import annotations
2
+
1
3
  """
2
4
  Bug collection for managing bug report work items.
3
5
 
4
6
  Extends BaseCollection with bug-specific builder support.
5
7
  """
6
8
 
7
- from __future__ import annotations
8
9
 
9
10
  from typing import TYPE_CHECKING
10
11
 
@@ -1,10 +1,11 @@
1
+ from __future__ import annotations
2
+
1
3
  """
2
4
  Chore collection for managing maintenance task work items.
3
5
 
4
6
  Extends BaseCollection with chore-specific builder support.
5
7
  """
6
8
 
7
- from __future__ import annotations
8
9
 
9
10
  from typing import TYPE_CHECKING
10
11
 
@@ -1,10 +1,11 @@
1
+ from __future__ import annotations
2
+
1
3
  """
2
4
  Epic collection for managing large body of work items.
3
5
 
4
6
  Extends BaseCollection with epic-specific builder support.
5
7
  """
6
8
 
7
- from __future__ import annotations
8
9
 
9
10
  from typing import TYPE_CHECKING
10
11
 
@@ -1,10 +1,11 @@
1
+ from __future__ import annotations
2
+
1
3
  """
2
4
  Feature collection for managing feature work items.
3
5
 
4
6
  Extends BaseCollection with feature-specific builder support.
5
7
  """
6
8
 
7
- from __future__ import annotations
8
9
 
9
10
  from typing import TYPE_CHECKING
10
11
 
@@ -1,10 +1,11 @@
1
+ from __future__ import annotations
2
+
1
3
  """
2
4
  SessionInsight collection for managing session insights.
3
5
 
4
6
  Extends BaseCollection with insight-specific query methods.
5
7
  """
6
8
 
7
- from __future__ import annotations
8
9
 
9
10
  from typing import TYPE_CHECKING
10
11
 
@@ -1,10 +1,11 @@
1
+ from __future__ import annotations
2
+
1
3
  """
2
4
  AggregatedMetric collection for managing aggregated metrics.
3
5
 
4
6
  Extends BaseCollection with metric-specific query methods.
5
7
  """
6
8
 
7
- from __future__ import annotations
8
9
 
9
10
  from typing import TYPE_CHECKING
10
11
 
@@ -1,10 +1,11 @@
1
+ from __future__ import annotations
2
+
1
3
  """
2
4
  Pattern collection for managing workflow patterns.
3
5
 
4
6
  Extends BaseCollection with pattern-specific query methods.
5
7
  """
6
8
 
7
- from __future__ import annotations
8
9
 
9
10
  from typing import TYPE_CHECKING
10
11
 
@@ -1,10 +1,11 @@
1
+ from __future__ import annotations
2
+
1
3
  """
2
4
  Phase collection for managing project phase work items.
3
5
 
4
6
  Extends BaseCollection with phase-specific builder support.
5
7
  """
6
8
 
7
- from __future__ import annotations
8
9
 
9
10
  from typing import TYPE_CHECKING
10
11