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.
Files changed (331) 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 +173 -17
  5. htmlgraph/__init__.pyi +123 -0
  6. htmlgraph/agent_detection.py +127 -0
  7. htmlgraph/agent_registry.py +45 -30
  8. htmlgraph/agents.py +160 -107
  9. htmlgraph/analytics/__init__.py +9 -2
  10. htmlgraph/analytics/cli.py +190 -51
  11. htmlgraph/analytics/cost_analyzer.py +391 -0
  12. htmlgraph/analytics/cost_monitor.py +664 -0
  13. htmlgraph/analytics/cost_reporter.py +675 -0
  14. htmlgraph/analytics/cross_session.py +617 -0
  15. htmlgraph/analytics/dependency.py +192 -100
  16. htmlgraph/analytics/pattern_learning.py +771 -0
  17. htmlgraph/analytics/session_graph.py +707 -0
  18. htmlgraph/analytics/strategic/__init__.py +80 -0
  19. htmlgraph/analytics/strategic/cost_optimizer.py +611 -0
  20. htmlgraph/analytics/strategic/pattern_detector.py +876 -0
  21. htmlgraph/analytics/strategic/preference_manager.py +709 -0
  22. htmlgraph/analytics/strategic/suggestion_engine.py +747 -0
  23. htmlgraph/analytics/work_type.py +190 -14
  24. htmlgraph/analytics_index.py +135 -51
  25. htmlgraph/api/__init__.py +3 -0
  26. htmlgraph/api/cost_alerts_websocket.py +416 -0
  27. htmlgraph/api/main.py +2498 -0
  28. htmlgraph/api/static/htmx.min.js +1 -0
  29. htmlgraph/api/static/style-redesign.css +1344 -0
  30. htmlgraph/api/static/style.css +1079 -0
  31. htmlgraph/api/templates/dashboard-redesign.html +1366 -0
  32. htmlgraph/api/templates/dashboard.html +794 -0
  33. htmlgraph/api/templates/partials/activity-feed-hierarchical.html +326 -0
  34. htmlgraph/api/templates/partials/activity-feed.html +1100 -0
  35. htmlgraph/api/templates/partials/agents-redesign.html +317 -0
  36. htmlgraph/api/templates/partials/agents.html +317 -0
  37. htmlgraph/api/templates/partials/event-traces.html +373 -0
  38. htmlgraph/api/templates/partials/features-kanban-redesign.html +509 -0
  39. htmlgraph/api/templates/partials/features.html +578 -0
  40. htmlgraph/api/templates/partials/metrics-redesign.html +346 -0
  41. htmlgraph/api/templates/partials/metrics.html +346 -0
  42. htmlgraph/api/templates/partials/orchestration-redesign.html +443 -0
  43. htmlgraph/api/templates/partials/orchestration.html +198 -0
  44. htmlgraph/api/templates/partials/spawners.html +375 -0
  45. htmlgraph/api/templates/partials/work-items.html +613 -0
  46. htmlgraph/api/websocket.py +538 -0
  47. htmlgraph/archive/__init__.py +24 -0
  48. htmlgraph/archive/bloom.py +234 -0
  49. htmlgraph/archive/fts.py +297 -0
  50. htmlgraph/archive/manager.py +583 -0
  51. htmlgraph/archive/search.py +244 -0
  52. htmlgraph/atomic_ops.py +560 -0
  53. htmlgraph/attribute_index.py +208 -0
  54. htmlgraph/bounded_paths.py +539 -0
  55. htmlgraph/builders/__init__.py +14 -0
  56. htmlgraph/builders/base.py +118 -29
  57. htmlgraph/builders/bug.py +150 -0
  58. htmlgraph/builders/chore.py +119 -0
  59. htmlgraph/builders/epic.py +150 -0
  60. htmlgraph/builders/feature.py +31 -6
  61. htmlgraph/builders/insight.py +195 -0
  62. htmlgraph/builders/metric.py +217 -0
  63. htmlgraph/builders/pattern.py +202 -0
  64. htmlgraph/builders/phase.py +162 -0
  65. htmlgraph/builders/spike.py +52 -19
  66. htmlgraph/builders/track.py +148 -72
  67. htmlgraph/cigs/__init__.py +81 -0
  68. htmlgraph/cigs/autonomy.py +385 -0
  69. htmlgraph/cigs/cost.py +475 -0
  70. htmlgraph/cigs/messages_basic.py +472 -0
  71. htmlgraph/cigs/messaging.py +365 -0
  72. htmlgraph/cigs/models.py +771 -0
  73. htmlgraph/cigs/pattern_storage.py +427 -0
  74. htmlgraph/cigs/patterns.py +503 -0
  75. htmlgraph/cigs/posttool_analyzer.py +234 -0
  76. htmlgraph/cigs/reporter.py +818 -0
  77. htmlgraph/cigs/tracker.py +317 -0
  78. htmlgraph/cli/.htmlgraph/.session-warning-state.json +6 -0
  79. htmlgraph/cli/.htmlgraph/agents.json +72 -0
  80. htmlgraph/cli/.htmlgraph/htmlgraph.db +0 -0
  81. htmlgraph/cli/__init__.py +42 -0
  82. htmlgraph/cli/__main__.py +6 -0
  83. htmlgraph/cli/analytics.py +1424 -0
  84. htmlgraph/cli/base.py +685 -0
  85. htmlgraph/cli/constants.py +206 -0
  86. htmlgraph/cli/core.py +954 -0
  87. htmlgraph/cli/main.py +147 -0
  88. htmlgraph/cli/models.py +475 -0
  89. htmlgraph/cli/templates/__init__.py +1 -0
  90. htmlgraph/cli/templates/cost_dashboard.py +399 -0
  91. htmlgraph/cli/work/__init__.py +239 -0
  92. htmlgraph/cli/work/browse.py +115 -0
  93. htmlgraph/cli/work/features.py +568 -0
  94. htmlgraph/cli/work/orchestration.py +676 -0
  95. htmlgraph/cli/work/report.py +728 -0
  96. htmlgraph/cli/work/sessions.py +466 -0
  97. htmlgraph/cli/work/snapshot.py +559 -0
  98. htmlgraph/cli/work/tracks.py +486 -0
  99. htmlgraph/cli_commands/__init__.py +1 -0
  100. htmlgraph/cli_commands/feature.py +195 -0
  101. htmlgraph/cli_framework.py +115 -0
  102. htmlgraph/collections/__init__.py +18 -0
  103. htmlgraph/collections/base.py +415 -98
  104. htmlgraph/collections/bug.py +53 -0
  105. htmlgraph/collections/chore.py +53 -0
  106. htmlgraph/collections/epic.py +53 -0
  107. htmlgraph/collections/feature.py +12 -26
  108. htmlgraph/collections/insight.py +100 -0
  109. htmlgraph/collections/metric.py +92 -0
  110. htmlgraph/collections/pattern.py +97 -0
  111. htmlgraph/collections/phase.py +53 -0
  112. htmlgraph/collections/session.py +194 -0
  113. htmlgraph/collections/spike.py +56 -16
  114. htmlgraph/collections/task_delegation.py +241 -0
  115. htmlgraph/collections/todo.py +511 -0
  116. htmlgraph/collections/traces.py +487 -0
  117. htmlgraph/config/cost_models.json +56 -0
  118. htmlgraph/config.py +190 -0
  119. htmlgraph/context_analytics.py +344 -0
  120. htmlgraph/converter.py +216 -28
  121. htmlgraph/cost_analysis/__init__.py +5 -0
  122. htmlgraph/cost_analysis/analyzer.py +438 -0
  123. htmlgraph/dashboard.html +2406 -307
  124. htmlgraph/dashboard.html.backup +6592 -0
  125. htmlgraph/dashboard.html.bak +7181 -0
  126. htmlgraph/dashboard.html.bak2 +7231 -0
  127. htmlgraph/dashboard.html.bak3 +7232 -0
  128. htmlgraph/db/__init__.py +38 -0
  129. htmlgraph/db/queries.py +790 -0
  130. htmlgraph/db/schema.py +1788 -0
  131. htmlgraph/decorators.py +317 -0
  132. htmlgraph/dependency_models.py +19 -2
  133. htmlgraph/deploy.py +142 -125
  134. htmlgraph/deployment_models.py +474 -0
  135. htmlgraph/docs/API_REFERENCE.md +841 -0
  136. htmlgraph/docs/HTTP_API.md +750 -0
  137. htmlgraph/docs/INTEGRATION_GUIDE.md +752 -0
  138. htmlgraph/docs/ORCHESTRATION_PATTERNS.md +717 -0
  139. htmlgraph/docs/README.md +532 -0
  140. htmlgraph/docs/__init__.py +77 -0
  141. htmlgraph/docs/docs_version.py +55 -0
  142. htmlgraph/docs/metadata.py +93 -0
  143. htmlgraph/docs/migrations.py +232 -0
  144. htmlgraph/docs/template_engine.py +143 -0
  145. htmlgraph/docs/templates/_sections/cli_reference.md.j2 +52 -0
  146. htmlgraph/docs/templates/_sections/core_concepts.md.j2 +29 -0
  147. htmlgraph/docs/templates/_sections/sdk_basics.md.j2 +69 -0
  148. htmlgraph/docs/templates/base_agents.md.j2 +78 -0
  149. htmlgraph/docs/templates/example_user_override.md.j2 +47 -0
  150. htmlgraph/docs/version_check.py +163 -0
  151. htmlgraph/edge_index.py +182 -27
  152. htmlgraph/error_handler.py +544 -0
  153. htmlgraph/event_log.py +100 -52
  154. htmlgraph/event_migration.py +13 -4
  155. htmlgraph/exceptions.py +49 -0
  156. htmlgraph/file_watcher.py +101 -28
  157. htmlgraph/find_api.py +75 -63
  158. htmlgraph/git_events.py +145 -63
  159. htmlgraph/graph.py +1122 -106
  160. htmlgraph/hooks/.htmlgraph/.session-warning-state.json +6 -0
  161. htmlgraph/hooks/.htmlgraph/agents.json +72 -0
  162. htmlgraph/hooks/.htmlgraph/index.sqlite +0 -0
  163. htmlgraph/hooks/__init__.py +45 -0
  164. htmlgraph/hooks/bootstrap.py +169 -0
  165. htmlgraph/hooks/cigs_pretool_enforcer.py +354 -0
  166. htmlgraph/hooks/concurrent_sessions.py +208 -0
  167. htmlgraph/hooks/context.py +350 -0
  168. htmlgraph/hooks/drift_handler.py +525 -0
  169. htmlgraph/hooks/event_tracker.py +1314 -0
  170. htmlgraph/hooks/git_commands.py +175 -0
  171. htmlgraph/hooks/hooks-config.example.json +12 -0
  172. htmlgraph/hooks/installer.py +343 -0
  173. htmlgraph/hooks/orchestrator.py +674 -0
  174. htmlgraph/hooks/orchestrator_reflector.py +223 -0
  175. htmlgraph/hooks/post-checkout.sh +28 -0
  176. htmlgraph/hooks/post-commit.sh +24 -0
  177. htmlgraph/hooks/post-merge.sh +26 -0
  178. htmlgraph/hooks/post_tool_use_failure.py +273 -0
  179. htmlgraph/hooks/post_tool_use_handler.py +257 -0
  180. htmlgraph/hooks/posttooluse.py +408 -0
  181. htmlgraph/hooks/pre-commit.sh +94 -0
  182. htmlgraph/hooks/pre-push.sh +28 -0
  183. htmlgraph/hooks/pretooluse.py +819 -0
  184. htmlgraph/hooks/prompt_analyzer.py +637 -0
  185. htmlgraph/hooks/session_handler.py +668 -0
  186. htmlgraph/hooks/session_summary.py +395 -0
  187. htmlgraph/hooks/state_manager.py +504 -0
  188. htmlgraph/hooks/subagent_detection.py +202 -0
  189. htmlgraph/hooks/subagent_stop.py +369 -0
  190. htmlgraph/hooks/task_enforcer.py +255 -0
  191. htmlgraph/hooks/task_validator.py +177 -0
  192. htmlgraph/hooks/validator.py +628 -0
  193. htmlgraph/ids.py +41 -27
  194. htmlgraph/index.d.ts +286 -0
  195. htmlgraph/learning.py +767 -0
  196. htmlgraph/mcp_server.py +69 -23
  197. htmlgraph/models.py +1586 -87
  198. htmlgraph/operations/README.md +62 -0
  199. htmlgraph/operations/__init__.py +79 -0
  200. htmlgraph/operations/analytics.py +339 -0
  201. htmlgraph/operations/bootstrap.py +289 -0
  202. htmlgraph/operations/events.py +244 -0
  203. htmlgraph/operations/fastapi_server.py +231 -0
  204. htmlgraph/operations/hooks.py +350 -0
  205. htmlgraph/operations/initialization.py +597 -0
  206. htmlgraph/operations/initialization.py.backup +228 -0
  207. htmlgraph/operations/server.py +303 -0
  208. htmlgraph/orchestration/__init__.py +58 -0
  209. htmlgraph/orchestration/claude_launcher.py +179 -0
  210. htmlgraph/orchestration/command_builder.py +72 -0
  211. htmlgraph/orchestration/headless_spawner.py +281 -0
  212. htmlgraph/orchestration/live_events.py +377 -0
  213. htmlgraph/orchestration/model_selection.py +327 -0
  214. htmlgraph/orchestration/plugin_manager.py +140 -0
  215. htmlgraph/orchestration/prompts.py +137 -0
  216. htmlgraph/orchestration/spawner_event_tracker.py +383 -0
  217. htmlgraph/orchestration/spawners/__init__.py +16 -0
  218. htmlgraph/orchestration/spawners/base.py +194 -0
  219. htmlgraph/orchestration/spawners/claude.py +173 -0
  220. htmlgraph/orchestration/spawners/codex.py +435 -0
  221. htmlgraph/orchestration/spawners/copilot.py +294 -0
  222. htmlgraph/orchestration/spawners/gemini.py +471 -0
  223. htmlgraph/orchestration/subprocess_runner.py +36 -0
  224. htmlgraph/orchestration/task_coordination.py +343 -0
  225. htmlgraph/orchestration.md +563 -0
  226. htmlgraph/orchestrator-system-prompt-optimized.txt +863 -0
  227. htmlgraph/orchestrator.py +669 -0
  228. htmlgraph/orchestrator_config.py +357 -0
  229. htmlgraph/orchestrator_mode.py +328 -0
  230. htmlgraph/orchestrator_validator.py +133 -0
  231. htmlgraph/parallel.py +646 -0
  232. htmlgraph/parser.py +160 -35
  233. htmlgraph/path_query.py +608 -0
  234. htmlgraph/pattern_matcher.py +636 -0
  235. htmlgraph/planning.py +147 -52
  236. htmlgraph/pydantic_models.py +476 -0
  237. htmlgraph/quality_gates.py +350 -0
  238. htmlgraph/query_builder.py +109 -72
  239. htmlgraph/query_composer.py +509 -0
  240. htmlgraph/reflection.py +443 -0
  241. htmlgraph/refs.py +344 -0
  242. htmlgraph/repo_hash.py +512 -0
  243. htmlgraph/repositories/__init__.py +292 -0
  244. htmlgraph/repositories/analytics_repository.py +455 -0
  245. htmlgraph/repositories/analytics_repository_standard.py +628 -0
  246. htmlgraph/repositories/feature_repository.py +581 -0
  247. htmlgraph/repositories/feature_repository_htmlfile.py +668 -0
  248. htmlgraph/repositories/feature_repository_memory.py +607 -0
  249. htmlgraph/repositories/feature_repository_sqlite.py +858 -0
  250. htmlgraph/repositories/filter_service.py +620 -0
  251. htmlgraph/repositories/filter_service_standard.py +445 -0
  252. htmlgraph/repositories/shared_cache.py +621 -0
  253. htmlgraph/repositories/shared_cache_memory.py +395 -0
  254. htmlgraph/repositories/track_repository.py +552 -0
  255. htmlgraph/repositories/track_repository_htmlfile.py +619 -0
  256. htmlgraph/repositories/track_repository_memory.py +508 -0
  257. htmlgraph/repositories/track_repository_sqlite.py +711 -0
  258. htmlgraph/routing.py +8 -19
  259. htmlgraph/scripts/deploy.py +1 -2
  260. htmlgraph/sdk/__init__.py +398 -0
  261. htmlgraph/sdk/__init__.pyi +14 -0
  262. htmlgraph/sdk/analytics/__init__.py +19 -0
  263. htmlgraph/sdk/analytics/engine.py +155 -0
  264. htmlgraph/sdk/analytics/helpers.py +178 -0
  265. htmlgraph/sdk/analytics/registry.py +109 -0
  266. htmlgraph/sdk/base.py +484 -0
  267. htmlgraph/sdk/constants.py +216 -0
  268. htmlgraph/sdk/core.pyi +308 -0
  269. htmlgraph/sdk/discovery.py +120 -0
  270. htmlgraph/sdk/help/__init__.py +12 -0
  271. htmlgraph/sdk/help/mixin.py +699 -0
  272. htmlgraph/sdk/mixins/__init__.py +15 -0
  273. htmlgraph/sdk/mixins/attribution.py +113 -0
  274. htmlgraph/sdk/mixins/mixin.py +410 -0
  275. htmlgraph/sdk/operations/__init__.py +12 -0
  276. htmlgraph/sdk/operations/mixin.py +427 -0
  277. htmlgraph/sdk/orchestration/__init__.py +17 -0
  278. htmlgraph/sdk/orchestration/coordinator.py +203 -0
  279. htmlgraph/sdk/orchestration/spawner.py +204 -0
  280. htmlgraph/sdk/planning/__init__.py +19 -0
  281. htmlgraph/sdk/planning/bottlenecks.py +93 -0
  282. htmlgraph/sdk/planning/mixin.py +211 -0
  283. htmlgraph/sdk/planning/parallel.py +186 -0
  284. htmlgraph/sdk/planning/queue.py +210 -0
  285. htmlgraph/sdk/planning/recommendations.py +87 -0
  286. htmlgraph/sdk/planning/smart_planning.py +319 -0
  287. htmlgraph/sdk/session/__init__.py +19 -0
  288. htmlgraph/sdk/session/continuity.py +57 -0
  289. htmlgraph/sdk/session/handoff.py +110 -0
  290. htmlgraph/sdk/session/info.py +309 -0
  291. htmlgraph/sdk/session/manager.py +103 -0
  292. htmlgraph/sdk/strategic/__init__.py +26 -0
  293. htmlgraph/sdk/strategic/mixin.py +563 -0
  294. htmlgraph/server.py +685 -180
  295. htmlgraph/services/__init__.py +10 -0
  296. htmlgraph/services/claiming.py +199 -0
  297. htmlgraph/session_hooks.py +300 -0
  298. htmlgraph/session_manager.py +1392 -175
  299. htmlgraph/session_registry.py +587 -0
  300. htmlgraph/session_state.py +436 -0
  301. htmlgraph/session_warning.py +201 -0
  302. htmlgraph/sessions/__init__.py +23 -0
  303. htmlgraph/sessions/handoff.py +756 -0
  304. htmlgraph/setup.py +34 -17
  305. htmlgraph/spike_index.py +143 -0
  306. htmlgraph/sync_docs.py +12 -15
  307. htmlgraph/system_prompts.py +450 -0
  308. htmlgraph/templates/AGENTS.md.template +366 -0
  309. htmlgraph/templates/CLAUDE.md.template +97 -0
  310. htmlgraph/templates/GEMINI.md.template +87 -0
  311. htmlgraph/templates/orchestration-view.html +350 -0
  312. htmlgraph/track_builder.py +146 -15
  313. htmlgraph/track_manager.py +69 -21
  314. htmlgraph/transcript.py +890 -0
  315. htmlgraph/transcript_analytics.py +699 -0
  316. htmlgraph/types.py +323 -0
  317. htmlgraph/validation.py +115 -0
  318. htmlgraph/watch.py +8 -5
  319. htmlgraph/work_type_utils.py +3 -2
  320. {htmlgraph-0.9.3.data → htmlgraph-0.27.5.data}/data/htmlgraph/dashboard.html +2406 -307
  321. htmlgraph-0.27.5.data/data/htmlgraph/templates/AGENTS.md.template +366 -0
  322. htmlgraph-0.27.5.data/data/htmlgraph/templates/CLAUDE.md.template +97 -0
  323. htmlgraph-0.27.5.data/data/htmlgraph/templates/GEMINI.md.template +87 -0
  324. {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/METADATA +97 -64
  325. htmlgraph-0.27.5.dist-info/RECORD +337 -0
  326. {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/entry_points.txt +1 -1
  327. htmlgraph/cli.py +0 -2688
  328. htmlgraph/sdk.py +0 -709
  329. htmlgraph-0.9.3.dist-info/RECORD +0 -61
  330. {htmlgraph-0.9.3.data → htmlgraph-0.27.5.data}/data/htmlgraph/styles.css +0 -0
  331. {htmlgraph-0.9.3.dist-info → htmlgraph-0.27.5.dist-info}/WHEEL +0 -0
@@ -0,0 +1,597 @@
1
+ from __future__ import annotations
2
+
3
+ """HtmlGraph initialization operations.
4
+
5
+ This module provides functions for initializing the .htmlgraph directory structure,
6
+ creating necessary files, and optionally installing Git hooks.
7
+
8
+ The initialization process includes:
9
+ 1. Directory structure creation (.htmlgraph with subdirectories)
10
+ 2. Database initialization (htmlgraph.db)
11
+ 3. Index creation (index.sqlite)
12
+ 4. Configuration files
13
+ 5. Optional Git hooks installation
14
+
15
+ Extracted from monolithic cmd_init() implementation for better maintainability.
16
+ """
17
+
18
+
19
+ import json
20
+ import sqlite3
21
+ import subprocess
22
+ from pathlib import Path
23
+ from typing import TYPE_CHECKING
24
+
25
+ if TYPE_CHECKING:
26
+ from htmlgraph.cli.models import InitConfig, InitResult, ValidationResult
27
+
28
+
29
+ # Default collections to create
30
+ DEFAULT_COLLECTIONS = [
31
+ "features",
32
+ "bugs",
33
+ "chores",
34
+ "spikes",
35
+ "epics",
36
+ "tracks",
37
+ "sessions",
38
+ "insights",
39
+ "metrics",
40
+ "cigs",
41
+ "patterns", # Learning collection (SDK patterns API)
42
+ "todos", # Persistent task tracking
43
+ "task-delegations", # Spawned agent observability
44
+ ]
45
+
46
+ # Additional directories
47
+ ADDITIONAL_DIRECTORIES = [
48
+ "events",
49
+ "logs",
50
+ "archive-index",
51
+ "archives",
52
+ ]
53
+
54
+
55
+ def validate_directory(base_dir: Path) -> ValidationResult:
56
+ """
57
+ Validate that directory is ready for initialization.
58
+
59
+ Args:
60
+ base_dir: Directory to validate
61
+
62
+ Returns:
63
+ ValidationResult with validation status and details
64
+ """
65
+ from htmlgraph.cli.models import ValidationResult
66
+
67
+ result = ValidationResult(exists=base_dir.exists())
68
+
69
+ # Check if directory exists
70
+ if not base_dir.exists():
71
+ result.valid = False
72
+ result.errors.append(f"Directory does not exist: {base_dir}")
73
+ return result
74
+
75
+ # Check if already initialized
76
+ graph_dir = base_dir / ".htmlgraph"
77
+ if graph_dir.exists():
78
+ result.is_initialized = True
79
+
80
+ # Check for nested .htmlgraph directory (initialization corruption bug)
81
+ nested_graph = graph_dir / ".htmlgraph"
82
+ if nested_graph.exists():
83
+ result.errors.append(
84
+ f"ERROR: Nested .htmlgraph directory detected at {nested_graph}\n"
85
+ " This indicates initialization corruption.\n"
86
+ " Fix: Remove nested directory with: rm -rf .htmlgraph/.htmlgraph/"
87
+ )
88
+ result.valid = False
89
+ return result
90
+
91
+ result.errors.append(
92
+ f"Directory already initialized: {graph_dir}\n"
93
+ " Directory already contains .htmlgraph folder"
94
+ )
95
+ result.valid = False
96
+ return result
97
+
98
+ # Check if in git repository
99
+ try:
100
+ subprocess.run(
101
+ ["git", "rev-parse", "--git-dir"],
102
+ cwd=base_dir,
103
+ capture_output=True,
104
+ check=True,
105
+ )
106
+ result.has_git = True
107
+ except (subprocess.CalledProcessError, FileNotFoundError):
108
+ result.has_git = False
109
+
110
+ return result
111
+
112
+
113
+ def create_directory_structure(base_dir: Path) -> list[str]:
114
+ """
115
+ Create the .htmlgraph directory structure.
116
+
117
+ Args:
118
+ base_dir: Base directory (usually current working directory)
119
+
120
+ Returns:
121
+ List of created directory paths
122
+ """
123
+ created = []
124
+ graph_dir = base_dir / ".htmlgraph"
125
+
126
+ # Create main graph directory
127
+ if not graph_dir.exists():
128
+ graph_dir.mkdir(parents=True)
129
+ created.append(str(graph_dir))
130
+
131
+ # Create collection directories
132
+ for collection in DEFAULT_COLLECTIONS:
133
+ coll_dir = graph_dir / collection
134
+ if not coll_dir.exists():
135
+ coll_dir.mkdir(parents=True)
136
+ created.append(str(coll_dir))
137
+
138
+ # Create additional directories
139
+ for dirname in ADDITIONAL_DIRECTORIES:
140
+ add_dir = graph_dir / dirname
141
+ if not add_dir.exists():
142
+ add_dir.mkdir(parents=True)
143
+ created.append(str(add_dir))
144
+
145
+ # Create logs subdirectory for errors
146
+ logs_errors = graph_dir / "logs" / "errors"
147
+ if not logs_errors.exists():
148
+ logs_errors.mkdir(parents=True)
149
+ created.append(str(logs_errors))
150
+
151
+ return created
152
+
153
+
154
+ def create_database(graph_dir: Path) -> str:
155
+ """
156
+ Create the SQLite database for agent events and sessions.
157
+
158
+ Args:
159
+ graph_dir: Path to .htmlgraph directory
160
+
161
+ Returns:
162
+ Path to created database file
163
+ """
164
+ db_path = graph_dir / "htmlgraph.db"
165
+
166
+ # Create database with schema
167
+ conn = sqlite3.connect(db_path)
168
+ cursor = conn.cursor()
169
+
170
+ # Sessions table
171
+ cursor.execute("""
172
+ CREATE TABLE IF NOT EXISTS sessions (
173
+ session_id TEXT PRIMARY KEY,
174
+ agent TEXT NOT NULL,
175
+ status TEXT DEFAULT 'active',
176
+ started_at TEXT NOT NULL,
177
+ ended_at TEXT,
178
+ event_count INTEGER DEFAULT 0,
179
+ created_at TEXT DEFAULT CURRENT_TIMESTAMP
180
+ )
181
+ """)
182
+
183
+ # Agent events table
184
+ cursor.execute("""
185
+ CREATE TABLE IF NOT EXISTS agent_events (
186
+ event_id TEXT PRIMARY KEY,
187
+ session_id TEXT NOT NULL,
188
+ tool_name TEXT NOT NULL,
189
+ timestamp TEXT NOT NULL,
190
+ success INTEGER DEFAULT 1,
191
+ feature_id TEXT,
192
+ work_type TEXT,
193
+ context TEXT,
194
+ FOREIGN KEY (session_id) REFERENCES sessions(session_id)
195
+ )
196
+ """)
197
+
198
+ # Create indexes for common queries
199
+ cursor.execute("""
200
+ CREATE INDEX IF NOT EXISTS idx_events_session
201
+ ON agent_events(session_id)
202
+ """)
203
+
204
+ cursor.execute("""
205
+ CREATE INDEX IF NOT EXISTS idx_events_timestamp
206
+ ON agent_events(timestamp)
207
+ """)
208
+
209
+ cursor.execute("""
210
+ CREATE INDEX IF NOT EXISTS idx_events_feature
211
+ ON agent_events(feature_id)
212
+ """)
213
+
214
+ conn.commit()
215
+ conn.close()
216
+
217
+ return str(db_path)
218
+
219
+
220
+ def create_analytics_index(graph_dir: Path) -> str:
221
+ """
222
+ Create the analytics cache database (index.sqlite).
223
+
224
+ Args:
225
+ graph_dir: Path to .htmlgraph directory
226
+
227
+ Returns:
228
+ Path to created index file
229
+ """
230
+ index_path = graph_dir / "index.sqlite"
231
+
232
+ try:
233
+ # Use AnalyticsIndex if available to ensure proper schema
234
+ from htmlgraph.analytics_index import AnalyticsIndex
235
+
236
+ index = AnalyticsIndex(str(index_path))
237
+ index.ensure_schema()
238
+ except ImportError:
239
+ # Fallback to simple creation if AnalyticsIndex not available
240
+ conn = sqlite3.connect(index_path)
241
+ cursor = conn.cursor()
242
+
243
+ # Create basic cache table structure
244
+ cursor.execute("""
245
+ CREATE TABLE IF NOT EXISTS cache_metadata (
246
+ key TEXT PRIMARY KEY,
247
+ value TEXT,
248
+ updated_at TEXT DEFAULT CURRENT_TIMESTAMP
249
+ )
250
+ """)
251
+
252
+ # Store schema version
253
+ cursor.execute("""
254
+ INSERT OR REPLACE INTO cache_metadata (key, value)
255
+ VALUES ('schema_version', '1.0')
256
+ """)
257
+
258
+ conn.commit()
259
+ conn.close()
260
+
261
+ return str(index_path)
262
+
263
+
264
+ def create_config_files(graph_dir: Path) -> list[str]:
265
+ """
266
+ Create initial configuration files.
267
+
268
+ Args:
269
+ graph_dir: Path to .htmlgraph directory
270
+
271
+ Returns:
272
+ List of created config file paths
273
+ """
274
+ created = []
275
+
276
+ # Create hooks-config.json
277
+ hooks_config = graph_dir / "hooks-config.json"
278
+ if not hooks_config.exists():
279
+ hooks_config.write_text(
280
+ json.dumps(
281
+ {
282
+ "enabled": True,
283
+ "track_events": True,
284
+ "detect_drift": True,
285
+ "auto_spikes": False,
286
+ },
287
+ indent=2,
288
+ )
289
+ )
290
+ created.append(str(hooks_config))
291
+
292
+ # Create drift-queue.json
293
+ drift_queue = graph_dir / "drift-queue.json"
294
+ if not drift_queue.exists():
295
+ drift_queue.write_text(json.dumps([], indent=2))
296
+ created.append(str(drift_queue))
297
+
298
+ # Create active-auto-spikes.json
299
+ auto_spikes = graph_dir / "active-auto-spikes.json"
300
+ if not auto_spikes.exists():
301
+ auto_spikes.write_text(json.dumps({}, indent=2))
302
+ created.append(str(auto_spikes))
303
+
304
+ # Create .gitkeep for events directory
305
+ events_gitkeep = graph_dir / "events" / ".gitkeep"
306
+ if not events_gitkeep.exists():
307
+ events_gitkeep.touch()
308
+ created.append(str(events_gitkeep))
309
+
310
+ return created
311
+
312
+
313
+ def create_hook_scripts(graph_dir: Path) -> list[str]:
314
+ """
315
+ Copy hook scripts to .htmlgraph/hooks directory.
316
+
317
+ Args:
318
+ graph_dir: Path to .htmlgraph directory
319
+
320
+ Returns:
321
+ List of created hook file paths
322
+ """
323
+ created: list[str] = []
324
+
325
+ try:
326
+ # Get the path to the hooks directory in the package
327
+ import htmlgraph
328
+
329
+ htmlgraph_dir = Path(htmlgraph.__file__).parent
330
+ hooks_src = htmlgraph_dir / "hooks"
331
+
332
+ if not hooks_src.exists():
333
+ return created
334
+
335
+ # Create hooks directory in graph_dir
336
+ hooks_dir = graph_dir / "hooks"
337
+ if not hooks_dir.exists():
338
+ hooks_dir.mkdir(parents=True)
339
+
340
+ # Copy hook scripts
341
+ hook_names = [
342
+ "post-commit.sh",
343
+ "post-checkout.sh",
344
+ "post-merge.sh",
345
+ "pre-push.sh",
346
+ ]
347
+ for hook_name in hook_names:
348
+ src_hook = hooks_src / hook_name
349
+ dest_hook = hooks_dir / hook_name
350
+
351
+ if src_hook.exists() and not dest_hook.exists():
352
+ # Copy the file
353
+ dest_hook.write_text(src_hook.read_text(encoding="utf-8"))
354
+ # Make it executable
355
+ import stat
356
+
357
+ dest_hook.chmod(
358
+ dest_hook.stat().st_mode
359
+ | stat.S_IXUSR
360
+ | stat.S_IXGRP
361
+ | stat.S_IXOTH
362
+ )
363
+ created.append(str(dest_hook))
364
+
365
+ except Exception:
366
+ # Silently fail if hooks can't be copied
367
+ pass
368
+
369
+ return created
370
+
371
+
372
+ def update_gitignore(base_dir: Path) -> str | None:
373
+ """
374
+ Update .gitignore to exclude HtmlGraph cache files.
375
+
376
+ Args:
377
+ base_dir: Base directory containing .gitignore
378
+
379
+ Returns:
380
+ Path to .gitignore if updated, None otherwise
381
+ """
382
+ gitignore_path = base_dir / ".gitignore"
383
+
384
+ # Read existing .gitignore or create new
385
+ existing_lines = []
386
+ if gitignore_path.exists():
387
+ existing_lines = gitignore_path.read_text().splitlines()
388
+
389
+ # Check if HtmlGraph section already exists
390
+ if any("# HtmlGraph" in line for line in existing_lines):
391
+ return None
392
+
393
+ # Add HtmlGraph section
394
+ new_lines = [
395
+ "",
396
+ "# HtmlGraph cache and regenerable files",
397
+ ".htmlgraph/index.sqlite",
398
+ ".htmlgraph/index.sqlite.backup",
399
+ ".htmlgraph/database.db",
400
+ ".htmlgraph/sessions/*.jsonl",
401
+ ".htmlgraph/events/*.jsonl",
402
+ ".htmlgraph/parent-activity.json",
403
+ ".htmlgraph/hook-debug.jsonl",
404
+ ".htmlgraph/errors.jsonl",
405
+ ]
406
+
407
+ # Append to existing .gitignore
408
+ with gitignore_path.open("a") as f:
409
+ f.write("\n".join(new_lines) + "\n")
410
+
411
+ return str(gitignore_path)
412
+
413
+
414
+ def install_git_hooks(base_dir: Path) -> bool:
415
+ """
416
+ Install Git hooks for event logging.
417
+
418
+ Args:
419
+ base_dir: Base directory containing .git
420
+
421
+ Returns:
422
+ True if hooks installed successfully, False otherwise
423
+ """
424
+ # Check if .git directory exists
425
+ git_dir = base_dir / ".git"
426
+ if not git_dir.exists():
427
+ return False
428
+
429
+ # Import hook installation from operations.hooks
430
+ try:
431
+ from htmlgraph.operations.hooks import install_hooks
432
+
433
+ result = install_hooks(project_dir=base_dir, use_copy=False)
434
+ return bool(result.installed)
435
+ except Exception:
436
+ return False
437
+
438
+
439
+ def _run_interactive_setup(graph_dir: Path, result: InitResult) -> None:
440
+ """
441
+ Run interactive setup wizard.
442
+
443
+ Args:
444
+ graph_dir: Path to .htmlgraph directory
445
+ result: InitResult to update with created files
446
+ """
447
+ print("\n=== HtmlGraph Interactive Setup ===\n")
448
+
449
+ # Ask about project name
450
+ project_name = input("Project name (optional, press Enter to skip): ").strip()
451
+
452
+ # Ask about default agent
453
+ default_agent = input("Default agent name (default: claude): ").strip()
454
+ if not default_agent:
455
+ default_agent = "claude"
456
+
457
+ # Create config file
458
+ config_file = graph_dir / "config.json"
459
+ if not config_file.exists():
460
+ config_data = {}
461
+ if project_name:
462
+ config_data["project_name"] = project_name
463
+ config_data["default_agent"] = default_agent
464
+
465
+ config_file.write_text(json.dumps(config_data, indent=2) + "\n")
466
+ result.files_created.append(str(config_file))
467
+ print(f"\n✓ Created config file: {config_file}")
468
+
469
+ print("\n✓ Interactive setup complete!\n")
470
+
471
+
472
+ def create_dashboard_index(base_dir: Path) -> str | None:
473
+ """
474
+ Copy the dashboard HTML file to index.html at the root.
475
+
476
+ Args:
477
+ base_dir: Base directory where index.html should be created
478
+
479
+ Returns:
480
+ Path to created index.html, or None if not created
481
+ """
482
+ try:
483
+ # Get the path to the dashboard template
484
+ import htmlgraph
485
+
486
+ htmlgraph_dir = Path(htmlgraph.__file__).parent
487
+ dashboard_path = htmlgraph_dir / "dashboard.html"
488
+
489
+ if not dashboard_path.exists():
490
+ return None
491
+
492
+ # Copy to root as index.html
493
+ index_path = base_dir / "index.html"
494
+ index_path.write_text(dashboard_path.read_text(encoding="utf-8"))
495
+ return str(index_path)
496
+ except Exception:
497
+ return None
498
+
499
+
500
+ def initialize_htmlgraph(config: InitConfig) -> InitResult:
501
+ """
502
+ Initialize HtmlGraph directory structure.
503
+
504
+ This is the main entry point for the init command.
505
+
506
+ Args:
507
+ config: InitConfig with initialization settings
508
+
509
+ Returns:
510
+ InitResult with initialization details
511
+ """
512
+ from htmlgraph.cli.models import InitResult
513
+
514
+ base_dir = Path(config.dir).resolve()
515
+ graph_dir = base_dir / ".htmlgraph"
516
+
517
+ # Validate directory
518
+ validation = validate_directory(base_dir)
519
+ if not validation.valid:
520
+ return InitResult(
521
+ success=False,
522
+ graph_dir=str(graph_dir),
523
+ errors=validation.errors,
524
+ )
525
+
526
+ result = InitResult(graph_dir=str(graph_dir))
527
+
528
+ try:
529
+ # Create directory structure
530
+ dirs_created = create_directory_structure(base_dir)
531
+ result.directories_created.extend(dirs_created)
532
+
533
+ # Create database
534
+ db_path = create_database(graph_dir)
535
+ result.files_created.append(db_path)
536
+
537
+ # Create analytics index (unless disabled)
538
+ if not config.no_index:
539
+ index_path = create_analytics_index(graph_dir)
540
+ result.files_created.append(index_path)
541
+ else:
542
+ result.warnings.append("Skipped analytics cache creation (--no-index)")
543
+
544
+ # Create config files (unless --no-events-keep)
545
+ if not config.no_events_keep:
546
+ config_files = create_config_files(graph_dir)
547
+ result.files_created.extend(config_files)
548
+ else:
549
+ result.warnings.append("Skipped .gitkeep creation (--no-events-keep)")
550
+
551
+ # Create hook scripts
552
+ hook_files = create_hook_scripts(graph_dir)
553
+ result.files_created.extend(hook_files)
554
+
555
+ # Create dashboard index.html at root
556
+ dashboard_index = create_dashboard_index(base_dir)
557
+ if dashboard_index:
558
+ result.files_created.append(dashboard_index)
559
+
560
+ # Update .gitignore (unless disabled)
561
+ if not config.no_update_gitignore:
562
+ gitignore_path = update_gitignore(base_dir)
563
+ if gitignore_path:
564
+ result.files_created.append(gitignore_path)
565
+ result.warnings.append("Updated .gitignore with HtmlGraph cache rules")
566
+ else:
567
+ result.warnings.append("Skipped .gitignore update (--no-update-gitignore)")
568
+
569
+ # Install Git hooks (if requested)
570
+ if config.install_hooks:
571
+ hooks_installed = install_git_hooks(base_dir)
572
+ result.hooks_installed = hooks_installed
573
+ if hooks_installed:
574
+ result.warnings.append("Installed Git hooks for event logging")
575
+ else:
576
+ result.warnings.append(
577
+ "Failed to install Git hooks (not in git repository?)"
578
+ )
579
+
580
+ # Interactive setup wizard (if requested)
581
+ if config.interactive:
582
+ _run_interactive_setup(graph_dir, result)
583
+
584
+ # Add Git reminder if not initialized
585
+ if not validation.has_git and not config.install_hooks:
586
+ result.warnings.append(
587
+ "Not in a Git repository. Run 'htmlgraph init --install-hooks' "
588
+ "if you want to track Git events."
589
+ )
590
+
591
+ result.success = True
592
+
593
+ except Exception as e:
594
+ result.success = False
595
+ result.errors.append(f"Initialization failed: {e}")
596
+
597
+ return result