htmlgraph 0.9.3__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.
- htmlgraph/.htmlgraph/.session-warning-state.json +6 -0
- htmlgraph/.htmlgraph/agents.json +72 -0
- htmlgraph/.htmlgraph/htmlgraph.db +0 -0
- htmlgraph/__init__.py +173 -17
- htmlgraph/__init__.pyi +123 -0
- htmlgraph/agent_detection.py +127 -0
- htmlgraph/agent_registry.py +45 -30
- htmlgraph/agents.py +160 -107
- htmlgraph/analytics/__init__.py +9 -2
- htmlgraph/analytics/cli.py +190 -51
- htmlgraph/analytics/cost_analyzer.py +391 -0
- htmlgraph/analytics/cost_monitor.py +664 -0
- htmlgraph/analytics/cost_reporter.py +675 -0
- htmlgraph/analytics/cross_session.py +617 -0
- htmlgraph/analytics/dependency.py +192 -100
- htmlgraph/analytics/pattern_learning.py +771 -0
- htmlgraph/analytics/session_graph.py +707 -0
- htmlgraph/analytics/strategic/__init__.py +80 -0
- htmlgraph/analytics/strategic/cost_optimizer.py +611 -0
- htmlgraph/analytics/strategic/pattern_detector.py +876 -0
- htmlgraph/analytics/strategic/preference_manager.py +709 -0
- htmlgraph/analytics/strategic/suggestion_engine.py +747 -0
- htmlgraph/analytics/work_type.py +190 -14
- htmlgraph/analytics_index.py +135 -51
- htmlgraph/api/__init__.py +3 -0
- htmlgraph/api/cost_alerts_websocket.py +416 -0
- htmlgraph/api/main.py +2498 -0
- htmlgraph/api/static/htmx.min.js +1 -0
- htmlgraph/api/static/style-redesign.css +1344 -0
- htmlgraph/api/static/style.css +1079 -0
- htmlgraph/api/templates/dashboard-redesign.html +1366 -0
- htmlgraph/api/templates/dashboard.html +794 -0
- htmlgraph/api/templates/partials/activity-feed-hierarchical.html +326 -0
- htmlgraph/api/templates/partials/activity-feed.html +1100 -0
- htmlgraph/api/templates/partials/agents-redesign.html +317 -0
- htmlgraph/api/templates/partials/agents.html +317 -0
- htmlgraph/api/templates/partials/event-traces.html +373 -0
- htmlgraph/api/templates/partials/features-kanban-redesign.html +509 -0
- htmlgraph/api/templates/partials/features.html +578 -0
- htmlgraph/api/templates/partials/metrics-redesign.html +346 -0
- htmlgraph/api/templates/partials/metrics.html +346 -0
- htmlgraph/api/templates/partials/orchestration-redesign.html +443 -0
- htmlgraph/api/templates/partials/orchestration.html +198 -0
- htmlgraph/api/templates/partials/spawners.html +375 -0
- htmlgraph/api/templates/partials/work-items.html +613 -0
- htmlgraph/api/websocket.py +538 -0
- htmlgraph/archive/__init__.py +24 -0
- htmlgraph/archive/bloom.py +234 -0
- htmlgraph/archive/fts.py +297 -0
- htmlgraph/archive/manager.py +583 -0
- htmlgraph/archive/search.py +244 -0
- htmlgraph/atomic_ops.py +560 -0
- htmlgraph/attribute_index.py +208 -0
- htmlgraph/bounded_paths.py +539 -0
- htmlgraph/builders/__init__.py +14 -0
- htmlgraph/builders/base.py +118 -29
- htmlgraph/builders/bug.py +150 -0
- htmlgraph/builders/chore.py +119 -0
- htmlgraph/builders/epic.py +150 -0
- htmlgraph/builders/feature.py +31 -6
- htmlgraph/builders/insight.py +195 -0
- htmlgraph/builders/metric.py +217 -0
- htmlgraph/builders/pattern.py +202 -0
- htmlgraph/builders/phase.py +162 -0
- htmlgraph/builders/spike.py +52 -19
- htmlgraph/builders/track.py +148 -72
- htmlgraph/cigs/__init__.py +81 -0
- htmlgraph/cigs/autonomy.py +385 -0
- htmlgraph/cigs/cost.py +475 -0
- htmlgraph/cigs/messages_basic.py +472 -0
- htmlgraph/cigs/messaging.py +365 -0
- htmlgraph/cigs/models.py +771 -0
- htmlgraph/cigs/pattern_storage.py +427 -0
- htmlgraph/cigs/patterns.py +503 -0
- htmlgraph/cigs/posttool_analyzer.py +234 -0
- htmlgraph/cigs/reporter.py +818 -0
- htmlgraph/cigs/tracker.py +317 -0
- htmlgraph/cli/.htmlgraph/.session-warning-state.json +6 -0
- htmlgraph/cli/.htmlgraph/agents.json +72 -0
- htmlgraph/cli/.htmlgraph/htmlgraph.db +0 -0
- htmlgraph/cli/__init__.py +42 -0
- htmlgraph/cli/__main__.py +6 -0
- htmlgraph/cli/analytics.py +1424 -0
- htmlgraph/cli/base.py +685 -0
- htmlgraph/cli/constants.py +206 -0
- htmlgraph/cli/core.py +954 -0
- htmlgraph/cli/main.py +147 -0
- htmlgraph/cli/models.py +475 -0
- htmlgraph/cli/templates/__init__.py +1 -0
- htmlgraph/cli/templates/cost_dashboard.py +399 -0
- htmlgraph/cli/work/__init__.py +239 -0
- htmlgraph/cli/work/browse.py +115 -0
- htmlgraph/cli/work/features.py +568 -0
- htmlgraph/cli/work/orchestration.py +676 -0
- htmlgraph/cli/work/report.py +728 -0
- htmlgraph/cli/work/sessions.py +466 -0
- htmlgraph/cli/work/snapshot.py +559 -0
- htmlgraph/cli/work/tracks.py +486 -0
- htmlgraph/cli_commands/__init__.py +1 -0
- htmlgraph/cli_commands/feature.py +195 -0
- htmlgraph/cli_framework.py +115 -0
- htmlgraph/collections/__init__.py +18 -0
- htmlgraph/collections/base.py +415 -98
- htmlgraph/collections/bug.py +53 -0
- htmlgraph/collections/chore.py +53 -0
- htmlgraph/collections/epic.py +53 -0
- htmlgraph/collections/feature.py +12 -26
- htmlgraph/collections/insight.py +100 -0
- htmlgraph/collections/metric.py +92 -0
- htmlgraph/collections/pattern.py +97 -0
- htmlgraph/collections/phase.py +53 -0
- htmlgraph/collections/session.py +194 -0
- htmlgraph/collections/spike.py +56 -16
- htmlgraph/collections/task_delegation.py +241 -0
- htmlgraph/collections/todo.py +511 -0
- htmlgraph/collections/traces.py +487 -0
- htmlgraph/config/cost_models.json +56 -0
- htmlgraph/config.py +190 -0
- htmlgraph/context_analytics.py +344 -0
- htmlgraph/converter.py +216 -28
- htmlgraph/cost_analysis/__init__.py +5 -0
- htmlgraph/cost_analysis/analyzer.py +438 -0
- htmlgraph/dashboard.html +2406 -307
- htmlgraph/dashboard.html.backup +6592 -0
- htmlgraph/dashboard.html.bak +7181 -0
- htmlgraph/dashboard.html.bak2 +7231 -0
- htmlgraph/dashboard.html.bak3 +7232 -0
- htmlgraph/db/__init__.py +38 -0
- htmlgraph/db/queries.py +790 -0
- htmlgraph/db/schema.py +1788 -0
- htmlgraph/decorators.py +317 -0
- htmlgraph/dependency_models.py +19 -2
- htmlgraph/deploy.py +142 -125
- htmlgraph/deployment_models.py +474 -0
- htmlgraph/docs/API_REFERENCE.md +841 -0
- htmlgraph/docs/HTTP_API.md +750 -0
- htmlgraph/docs/INTEGRATION_GUIDE.md +752 -0
- htmlgraph/docs/ORCHESTRATION_PATTERNS.md +717 -0
- htmlgraph/docs/README.md +532 -0
- 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 +163 -0
- htmlgraph/edge_index.py +182 -27
- htmlgraph/error_handler.py +544 -0
- htmlgraph/event_log.py +100 -52
- htmlgraph/event_migration.py +13 -4
- htmlgraph/exceptions.py +49 -0
- htmlgraph/file_watcher.py +101 -28
- htmlgraph/find_api.py +75 -63
- htmlgraph/git_events.py +145 -63
- htmlgraph/graph.py +1122 -106
- htmlgraph/hooks/.htmlgraph/.session-warning-state.json +6 -0
- htmlgraph/hooks/.htmlgraph/agents.json +72 -0
- htmlgraph/hooks/.htmlgraph/index.sqlite +0 -0
- htmlgraph/hooks/__init__.py +45 -0
- htmlgraph/hooks/bootstrap.py +169 -0
- htmlgraph/hooks/cigs_pretool_enforcer.py +354 -0
- htmlgraph/hooks/concurrent_sessions.py +208 -0
- htmlgraph/hooks/context.py +350 -0
- htmlgraph/hooks/drift_handler.py +525 -0
- htmlgraph/hooks/event_tracker.py +1314 -0
- htmlgraph/hooks/git_commands.py +175 -0
- htmlgraph/hooks/hooks-config.example.json +12 -0
- htmlgraph/hooks/installer.py +343 -0
- htmlgraph/hooks/orchestrator.py +674 -0
- htmlgraph/hooks/orchestrator_reflector.py +223 -0
- htmlgraph/hooks/post-checkout.sh +28 -0
- htmlgraph/hooks/post-commit.sh +24 -0
- htmlgraph/hooks/post-merge.sh +26 -0
- htmlgraph/hooks/post_tool_use_failure.py +273 -0
- htmlgraph/hooks/post_tool_use_handler.py +257 -0
- htmlgraph/hooks/posttooluse.py +408 -0
- htmlgraph/hooks/pre-commit.sh +94 -0
- htmlgraph/hooks/pre-push.sh +28 -0
- htmlgraph/hooks/pretooluse.py +819 -0
- htmlgraph/hooks/prompt_analyzer.py +637 -0
- htmlgraph/hooks/session_handler.py +668 -0
- htmlgraph/hooks/session_summary.py +395 -0
- htmlgraph/hooks/state_manager.py +504 -0
- htmlgraph/hooks/subagent_detection.py +202 -0
- htmlgraph/hooks/subagent_stop.py +369 -0
- htmlgraph/hooks/task_enforcer.py +255 -0
- htmlgraph/hooks/task_validator.py +177 -0
- htmlgraph/hooks/validator.py +628 -0
- htmlgraph/ids.py +41 -27
- htmlgraph/index.d.ts +286 -0
- htmlgraph/learning.py +767 -0
- htmlgraph/mcp_server.py +69 -23
- htmlgraph/models.py +1586 -87
- htmlgraph/operations/README.md +62 -0
- htmlgraph/operations/__init__.py +79 -0
- htmlgraph/operations/analytics.py +339 -0
- htmlgraph/operations/bootstrap.py +289 -0
- htmlgraph/operations/events.py +244 -0
- htmlgraph/operations/fastapi_server.py +231 -0
- htmlgraph/operations/hooks.py +350 -0
- htmlgraph/operations/initialization.py +597 -0
- htmlgraph/operations/initialization.py.backup +228 -0
- htmlgraph/operations/server.py +303 -0
- htmlgraph/orchestration/__init__.py +58 -0
- htmlgraph/orchestration/claude_launcher.py +179 -0
- htmlgraph/orchestration/command_builder.py +72 -0
- htmlgraph/orchestration/headless_spawner.py +281 -0
- htmlgraph/orchestration/live_events.py +377 -0
- htmlgraph/orchestration/model_selection.py +327 -0
- htmlgraph/orchestration/plugin_manager.py +140 -0
- htmlgraph/orchestration/prompts.py +137 -0
- htmlgraph/orchestration/spawner_event_tracker.py +383 -0
- htmlgraph/orchestration/spawners/__init__.py +16 -0
- htmlgraph/orchestration/spawners/base.py +194 -0
- htmlgraph/orchestration/spawners/claude.py +173 -0
- htmlgraph/orchestration/spawners/codex.py +435 -0
- htmlgraph/orchestration/spawners/copilot.py +294 -0
- htmlgraph/orchestration/spawners/gemini.py +471 -0
- htmlgraph/orchestration/subprocess_runner.py +36 -0
- htmlgraph/orchestration/task_coordination.py +343 -0
- htmlgraph/orchestration.md +563 -0
- htmlgraph/orchestrator-system-prompt-optimized.txt +863 -0
- htmlgraph/orchestrator.py +669 -0
- htmlgraph/orchestrator_config.py +357 -0
- htmlgraph/orchestrator_mode.py +328 -0
- htmlgraph/orchestrator_validator.py +133 -0
- htmlgraph/parallel.py +646 -0
- htmlgraph/parser.py +160 -35
- htmlgraph/path_query.py +608 -0
- htmlgraph/pattern_matcher.py +636 -0
- htmlgraph/planning.py +147 -52
- htmlgraph/pydantic_models.py +476 -0
- htmlgraph/quality_gates.py +350 -0
- htmlgraph/query_builder.py +109 -72
- htmlgraph/query_composer.py +509 -0
- htmlgraph/reflection.py +443 -0
- htmlgraph/refs.py +344 -0
- htmlgraph/repo_hash.py +512 -0
- htmlgraph/repositories/__init__.py +292 -0
- htmlgraph/repositories/analytics_repository.py +455 -0
- htmlgraph/repositories/analytics_repository_standard.py +628 -0
- htmlgraph/repositories/feature_repository.py +581 -0
- htmlgraph/repositories/feature_repository_htmlfile.py +668 -0
- htmlgraph/repositories/feature_repository_memory.py +607 -0
- htmlgraph/repositories/feature_repository_sqlite.py +858 -0
- htmlgraph/repositories/filter_service.py +620 -0
- htmlgraph/repositories/filter_service_standard.py +445 -0
- htmlgraph/repositories/shared_cache.py +621 -0
- htmlgraph/repositories/shared_cache_memory.py +395 -0
- htmlgraph/repositories/track_repository.py +552 -0
- htmlgraph/repositories/track_repository_htmlfile.py +619 -0
- htmlgraph/repositories/track_repository_memory.py +508 -0
- htmlgraph/repositories/track_repository_sqlite.py +711 -0
- htmlgraph/routing.py +8 -19
- htmlgraph/scripts/deploy.py +1 -2
- htmlgraph/sdk/__init__.py +398 -0
- htmlgraph/sdk/__init__.pyi +14 -0
- htmlgraph/sdk/analytics/__init__.py +19 -0
- htmlgraph/sdk/analytics/engine.py +155 -0
- htmlgraph/sdk/analytics/helpers.py +178 -0
- htmlgraph/sdk/analytics/registry.py +109 -0
- htmlgraph/sdk/base.py +484 -0
- htmlgraph/sdk/constants.py +216 -0
- htmlgraph/sdk/core.pyi +308 -0
- htmlgraph/sdk/discovery.py +120 -0
- htmlgraph/sdk/help/__init__.py +12 -0
- htmlgraph/sdk/help/mixin.py +699 -0
- htmlgraph/sdk/mixins/__init__.py +15 -0
- htmlgraph/sdk/mixins/attribution.py +113 -0
- htmlgraph/sdk/mixins/mixin.py +410 -0
- htmlgraph/sdk/operations/__init__.py +12 -0
- htmlgraph/sdk/operations/mixin.py +427 -0
- htmlgraph/sdk/orchestration/__init__.py +17 -0
- htmlgraph/sdk/orchestration/coordinator.py +203 -0
- htmlgraph/sdk/orchestration/spawner.py +204 -0
- htmlgraph/sdk/planning/__init__.py +19 -0
- htmlgraph/sdk/planning/bottlenecks.py +93 -0
- htmlgraph/sdk/planning/mixin.py +211 -0
- htmlgraph/sdk/planning/parallel.py +186 -0
- htmlgraph/sdk/planning/queue.py +210 -0
- htmlgraph/sdk/planning/recommendations.py +87 -0
- htmlgraph/sdk/planning/smart_planning.py +319 -0
- htmlgraph/sdk/session/__init__.py +19 -0
- htmlgraph/sdk/session/continuity.py +57 -0
- htmlgraph/sdk/session/handoff.py +110 -0
- htmlgraph/sdk/session/info.py +309 -0
- htmlgraph/sdk/session/manager.py +103 -0
- htmlgraph/sdk/strategic/__init__.py +26 -0
- htmlgraph/sdk/strategic/mixin.py +563 -0
- htmlgraph/server.py +685 -180
- htmlgraph/services/__init__.py +10 -0
- htmlgraph/services/claiming.py +199 -0
- htmlgraph/session_hooks.py +300 -0
- htmlgraph/session_manager.py +1392 -175
- htmlgraph/session_registry.py +587 -0
- htmlgraph/session_state.py +436 -0
- htmlgraph/session_warning.py +201 -0
- htmlgraph/sessions/__init__.py +23 -0
- htmlgraph/sessions/handoff.py +756 -0
- htmlgraph/setup.py +34 -17
- htmlgraph/spike_index.py +143 -0
- htmlgraph/sync_docs.py +12 -15
- htmlgraph/system_prompts.py +450 -0
- htmlgraph/templates/AGENTS.md.template +366 -0
- htmlgraph/templates/CLAUDE.md.template +97 -0
- htmlgraph/templates/GEMINI.md.template +87 -0
- htmlgraph/templates/orchestration-view.html +350 -0
- htmlgraph/track_builder.py +146 -15
- htmlgraph/track_manager.py +69 -21
- htmlgraph/transcript.py +890 -0
- htmlgraph/transcript_analytics.py +699 -0
- htmlgraph/types.py +323 -0
- htmlgraph/validation.py +115 -0
- htmlgraph/watch.py +8 -5
- htmlgraph/work_type_utils.py +3 -2
- {htmlgraph-0.9.3.data → htmlgraph-0.27.5.data}/data/htmlgraph/dashboard.html +2406 -307
- htmlgraph-0.27.5.data/data/htmlgraph/templates/AGENTS.md.template +366 -0
- htmlgraph-0.27.5.data/data/htmlgraph/templates/CLAUDE.md.template +97 -0
- htmlgraph-0.27.5.data/data/htmlgraph/templates/GEMINI.md.template +87 -0
- {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/METADATA +97 -64
- htmlgraph-0.27.5.dist-info/RECORD +337 -0
- {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/entry_points.txt +1 -1
- htmlgraph/cli.py +0 -2688
- htmlgraph/sdk.py +0 -709
- htmlgraph-0.9.3.dist-info/RECORD +0 -61
- {htmlgraph-0.9.3.data → htmlgraph-0.27.5.data}/data/htmlgraph/styles.css +0 -0
- {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/WHEEL +0 -0
htmlgraph/sdk/base.py
ADDED
|
@@ -0,0 +1,484 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Base SDK Core Class - Initialization and Core Properties
|
|
5
|
+
|
|
6
|
+
Extracted from sdk.py to reduce file size and improve modularity.
|
|
7
|
+
Contains the core SDK initialization logic and essential properties.
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
import os
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
from typing import TYPE_CHECKING, Any, cast
|
|
14
|
+
|
|
15
|
+
if TYPE_CHECKING:
|
|
16
|
+
from htmlgraph import SDK
|
|
17
|
+
|
|
18
|
+
from htmlgraph.agent_detection import detect_agent_name
|
|
19
|
+
from htmlgraph.agents import AgentInterface
|
|
20
|
+
from htmlgraph.analytics import Analytics, CrossSessionAnalytics, DependencyAnalytics
|
|
21
|
+
from htmlgraph.collections import (
|
|
22
|
+
BaseCollection,
|
|
23
|
+
BugCollection,
|
|
24
|
+
ChoreCollection,
|
|
25
|
+
EpicCollection,
|
|
26
|
+
FeatureCollection,
|
|
27
|
+
PhaseCollection,
|
|
28
|
+
SpikeCollection,
|
|
29
|
+
TaskDelegationCollection,
|
|
30
|
+
TodoCollection,
|
|
31
|
+
)
|
|
32
|
+
from htmlgraph.collections.insight import InsightCollection
|
|
33
|
+
from htmlgraph.collections.metric import MetricCollection
|
|
34
|
+
from htmlgraph.collections.pattern import PatternCollection
|
|
35
|
+
from htmlgraph.collections.session import SessionCollection
|
|
36
|
+
from htmlgraph.context_analytics import ContextAnalytics
|
|
37
|
+
from htmlgraph.db.schema import HtmlGraphDB
|
|
38
|
+
from htmlgraph.graph import HtmlGraph
|
|
39
|
+
from htmlgraph.session_manager import SessionManager
|
|
40
|
+
from htmlgraph.session_warning import check_and_show_warning
|
|
41
|
+
from htmlgraph.system_prompts import SystemPromptManager
|
|
42
|
+
from htmlgraph.track_builder import TrackCollection
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class BaseSDK:
|
|
46
|
+
"""
|
|
47
|
+
Core SDK class with initialization logic and essential properties.
|
|
48
|
+
|
|
49
|
+
This class handles:
|
|
50
|
+
- SDK initialization and auto-discovery
|
|
51
|
+
- Database and graph initialization
|
|
52
|
+
- Collection setup and configuration
|
|
53
|
+
- Lazy-loaded properties (orchestrator, system_prompts)
|
|
54
|
+
- Core utility methods (_log_event, _ensure_session_exists)
|
|
55
|
+
|
|
56
|
+
Subclasses add domain-specific methods (analytics, planning, orchestration).
|
|
57
|
+
"""
|
|
58
|
+
|
|
59
|
+
def __init__(
|
|
60
|
+
self,
|
|
61
|
+
directory: Path | str | None = None,
|
|
62
|
+
agent: str | None = None,
|
|
63
|
+
parent_session: str | None = None,
|
|
64
|
+
db_path: str | None = None,
|
|
65
|
+
):
|
|
66
|
+
"""
|
|
67
|
+
Initialize SDK.
|
|
68
|
+
|
|
69
|
+
Args:
|
|
70
|
+
directory: Path to .htmlgraph directory (auto-discovered if not provided)
|
|
71
|
+
agent: REQUIRED - Agent identifier for operations.
|
|
72
|
+
Used to attribute work items (features, spikes, bugs, etc) to the agent.
|
|
73
|
+
Examples: agent='explorer', agent='coder', agent='tester'
|
|
74
|
+
Critical for: Work attribution, result retrieval, orchestrator tracking
|
|
75
|
+
Falls back to: CLAUDE_AGENT_NAME env var, then detect_agent_name()
|
|
76
|
+
Raises ValueError if not provided and cannot be detected
|
|
77
|
+
parent_session: Parent session ID to log activities to (for nested contexts)
|
|
78
|
+
db_path: Path to SQLite database file (optional, defaults to ~/.htmlgraph/htmlgraph.db)
|
|
79
|
+
"""
|
|
80
|
+
if directory is None:
|
|
81
|
+
directory = self._discover_htmlgraph()
|
|
82
|
+
|
|
83
|
+
if agent is None:
|
|
84
|
+
# Try environment variable fallback
|
|
85
|
+
agent = os.getenv("CLAUDE_AGENT_NAME")
|
|
86
|
+
|
|
87
|
+
if agent is None:
|
|
88
|
+
# Try automatic detection
|
|
89
|
+
detected = detect_agent_name()
|
|
90
|
+
if detected and detected != "cli":
|
|
91
|
+
# Only accept detected if it's not the default fallback
|
|
92
|
+
agent = detected
|
|
93
|
+
else:
|
|
94
|
+
# No valid agent found - fail fast with helpful error message
|
|
95
|
+
raise ValueError(
|
|
96
|
+
"Agent identifier is required for work attribution. "
|
|
97
|
+
"Pass agent='name' to SDK() initialization. "
|
|
98
|
+
"Examples: SDK(agent='explorer'), SDK(agent='coder'), SDK(agent='tester')\n"
|
|
99
|
+
"Alternatively, set CLAUDE_AGENT_NAME environment variable.\n"
|
|
100
|
+
"Critical for: Work attribution, result retrieval, orchestrator tracking"
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
self._directory = Path(directory)
|
|
104
|
+
self._agent_id = agent
|
|
105
|
+
self._parent_session = parent_session or os.getenv("HTMLGRAPH_PARENT_SESSION")
|
|
106
|
+
|
|
107
|
+
# Initialize SQLite database (Phase 2)
|
|
108
|
+
self._db = HtmlGraphDB(
|
|
109
|
+
db_path or str(Path.home() / ".htmlgraph" / "htmlgraph.db")
|
|
110
|
+
)
|
|
111
|
+
self._db.connect()
|
|
112
|
+
self._db.create_tables()
|
|
113
|
+
|
|
114
|
+
# Initialize underlying HtmlGraphs first (for backward compatibility and sharing)
|
|
115
|
+
# These are shared with SessionManager to avoid double-loading features
|
|
116
|
+
self._graph = HtmlGraph(self._directory / "features")
|
|
117
|
+
self._bugs_graph = HtmlGraph(self._directory / "bugs")
|
|
118
|
+
|
|
119
|
+
# Initialize SessionManager with shared graph instances to avoid double-loading
|
|
120
|
+
self.session_manager = SessionManager(
|
|
121
|
+
self._directory,
|
|
122
|
+
features_graph=self._graph,
|
|
123
|
+
bugs_graph=self._bugs_graph,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
# Agent interface (for backward compatibility)
|
|
127
|
+
self._agent_interface = AgentInterface(
|
|
128
|
+
self._directory / "features", agent_id=agent
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Cast self to SDK for type checking - BaseSDK is only used via SDK subclass
|
|
132
|
+
sdk_self = cast("SDK", self)
|
|
133
|
+
|
|
134
|
+
# Collection interfaces - all work item types (all with builder support)
|
|
135
|
+
self.features = FeatureCollection(sdk_self)
|
|
136
|
+
self.bugs = BugCollection(sdk_self)
|
|
137
|
+
self.chores = ChoreCollection(sdk_self)
|
|
138
|
+
self.spikes = SpikeCollection(sdk_self)
|
|
139
|
+
self.epics = EpicCollection(sdk_self)
|
|
140
|
+
self.phases = PhaseCollection(sdk_self)
|
|
141
|
+
|
|
142
|
+
# Non-work collections
|
|
143
|
+
self.sessions: SessionCollection = SessionCollection(sdk_self)
|
|
144
|
+
self.tracks: TrackCollection = TrackCollection(
|
|
145
|
+
sdk_self
|
|
146
|
+
) # Use specialized collection with builder support
|
|
147
|
+
self.agents: BaseCollection[Any] = BaseCollection(sdk_self, "agents", "agent")
|
|
148
|
+
|
|
149
|
+
# Learning collections (Active Learning Persistence)
|
|
150
|
+
self.patterns = PatternCollection(sdk_self)
|
|
151
|
+
self.insights = InsightCollection(sdk_self)
|
|
152
|
+
self.metrics = MetricCollection(sdk_self)
|
|
153
|
+
|
|
154
|
+
# Todo collection (persistent task tracking)
|
|
155
|
+
self.todos = TodoCollection(sdk_self)
|
|
156
|
+
|
|
157
|
+
# Task delegation collection (observability for spawned agents)
|
|
158
|
+
self.task_delegations = TaskDelegationCollection(sdk_self)
|
|
159
|
+
|
|
160
|
+
# Create learning directories if needed
|
|
161
|
+
(self._directory / "patterns").mkdir(exist_ok=True)
|
|
162
|
+
(self._directory / "insights").mkdir(exist_ok=True)
|
|
163
|
+
(self._directory / "metrics").mkdir(exist_ok=True)
|
|
164
|
+
(self._directory / "todos").mkdir(exist_ok=True)
|
|
165
|
+
(self._directory / "task-delegations").mkdir(exist_ok=True)
|
|
166
|
+
|
|
167
|
+
# Initialize RefManager and set on all collections
|
|
168
|
+
from htmlgraph.refs import RefManager
|
|
169
|
+
|
|
170
|
+
self.refs = RefManager(self._directory)
|
|
171
|
+
|
|
172
|
+
# Set ref manager on all work item collections
|
|
173
|
+
self.features.set_ref_manager(self.refs)
|
|
174
|
+
self.bugs.set_ref_manager(self.refs)
|
|
175
|
+
self.chores.set_ref_manager(self.refs)
|
|
176
|
+
self.spikes.set_ref_manager(self.refs)
|
|
177
|
+
self.epics.set_ref_manager(self.refs)
|
|
178
|
+
self.phases.set_ref_manager(self.refs)
|
|
179
|
+
self.tracks.set_ref_manager(self.refs)
|
|
180
|
+
self.todos.set_ref_manager(self.refs)
|
|
181
|
+
|
|
182
|
+
# Analytics interface (Phase 2: Work Type Analytics)
|
|
183
|
+
self.analytics = Analytics(sdk_self)
|
|
184
|
+
|
|
185
|
+
# Dependency analytics interface (Advanced graph analytics)
|
|
186
|
+
self.dep_analytics = DependencyAnalytics(self._graph)
|
|
187
|
+
|
|
188
|
+
# Cross-session analytics interface (Git commit-based analytics)
|
|
189
|
+
self.cross_session_analytics = CrossSessionAnalytics(sdk_self)
|
|
190
|
+
|
|
191
|
+
# Context analytics interface (Context usage tracking)
|
|
192
|
+
self.context = ContextAnalytics(sdk_self)
|
|
193
|
+
|
|
194
|
+
# Pattern learning interface (Phase 2: Behavior Pattern Learning)
|
|
195
|
+
from htmlgraph.analytics.pattern_learning import PatternLearner
|
|
196
|
+
|
|
197
|
+
self.pattern_learning = PatternLearner(self._directory)
|
|
198
|
+
|
|
199
|
+
# Lazy-loaded orchestrator for subagent management
|
|
200
|
+
self._orchestrator: Any = None
|
|
201
|
+
|
|
202
|
+
# System prompt manager (lazy-loaded)
|
|
203
|
+
self._system_prompts: SystemPromptManager | None = None
|
|
204
|
+
|
|
205
|
+
# Session warning system (workaround for Claude Code hook bug #10373)
|
|
206
|
+
# Shows orchestrator instructions on first SDK usage per session
|
|
207
|
+
self._session_warning = check_and_show_warning(
|
|
208
|
+
self._directory,
|
|
209
|
+
agent=self._agent_id,
|
|
210
|
+
session_id=None, # Will be set by session manager if available
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
@staticmethod
|
|
214
|
+
def _discover_htmlgraph() -> Path:
|
|
215
|
+
"""
|
|
216
|
+
Auto-discover .htmlgraph directory.
|
|
217
|
+
|
|
218
|
+
Searches current directory and parents.
|
|
219
|
+
"""
|
|
220
|
+
current = Path.cwd()
|
|
221
|
+
|
|
222
|
+
# Check current directory
|
|
223
|
+
if (current / ".htmlgraph").exists():
|
|
224
|
+
return current / ".htmlgraph"
|
|
225
|
+
|
|
226
|
+
# Check parent directories
|
|
227
|
+
for parent in current.parents:
|
|
228
|
+
if (parent / ".htmlgraph").exists():
|
|
229
|
+
return parent / ".htmlgraph"
|
|
230
|
+
|
|
231
|
+
# Default to current directory
|
|
232
|
+
return current / ".htmlgraph"
|
|
233
|
+
|
|
234
|
+
@property
|
|
235
|
+
def agent(self) -> str | None:
|
|
236
|
+
"""Get current agent ID."""
|
|
237
|
+
return self._agent_id
|
|
238
|
+
|
|
239
|
+
@property
|
|
240
|
+
def system_prompts(self) -> SystemPromptManager:
|
|
241
|
+
"""
|
|
242
|
+
Access system prompt management.
|
|
243
|
+
|
|
244
|
+
Provides methods to:
|
|
245
|
+
- Get active prompt (project override OR plugin default)
|
|
246
|
+
- Create/delete project-level overrides
|
|
247
|
+
- Validate token counts
|
|
248
|
+
- Get prompt statistics
|
|
249
|
+
|
|
250
|
+
Lazy-loaded on first access.
|
|
251
|
+
|
|
252
|
+
Returns:
|
|
253
|
+
SystemPromptManager instance
|
|
254
|
+
|
|
255
|
+
Example:
|
|
256
|
+
>>> sdk = SDK(agent="claude")
|
|
257
|
+
|
|
258
|
+
# Get active prompt
|
|
259
|
+
>>> prompt = sdk.system_prompts.get_active()
|
|
260
|
+
|
|
261
|
+
# Create project override
|
|
262
|
+
>>> sdk.system_prompts.create("## Custom prompt\\n...")
|
|
263
|
+
|
|
264
|
+
# Validate token count
|
|
265
|
+
>>> result = sdk.system_prompts.validate()
|
|
266
|
+
>>> print(result['message'])
|
|
267
|
+
|
|
268
|
+
# Get statistics
|
|
269
|
+
>>> stats = sdk.system_prompts.get_stats()
|
|
270
|
+
>>> print(f"Source: {stats['source']}")
|
|
271
|
+
"""
|
|
272
|
+
if self._system_prompts is None:
|
|
273
|
+
self._system_prompts = SystemPromptManager(self._directory)
|
|
274
|
+
return self._system_prompts
|
|
275
|
+
|
|
276
|
+
def dismiss_session_warning(self) -> bool:
|
|
277
|
+
"""
|
|
278
|
+
Dismiss the session warning after reading it.
|
|
279
|
+
|
|
280
|
+
IMPORTANT: Call this as your FIRST action after seeing the orchestrator
|
|
281
|
+
warning. This confirms you've read the instructions.
|
|
282
|
+
|
|
283
|
+
Returns:
|
|
284
|
+
True if warning was dismissed, False if already dismissed
|
|
285
|
+
|
|
286
|
+
Example:
|
|
287
|
+
sdk = SDK(agent="claude")
|
|
288
|
+
# Warning shown automatically...
|
|
289
|
+
|
|
290
|
+
# First action: dismiss to confirm you read it
|
|
291
|
+
sdk.dismiss_session_warning()
|
|
292
|
+
|
|
293
|
+
# Now proceed with orchestration
|
|
294
|
+
sdk.spawn_coder(feature_id="feat-123", ...)
|
|
295
|
+
"""
|
|
296
|
+
if self._session_warning:
|
|
297
|
+
return self._session_warning.dismiss(
|
|
298
|
+
agent=self._agent_id,
|
|
299
|
+
session_id=None,
|
|
300
|
+
)
|
|
301
|
+
return False
|
|
302
|
+
|
|
303
|
+
def get_warning_status(self) -> dict[str, Any]:
|
|
304
|
+
"""
|
|
305
|
+
Get current session warning status.
|
|
306
|
+
|
|
307
|
+
Returns:
|
|
308
|
+
Dict with dismissed status, timestamp, and show count
|
|
309
|
+
"""
|
|
310
|
+
if self._session_warning:
|
|
311
|
+
return self._session_warning.get_status()
|
|
312
|
+
return {"dismissed": True, "show_count": 0}
|
|
313
|
+
|
|
314
|
+
def db(self) -> HtmlGraphDB:
|
|
315
|
+
"""
|
|
316
|
+
Get the SQLite database instance.
|
|
317
|
+
|
|
318
|
+
Returns:
|
|
319
|
+
HtmlGraphDB instance for executing queries
|
|
320
|
+
|
|
321
|
+
Example:
|
|
322
|
+
>>> sdk = SDK(agent="claude")
|
|
323
|
+
>>> db = sdk.db()
|
|
324
|
+
>>> events = db.get_session_events("sess-123")
|
|
325
|
+
>>> features = db.get_features_by_status("todo")
|
|
326
|
+
"""
|
|
327
|
+
return self._db
|
|
328
|
+
|
|
329
|
+
def query(self, sql: str, params: tuple = ()) -> list[dict[str, Any]]:
|
|
330
|
+
"""
|
|
331
|
+
Execute a raw SQL query on the SQLite database.
|
|
332
|
+
|
|
333
|
+
Args:
|
|
334
|
+
sql: SQL query string
|
|
335
|
+
params: Query parameters (for safe parameterized queries)
|
|
336
|
+
|
|
337
|
+
Returns:
|
|
338
|
+
List of result dictionaries
|
|
339
|
+
|
|
340
|
+
Example:
|
|
341
|
+
>>> sdk = SDK(agent="claude")
|
|
342
|
+
>>> results = sdk.query(
|
|
343
|
+
... "SELECT * FROM features WHERE status = ? AND priority = ?",
|
|
344
|
+
... ("todo", "high")
|
|
345
|
+
... )
|
|
346
|
+
>>> for row in results:
|
|
347
|
+
... print(row["title"])
|
|
348
|
+
"""
|
|
349
|
+
if not self._db.connection:
|
|
350
|
+
self._db.connect()
|
|
351
|
+
|
|
352
|
+
cursor = self._db.connection.cursor() # type: ignore[union-attr]
|
|
353
|
+
cursor.execute(sql, params)
|
|
354
|
+
rows = cursor.fetchall()
|
|
355
|
+
return [dict(row) for row in rows]
|
|
356
|
+
|
|
357
|
+
def execute_query_builder(
|
|
358
|
+
self, sql: str, params: tuple = ()
|
|
359
|
+
) -> list[dict[str, Any]]:
|
|
360
|
+
"""
|
|
361
|
+
Execute a query using the Queries builder.
|
|
362
|
+
|
|
363
|
+
Args:
|
|
364
|
+
sql: SQL query from Queries builder
|
|
365
|
+
params: Parameters from Queries builder
|
|
366
|
+
|
|
367
|
+
Returns:
|
|
368
|
+
List of result dictionaries
|
|
369
|
+
|
|
370
|
+
Example:
|
|
371
|
+
>>> sdk = SDK(agent="claude")
|
|
372
|
+
>>> sql, params = Queries.get_features_by_status("todo", limit=5)
|
|
373
|
+
>>> results = sdk.execute_query_builder(sql, params)
|
|
374
|
+
"""
|
|
375
|
+
return self.query(sql, params)
|
|
376
|
+
|
|
377
|
+
def _log_event(
|
|
378
|
+
self,
|
|
379
|
+
event_type: str,
|
|
380
|
+
tool_name: str | None = None,
|
|
381
|
+
input_summary: str | None = None,
|
|
382
|
+
output_summary: str | None = None,
|
|
383
|
+
context: dict[str, Any] | None = None,
|
|
384
|
+
cost_tokens: int = 0,
|
|
385
|
+
) -> bool:
|
|
386
|
+
"""
|
|
387
|
+
Log an event to the SQLite database with parent-child linking.
|
|
388
|
+
|
|
389
|
+
Internal method used by collections to track operations.
|
|
390
|
+
Automatically creates a session if one doesn't exist.
|
|
391
|
+
Reads parent event ID from HTMLGRAPH_PARENT_ACTIVITY env var for hierarchical tracking.
|
|
392
|
+
|
|
393
|
+
Args:
|
|
394
|
+
event_type: Type of event (tool_call, completion, error, etc.)
|
|
395
|
+
tool_name: Tool that was called
|
|
396
|
+
input_summary: Summary of input
|
|
397
|
+
output_summary: Summary of output
|
|
398
|
+
context: Additional context metadata
|
|
399
|
+
cost_tokens: Token cost estimate
|
|
400
|
+
|
|
401
|
+
Returns:
|
|
402
|
+
True if logged successfully, False otherwise
|
|
403
|
+
|
|
404
|
+
Example (internal use):
|
|
405
|
+
>>> sdk._log_event(
|
|
406
|
+
... event_type="tool_call",
|
|
407
|
+
... tool_name="Edit",
|
|
408
|
+
... input_summary="Edit file.py",
|
|
409
|
+
... cost_tokens=100
|
|
410
|
+
... )
|
|
411
|
+
"""
|
|
412
|
+
from uuid import uuid4
|
|
413
|
+
|
|
414
|
+
event_id = f"evt-{uuid4().hex[:12]}"
|
|
415
|
+
session_id = self._parent_session or "cli-session"
|
|
416
|
+
|
|
417
|
+
# Read parent event ID from environment variable for hierarchical linking
|
|
418
|
+
parent_event_id = os.getenv("HTMLGRAPH_PARENT_ACTIVITY")
|
|
419
|
+
|
|
420
|
+
# Ensure session exists before logging event
|
|
421
|
+
try:
|
|
422
|
+
self._ensure_session_exists(session_id, parent_event_id=parent_event_id)
|
|
423
|
+
except Exception as e:
|
|
424
|
+
import logging
|
|
425
|
+
|
|
426
|
+
logging.debug(f"Failed to ensure session exists: {e}")
|
|
427
|
+
# Continue anyway - session creation failure shouldn't block event logging
|
|
428
|
+
|
|
429
|
+
return self._db.insert_event(
|
|
430
|
+
event_id=event_id,
|
|
431
|
+
agent_id=self._agent_id,
|
|
432
|
+
event_type=event_type,
|
|
433
|
+
session_id=session_id,
|
|
434
|
+
tool_name=tool_name,
|
|
435
|
+
input_summary=input_summary,
|
|
436
|
+
output_summary=output_summary,
|
|
437
|
+
context=context,
|
|
438
|
+
parent_event_id=parent_event_id,
|
|
439
|
+
cost_tokens=cost_tokens,
|
|
440
|
+
)
|
|
441
|
+
|
|
442
|
+
def _ensure_session_exists(
|
|
443
|
+
self, session_id: str, parent_event_id: str | None = None
|
|
444
|
+
) -> None:
|
|
445
|
+
"""
|
|
446
|
+
Create a session record if it doesn't exist.
|
|
447
|
+
|
|
448
|
+
Args:
|
|
449
|
+
session_id: Session ID to ensure exists
|
|
450
|
+
parent_event_id: Event that spawned this session (optional)
|
|
451
|
+
"""
|
|
452
|
+
if not self._db.connection:
|
|
453
|
+
self._db.connect()
|
|
454
|
+
|
|
455
|
+
cursor = self._db.connection.cursor() # type: ignore[union-attr]
|
|
456
|
+
cursor.execute(
|
|
457
|
+
"SELECT COUNT(*) FROM sessions WHERE session_id = ?", (session_id,)
|
|
458
|
+
)
|
|
459
|
+
exists = cursor.fetchone()[0] > 0
|
|
460
|
+
|
|
461
|
+
if not exists:
|
|
462
|
+
# Create session record
|
|
463
|
+
self._db.insert_session(
|
|
464
|
+
session_id=session_id,
|
|
465
|
+
agent_assigned=self._agent_id,
|
|
466
|
+
is_subagent=self._parent_session is not None,
|
|
467
|
+
parent_session_id=self._parent_session,
|
|
468
|
+
parent_event_id=parent_event_id,
|
|
469
|
+
)
|
|
470
|
+
|
|
471
|
+
def reload(self) -> None:
|
|
472
|
+
"""Reload all data from disk."""
|
|
473
|
+
self._graph.reload()
|
|
474
|
+
self._agent_interface.reload()
|
|
475
|
+
# SessionManager reloads implicitly on access via its converters/graphs
|
|
476
|
+
|
|
477
|
+
def summary(self, max_items: int = 10) -> str:
|
|
478
|
+
"""
|
|
479
|
+
Get project summary.
|
|
480
|
+
|
|
481
|
+
Returns:
|
|
482
|
+
Compact overview for AI agent orientation
|
|
483
|
+
"""
|
|
484
|
+
return self._agent_interface.get_summary(max_items)
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
SDK Constants and Settings
|
|
5
|
+
|
|
6
|
+
Centralized configuration for the HtmlGraph SDK using Pydantic.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any
|
|
12
|
+
|
|
13
|
+
try:
|
|
14
|
+
from pydantic import Field
|
|
15
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
16
|
+
|
|
17
|
+
_PYDANTIC_AVAILABLE = True
|
|
18
|
+
except ImportError:
|
|
19
|
+
# Fallback if pydantic-settings not available
|
|
20
|
+
_PYDANTIC_AVAILABLE = False
|
|
21
|
+
BaseSettings = object # type: ignore
|
|
22
|
+
|
|
23
|
+
def Field(**kwargs: Any) -> None: # type: ignore[misc,no-redef] # noqa: N802
|
|
24
|
+
"""Fallback Field for environments without pydantic-settings."""
|
|
25
|
+
return None
|
|
26
|
+
|
|
27
|
+
SettingsConfigDict = dict # type: ignore
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
if _PYDANTIC_AVAILABLE:
|
|
31
|
+
|
|
32
|
+
class SDKSettings(BaseSettings):
|
|
33
|
+
"""
|
|
34
|
+
HtmlGraph SDK Configuration.
|
|
35
|
+
|
|
36
|
+
Uses Pydantic Settings for configuration from environment variables,
|
|
37
|
+
.env files, and direct instantiation.
|
|
38
|
+
|
|
39
|
+
Environment variables are prefixed with HTMLGRAPH_ (e.g., HTMLGRAPH_PROJECT_ROOT).
|
|
40
|
+
"""
|
|
41
|
+
|
|
42
|
+
# Core paths
|
|
43
|
+
project_root: Path = Field(default_factory=Path.cwd)
|
|
44
|
+
htmlgraph_dir_name: str = ".htmlgraph"
|
|
45
|
+
|
|
46
|
+
# Collection directories (relative to .htmlgraph)
|
|
47
|
+
features_dir: str = "features"
|
|
48
|
+
bugs_dir: str = "bugs"
|
|
49
|
+
chores_dir: str = "chores"
|
|
50
|
+
spikes_dir: str = "spikes"
|
|
51
|
+
epics_dir: str = "epics"
|
|
52
|
+
phases_dir: str = "phases"
|
|
53
|
+
sessions_dir: str = "sessions"
|
|
54
|
+
tracks_dir: str = "tracks"
|
|
55
|
+
agents_dir: str = "agents"
|
|
56
|
+
patterns_dir: str = "patterns"
|
|
57
|
+
insights_dir: str = "insights"
|
|
58
|
+
metrics_dir: str = "metrics"
|
|
59
|
+
todos_dir: str = "todos"
|
|
60
|
+
task_delegations_dir: str = "task-delegations"
|
|
61
|
+
archives_dir: str = "archives"
|
|
62
|
+
|
|
63
|
+
# Database
|
|
64
|
+
database_filename: str = "htmlgraph.db"
|
|
65
|
+
analytics_cache_filename: str = "index.sqlite"
|
|
66
|
+
|
|
67
|
+
# Session management
|
|
68
|
+
max_sessions: int = 100
|
|
69
|
+
session_retention_days: int = 30
|
|
70
|
+
auto_archive_sessions: bool = True
|
|
71
|
+
|
|
72
|
+
# Performance
|
|
73
|
+
max_query_results: int = 1000
|
|
74
|
+
cache_enabled: bool = True
|
|
75
|
+
cache_ttl_seconds: int = 3600
|
|
76
|
+
|
|
77
|
+
# Logging
|
|
78
|
+
log_level: str = "INFO"
|
|
79
|
+
|
|
80
|
+
# Agent detection
|
|
81
|
+
agent_env_var: str = "CLAUDE_AGENT_NAME"
|
|
82
|
+
parent_session_env_var: str = "HTMLGRAPH_PARENT_SESSION"
|
|
83
|
+
|
|
84
|
+
model_config = SettingsConfigDict(
|
|
85
|
+
env_prefix="HTMLGRAPH_",
|
|
86
|
+
env_file=".env",
|
|
87
|
+
case_sensitive=False,
|
|
88
|
+
extra="ignore",
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
def get_htmlgraph_dir(self: SDKSettings) -> Path: # type: ignore[misc]
|
|
92
|
+
"""Get the .htmlgraph directory path."""
|
|
93
|
+
return Path(self.project_root) / self.htmlgraph_dir_name # type: ignore[no-any-return]
|
|
94
|
+
|
|
95
|
+
def get_collection_dir(self: SDKSettings, collection: str) -> Path:
|
|
96
|
+
"""
|
|
97
|
+
Get the directory path for a specific collection.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
collection: Collection name (e.g., "features", "bugs", "spikes")
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
Path to collection directory
|
|
104
|
+
"""
|
|
105
|
+
collection_attr = f"{collection}_dir"
|
|
106
|
+
if hasattr(self, collection_attr):
|
|
107
|
+
dir_name = getattr(self, collection_attr)
|
|
108
|
+
return Path(self.get_htmlgraph_dir()) / str(dir_name)
|
|
109
|
+
raise ValueError(f"Unknown collection: {collection}")
|
|
110
|
+
|
|
111
|
+
def get_database_path(self: SDKSettings) -> Path: # type: ignore[misc]
|
|
112
|
+
"""Get the unified database path."""
|
|
113
|
+
return Path(self.get_htmlgraph_dir()) / self.database_filename # type: ignore[no-any-return]
|
|
114
|
+
|
|
115
|
+
def get_analytics_cache_path(self: SDKSettings) -> Path: # type: ignore[misc]
|
|
116
|
+
"""Get the analytics cache database path."""
|
|
117
|
+
return Path(self.get_htmlgraph_dir()) / self.analytics_cache_filename # type: ignore[no-any-return]
|
|
118
|
+
|
|
119
|
+
def ensure_directories(self: SDKSettings) -> None: # type: ignore[misc]
|
|
120
|
+
"""Create all collection directories if they don't exist."""
|
|
121
|
+
htmlgraph_dir = self.get_htmlgraph_dir()
|
|
122
|
+
htmlgraph_dir.mkdir(parents=True, exist_ok=True)
|
|
123
|
+
|
|
124
|
+
# Create all collection directories
|
|
125
|
+
for collection in [
|
|
126
|
+
"features",
|
|
127
|
+
"bugs",
|
|
128
|
+
"chores",
|
|
129
|
+
"spikes",
|
|
130
|
+
"epics",
|
|
131
|
+
"phases",
|
|
132
|
+
"sessions",
|
|
133
|
+
"tracks",
|
|
134
|
+
"agents",
|
|
135
|
+
"patterns",
|
|
136
|
+
"insights",
|
|
137
|
+
"metrics",
|
|
138
|
+
"todos",
|
|
139
|
+
"task_delegations",
|
|
140
|
+
"archives",
|
|
141
|
+
]:
|
|
142
|
+
self.get_collection_dir(collection).mkdir(exist_ok=True)
|
|
143
|
+
|
|
144
|
+
else:
|
|
145
|
+
# Pydantic not available - provide simple fallback
|
|
146
|
+
class SDKSettings: # type: ignore[no-redef]
|
|
147
|
+
"""Fallback settings without Pydantic."""
|
|
148
|
+
|
|
149
|
+
def __init__(self) -> None:
|
|
150
|
+
self.project_root = Path.cwd()
|
|
151
|
+
self.htmlgraph_dir_name = ".htmlgraph"
|
|
152
|
+
self.database_filename = "htmlgraph.db"
|
|
153
|
+
self.analytics_cache_filename = "index.sqlite"
|
|
154
|
+
|
|
155
|
+
def get_htmlgraph_dir(self) -> Path:
|
|
156
|
+
return self.project_root / self.htmlgraph_dir_name
|
|
157
|
+
|
|
158
|
+
def get_database_path(self) -> Path:
|
|
159
|
+
return self.get_htmlgraph_dir() / self.database_filename
|
|
160
|
+
|
|
161
|
+
def get_analytics_cache_path(self) -> Path:
|
|
162
|
+
return self.get_htmlgraph_dir() / self.analytics_cache_filename
|
|
163
|
+
|
|
164
|
+
default_settings = SDKSettings()
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
# Error messages (centralized)
|
|
168
|
+
ERROR_MESSAGES = {
|
|
169
|
+
"agent_required": (
|
|
170
|
+
"Agent identifier is required for work attribution. "
|
|
171
|
+
"Pass agent='name' to SDK() initialization. "
|
|
172
|
+
"Examples: SDK(agent='explorer'), SDK(agent='coder'), SDK(agent='tester')\n"
|
|
173
|
+
"Alternatively, set CLAUDE_AGENT_NAME environment variable.\n"
|
|
174
|
+
"Critical for: Work attribution, result retrieval, orchestrator tracking"
|
|
175
|
+
),
|
|
176
|
+
"htmlgraph_not_found": (
|
|
177
|
+
"Could not find .htmlgraph directory in {path} or any parent directory. "
|
|
178
|
+
"Run 'htmlgraph init' to initialize a new project."
|
|
179
|
+
),
|
|
180
|
+
"invalid_collection": "Unknown collection: {collection}",
|
|
181
|
+
"node_not_found": "Node not found: {node_id}",
|
|
182
|
+
"session_not_found": "Session not found: {session_id}",
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
# Work type constants
|
|
187
|
+
WORK_TYPES = [
|
|
188
|
+
"feature",
|
|
189
|
+
"bug",
|
|
190
|
+
"chore",
|
|
191
|
+
"spike",
|
|
192
|
+
"epic",
|
|
193
|
+
"phase",
|
|
194
|
+
"task",
|
|
195
|
+
"pattern",
|
|
196
|
+
"insight",
|
|
197
|
+
"metric",
|
|
198
|
+
]
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
# Status constants
|
|
202
|
+
STATUSES = ["todo", "active", "done", "archived", "abandoned"]
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
# Priority constants
|
|
206
|
+
PRIORITIES = ["low", "medium", "high", "critical"]
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
__all__ = [
|
|
210
|
+
"SDKSettings",
|
|
211
|
+
"default_settings",
|
|
212
|
+
"ERROR_MESSAGES",
|
|
213
|
+
"WORK_TYPES",
|
|
214
|
+
"STATUSES",
|
|
215
|
+
"PRIORITIES",
|
|
216
|
+
]
|