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,637 @@
1
+ """
2
+ Prompt Analysis Module for HtmlGraph Hooks.
3
+
4
+ Centralizes prompt classification and workflow guidance logic used across
5
+ multiple hooks (UserPromptSubmit, PreToolUse, etc.).
6
+
7
+ This module provides:
8
+ - Intent classification (implementation, testing, refactoring, etc.)
9
+ - CIGS (Computational Imperative Guidance System) violation detection
10
+ - Active work item tracking
11
+ - Workflow guidance generation
12
+ - UserQuery event creation for parent-child linking
13
+
14
+ The module is designed to be reusable across different hook implementations,
15
+ with graceful degradation if dependencies are unavailable.
16
+ """
17
+
18
+ import logging
19
+ import re
20
+ import uuid
21
+ from datetime import datetime, timezone
22
+ from typing import Any
23
+
24
+ from htmlgraph.hooks.context import HookContext
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+
29
+ # Patterns that indicate implementation intent
30
+ IMPLEMENTATION_PATTERNS = [
31
+ r"\b(implement|add|create|build|write|develop|make)\b.*\b(feature|function|method|class|component|endpoint|api)\b",
32
+ r"\b(fix|resolve|patch|repair)\b.*\b(bug|issue|error|problem)\b",
33
+ r"\b(refactor|rewrite|restructure|reorganize)\b",
34
+ r"\b(update|modify|change|edit)\b.*\b(code|file|function|class)\b",
35
+ r"\bcan you\b.*\b(add|implement|create|fix|change)\b",
36
+ r"\bplease\b.*\b(add|implement|create|fix|change)\b",
37
+ r"\bI need\b.*\b(feature|function|fix|change)\b",
38
+ r"\blet'?s\b.*\b(implement|add|create|build|fix)\b",
39
+ ]
40
+
41
+ # Patterns that indicate investigation/research
42
+ INVESTIGATION_PATTERNS = [
43
+ r"\b(investigate|research|explore|analyze|understand|find out|look into)\b",
44
+ r"\b(why|how come|what causes)\b.*\b(not working|broken|failing|error)\b",
45
+ r"\b(where|which|what)\b.*\b(file|code|function|class)\b.*\b(handle|process|do)\b",
46
+ r"\bcan you\b.*\b(find|search|look for|check)\b",
47
+ ]
48
+
49
+ # Patterns that indicate bug/issue
50
+ BUG_PATTERNS = [
51
+ r"\b(bug|issue|error|problem|broken|not working|fails|crash)\b",
52
+ r"\b(something'?s? wrong|doesn'?t work|isn'?t working)\b",
53
+ r"\bCI\b.*\b(fail|error|broken)\b",
54
+ r"\btest.*\b(fail|error|broken)\b",
55
+ ]
56
+
57
+ # Patterns for continuation
58
+ CONTINUATION_PATTERNS = [
59
+ r"^(continue|resume|proceed|go on|keep going|next)\b",
60
+ r"\b(where we left off|from before|last time)\b",
61
+ r"^(ok|okay|yes|sure|do it|go ahead)\b",
62
+ ]
63
+
64
+ # CIGS: Patterns for delegation-critical operations
65
+ EXPLORATION_KEYWORDS = [
66
+ "search",
67
+ "find",
68
+ "what files",
69
+ "which files",
70
+ "where is",
71
+ "locate",
72
+ "analyze",
73
+ "examine",
74
+ "inspect",
75
+ "review",
76
+ "check",
77
+ "look at",
78
+ "show me",
79
+ "list",
80
+ "grep",
81
+ "read",
82
+ "scan",
83
+ "explore",
84
+ ]
85
+
86
+ CODE_CHANGE_KEYWORDS = [
87
+ "implement",
88
+ "fix",
89
+ "update",
90
+ "refactor",
91
+ "change",
92
+ "modify",
93
+ "edit",
94
+ "write",
95
+ "create file",
96
+ "add code",
97
+ "remove code",
98
+ "replace",
99
+ "rewrite",
100
+ "patch",
101
+ "add",
102
+ ]
103
+
104
+ GIT_KEYWORDS = [
105
+ "commit",
106
+ "push",
107
+ "pull",
108
+ "merge",
109
+ "branch",
110
+ "checkout",
111
+ "git add",
112
+ "git commit",
113
+ "git push",
114
+ "git status",
115
+ "git diff",
116
+ "rebase",
117
+ "cherry-pick",
118
+ "stash",
119
+ ]
120
+
121
+
122
+ def classify_prompt(prompt: str) -> dict[str, Any]:
123
+ """
124
+ Classify the user's prompt intent.
125
+
126
+ Analyzes the prompt text to determine the primary intent using pattern matching.
127
+ Returns classification results with confidence scores.
128
+
129
+ Args:
130
+ prompt: User's prompt text
131
+
132
+ Returns:
133
+ dict with:
134
+ - is_implementation: bool - Implementation/coding request
135
+ - is_investigation: bool - Research/exploration request
136
+ - is_bug_report: bool - Bug/issue report
137
+ - is_continuation: bool - Continuation of previous work
138
+ - confidence: float - Overall confidence (0.0-1.0)
139
+ - matched_patterns: list - Patterns that matched
140
+
141
+ Example:
142
+ >>> result = classify_prompt("Can you implement a new feature?")
143
+ >>> result['is_implementation']
144
+ True
145
+ """
146
+ prompt_lower = prompt.lower().strip()
147
+
148
+ result: dict[str, Any] = {
149
+ "is_implementation": False,
150
+ "is_investigation": False,
151
+ "is_bug_report": False,
152
+ "is_continuation": False,
153
+ "confidence": 0.0,
154
+ "matched_patterns": [],
155
+ }
156
+
157
+ # Check for continuation first (short prompts like "ok", "continue")
158
+ for pattern in CONTINUATION_PATTERNS:
159
+ if re.search(pattern, prompt_lower):
160
+ result["is_continuation"] = True
161
+ result["confidence"] = 0.9
162
+ result["matched_patterns"].append(f"continuation: {pattern}")
163
+ return result
164
+
165
+ # Check for implementation patterns
166
+ for pattern in IMPLEMENTATION_PATTERNS:
167
+ if re.search(pattern, prompt_lower):
168
+ result["is_implementation"] = True
169
+ result["confidence"] = max(result["confidence"], 0.8)
170
+ result["matched_patterns"].append(f"implementation: {pattern}")
171
+
172
+ # Check for investigation patterns
173
+ for pattern in INVESTIGATION_PATTERNS:
174
+ if re.search(pattern, prompt_lower):
175
+ result["is_investigation"] = True
176
+ result["confidence"] = max(result["confidence"], 0.7)
177
+ result["matched_patterns"].append(f"investigation: {pattern}")
178
+
179
+ # Check for bug patterns
180
+ for pattern in BUG_PATTERNS:
181
+ if re.search(pattern, prompt_lower):
182
+ result["is_bug_report"] = True
183
+ result["confidence"] = max(result["confidence"], 0.75)
184
+ result["matched_patterns"].append(f"bug: {pattern}")
185
+
186
+ return result
187
+
188
+
189
+ def classify_cigs_intent(prompt: str) -> dict[str, Any]:
190
+ """
191
+ Classify prompt for CIGS delegation guidance.
192
+
193
+ Analyzes the prompt to detect patterns that indicate exploration, code changes,
194
+ or git operations. Used to generate pre-response delegation imperatives.
195
+
196
+ Args:
197
+ prompt: User's prompt text
198
+
199
+ Returns:
200
+ dict with:
201
+ - involves_exploration: bool - Exploration/search activity
202
+ - involves_code_changes: bool - Code modification activity
203
+ - involves_git: bool - Git operation activity
204
+ - intent_confidence: float - Overall confidence (0.0-1.0)
205
+
206
+ Example:
207
+ >>> result = classify_cigs_intent("Search for all error handling code")
208
+ >>> result['involves_exploration']
209
+ True
210
+ """
211
+ prompt_lower = prompt.lower().strip()
212
+
213
+ result: dict[str, Any] = {
214
+ "involves_exploration": False,
215
+ "involves_code_changes": False,
216
+ "involves_git": False,
217
+ "intent_confidence": 0.0,
218
+ }
219
+
220
+ # Check for exploration keywords
221
+ exploration_matches = sum(1 for kw in EXPLORATION_KEYWORDS if kw in prompt_lower)
222
+ if exploration_matches > 0:
223
+ result["involves_exploration"] = True
224
+ result["intent_confidence"] = min(1.0, exploration_matches * 0.3)
225
+
226
+ # Check for code change keywords
227
+ code_matches = sum(1 for kw in CODE_CHANGE_KEYWORDS if kw in prompt_lower)
228
+ if code_matches > 0:
229
+ result["involves_code_changes"] = True
230
+ result["intent_confidence"] = max(
231
+ result["intent_confidence"], min(1.0, code_matches * 0.35)
232
+ )
233
+
234
+ # Check for git keywords
235
+ git_matches = sum(1 for kw in GIT_KEYWORDS if kw in prompt_lower)
236
+ if git_matches > 0:
237
+ result["involves_git"] = True
238
+ result["intent_confidence"] = max(
239
+ result["intent_confidence"], min(1.0, git_matches * 0.4)
240
+ )
241
+
242
+ return result
243
+
244
+
245
+ def get_session_violation_count(context: HookContext) -> tuple[int, int]:
246
+ """
247
+ Get violation count for current session using CIGS ViolationTracker.
248
+
249
+ Queries the CIGS violation tracker to retrieve session violation metrics.
250
+ Gracefully degrades to (0, 0) if CIGS is unavailable.
251
+
252
+ Args:
253
+ context: HookContext with session and graph directory info
254
+
255
+ Returns:
256
+ Tuple of (violation_count, total_waste_tokens)
257
+ Returns (0, 0) if CIGS is unavailable
258
+
259
+ Example:
260
+ >>> violation_count, waste_tokens = get_session_violation_count(context)
261
+ >>> if violation_count > 0:
262
+ ... logger.info(f"Violations this session: {violation_count}")
263
+ """
264
+ try:
265
+ from htmlgraph.cigs import ViolationTracker
266
+
267
+ tracker = ViolationTracker()
268
+ summary = tracker.get_session_violations()
269
+ return summary.total_violations, summary.total_waste_tokens
270
+ except Exception as e:
271
+ # Graceful degradation if CIGS not available
272
+ logger.debug(f"Could not get violation count: {e}")
273
+ return 0, 0
274
+
275
+
276
+ def get_active_work_item(context: HookContext) -> dict[str, Any] | None:
277
+ """
278
+ Query HtmlGraph for active feature/spike.
279
+
280
+ Attempts to load the active work item from the session manager.
281
+ Returns None if no active work item or if SDK is unavailable.
282
+
283
+ Args:
284
+ context: HookContext with session and graph directory info
285
+
286
+ Returns:
287
+ dict with work item details (id, title, type) or None if not found
288
+
289
+ Example:
290
+ >>> active = get_active_work_item(context)
291
+ >>> if active and active['type'] == 'feature':
292
+ ... logger.info(f"Active feature: {active['title']}")
293
+ """
294
+ try:
295
+ from htmlgraph import SDK
296
+
297
+ sdk = SDK()
298
+ work_item = sdk.get_active_work_item()
299
+ if work_item is None:
300
+ return None
301
+ # Convert ActiveWorkItem TypedDict to dict
302
+ return dict(work_item) if hasattr(work_item, "__iter__") else work_item # type: ignore
303
+ except Exception as e:
304
+ logger.debug(f"Could not get active work item: {e}")
305
+ return None
306
+
307
+
308
+ def generate_guidance(
309
+ classification: dict[str, Any], active_work: dict[str, Any] | None, prompt: str
310
+ ) -> str | None:
311
+ """
312
+ Generate workflow guidance based on classification and context.
313
+
314
+ Produces orchestrator directives and workflow suggestions based on
315
+ the prompt classification and current active work item.
316
+
317
+ Args:
318
+ classification: Result from classify_prompt()
319
+ active_work: Result from get_active_work_item()
320
+ prompt: Original user prompt
321
+
322
+ Returns:
323
+ Guidance string to display to user, or None if no guidance needed
324
+
325
+ Example:
326
+ >>> classification = classify_prompt("Implement new API endpoint")
327
+ >>> guidance = generate_guidance(classification, None, prompt)
328
+ >>> if guidance:
329
+ ... logger.info("%s", guidance)
330
+ """
331
+
332
+ # If continuing and has active work, no guidance needed
333
+ if classification["is_continuation"] and active_work:
334
+ return None
335
+
336
+ # If has active work item, check if it matches intent
337
+ if active_work:
338
+ work_type = active_work.get("type", "")
339
+ work_id = active_work.get("id", "")
340
+ work_title = active_work.get("title", "")
341
+
342
+ # Implementation request with spike active - suggest creating feature
343
+ if classification["is_implementation"] and work_type == "spike":
344
+ return (
345
+ f"⚡ ORCHESTRATOR DIRECTIVE: Implementation requested during spike.\n\n"
346
+ f"Active work: {work_id} ({work_title}) - Type: spike\n\n"
347
+ f"Spikes are for investigation, NOT implementation.\n\n"
348
+ f"REQUIRED WORKFLOW:\n\n"
349
+ f"1. COMPLETE OR PAUSE the spike:\n"
350
+ f" sdk = SDK(agent='claude')\n"
351
+ f" sdk.spikes.complete('{work_id}') # or sdk.spikes.pause('{work_id}')\n\n"
352
+ f"2. CREATE A FEATURE for implementation:\n"
353
+ f" feature = sdk.features.create('Feature title').save()\n"
354
+ f" sdk.features.start(feature.id)\n\n"
355
+ f"3. DELEGATE TO SUBAGENT:\n"
356
+ f" from htmlgraph.tasks import Task\n"
357
+ f" Task(\n"
358
+ f" subagent_type='general-purpose',\n"
359
+ f" prompt='Implement: [details]'\n"
360
+ f" ).execute()\n\n"
361
+ f"Proceed with orchestration.\n"
362
+ )
363
+
364
+ # Implementation request with feature active - remind to delegate
365
+ if classification["is_implementation"] and work_type == "feature":
366
+ return (
367
+ f"⚡ ORCHESTRATOR DIRECTIVE: Implementation work detected.\n\n"
368
+ f"Active work: {work_id} ({work_title}) - Type: feature\n\n"
369
+ f"REQUIRED: DELEGATE TO SUBAGENT:\n\n"
370
+ f" from htmlgraph.tasks import Task\n"
371
+ f" Task(\n"
372
+ f" subagent_type='general-purpose',\n"
373
+ f" prompt='Implement: [specific implementation details for {work_title}]'\n"
374
+ f" ).execute()\n\n"
375
+ f"DO NOT EXECUTE CODE DIRECTLY IN THIS CONTEXT.\n"
376
+ f"Orchestrators coordinate, subagents implement.\n\n"
377
+ f"Proceed with orchestration.\n"
378
+ )
379
+
380
+ # Bug report with feature active - might want bug instead
381
+ if classification["is_bug_report"] and work_type == "feature":
382
+ return (
383
+ f"📋 WORKFLOW GUIDANCE:\n"
384
+ f"Active work: {work_id} ({work_title}) - Type: feature\n\n"
385
+ f"This looks like a bug report. Consider:\n"
386
+ f"1. If this bug is part of {work_title}, continue with current feature\n"
387
+ f"2. If this is a separate issue, create a bug:\n\n"
388
+ f" sdk = SDK(agent='claude')\n"
389
+ f" bug = sdk.bugs.create('Bug title').save()\n"
390
+ f" sdk.bugs.start(bug.id)\n"
391
+ )
392
+
393
+ # Has appropriate work item - no guidance needed
394
+ return None
395
+
396
+ # No active work item - provide guidance based on intent
397
+ if classification["is_implementation"]:
398
+ return (
399
+ "⚡ ORCHESTRATOR DIRECTIVE: This is implementation work.\n\n"
400
+ "REQUIRED WORKFLOW (execute in order):\n\n"
401
+ "1. CREATE A WORK ITEM:\n"
402
+ " sdk = SDK(agent='claude')\n"
403
+ " feature = sdk.features.create('Your feature title').save()\n"
404
+ " sdk.features.start(feature.id)\n\n"
405
+ "2. DELEGATE TO SUBAGENT:\n"
406
+ " from htmlgraph.tasks import Task\n"
407
+ " Task(\n"
408
+ " subagent_type='general-purpose',\n"
409
+ " prompt='Implement: [specific implementation details]'\n"
410
+ " ).execute()\n\n"
411
+ "3. DO NOT EXECUTE CODE DIRECTLY IN THIS CONTEXT\n"
412
+ " - Orchestrators coordinate, subagents implement\n"
413
+ " - This ensures proper work tracking and session management\n\n"
414
+ "Proceed with orchestration.\n"
415
+ )
416
+
417
+ if classification["is_bug_report"]:
418
+ return (
419
+ "📋 WORKFLOW GUIDANCE - BUG REPORT DETECTED:\n\n"
420
+ "Create a bug work item to track this:\n\n"
421
+ " sdk = SDK(agent='claude')\n"
422
+ " bug = sdk.bugs.create('Bug title').save()\n"
423
+ " sdk.bugs.start(bug.id)\n\n"
424
+ "Then investigate and fix the issue.\n"
425
+ )
426
+
427
+ if classification["is_investigation"]:
428
+ return (
429
+ "📋 WORKFLOW GUIDANCE - INVESTIGATION REQUEST DETECTED:\n\n"
430
+ "Create a spike for time-boxed investigation:\n\n"
431
+ " sdk = SDK(agent='claude')\n"
432
+ " spike = sdk.spikes.create('Investigation title').save()\n"
433
+ " sdk.spikes.start(spike.id)\n\n"
434
+ "Spikes help track research and exploration work.\n"
435
+ )
436
+
437
+ # Low confidence or unclear intent - provide gentle reminder
438
+ if classification["confidence"] < 0.5:
439
+ return (
440
+ "💡 REMINDER: Consider creating a work item if this is a task:\n"
441
+ "- Feature: sdk.features.create('Title').save()\n"
442
+ "- Bug: sdk.bugs.create('Title').save()\n"
443
+ "- Spike: sdk.spikes.create('Title').save()\n"
444
+ )
445
+
446
+ return None
447
+
448
+
449
+ def generate_cigs_guidance(
450
+ cigs_intent: dict[str, Any], violation_count: int, waste_tokens: int
451
+ ) -> str:
452
+ """
453
+ Generate CIGS-specific guidance for detected violations.
454
+
455
+ Produces pre-response imperative guidance based on CIGS intent
456
+ classification and current session violation metrics.
457
+
458
+ Args:
459
+ cigs_intent: Result from classify_cigs_intent()
460
+ violation_count: Number of violations this session
461
+ waste_tokens: Total wasted tokens this session
462
+
463
+ Returns:
464
+ Imperative guidance string (empty if no guidance needed)
465
+
466
+ Example:
467
+ >>> cigs = classify_cigs_intent("Search for all error handling")
468
+ >>> guidance = generate_cigs_guidance(cigs, 0, 0)
469
+ >>> if guidance:
470
+ ... logger.info("%s", guidance)
471
+ """
472
+ imperatives = []
473
+
474
+ # Exploration guidance
475
+ if cigs_intent["involves_exploration"]:
476
+ imperatives.append(
477
+ "🔴 IMPERATIVE: This request involves exploration.\n"
478
+ "YOU MUST use spawn_gemini() for exploration (FREE cost).\n"
479
+ "DO NOT use Read/Grep/Glob directly - delegate to Explorer subagent."
480
+ )
481
+
482
+ # Code changes guidance
483
+ if cigs_intent["involves_code_changes"]:
484
+ imperatives.append(
485
+ "🔴 IMPERATIVE: This request involves code changes.\n"
486
+ "YOU MUST use spawn_codex() or Task() for implementation.\n"
487
+ "DO NOT use Edit/Write directly - delegate to Coder subagent."
488
+ )
489
+
490
+ # Git operations guidance
491
+ if cigs_intent["involves_git"]:
492
+ imperatives.append(
493
+ "🔴 IMPERATIVE: This request involves git operations.\n"
494
+ "YOU MUST use spawn_copilot() for git commands (60% cheaper).\n"
495
+ "DO NOT run git commands directly via Bash."
496
+ )
497
+
498
+ # Violation warning
499
+ if violation_count > 0:
500
+ warning_emoji = "⚠️" if violation_count < 3 else "🚨"
501
+ imperatives.append(
502
+ f"{warning_emoji} VIOLATION WARNING: You have {violation_count} delegation "
503
+ f"violations this session ({waste_tokens:,} tokens wasted).\n"
504
+ f"Circuit breaker triggers at 3 violations."
505
+ )
506
+
507
+ if not imperatives:
508
+ return ""
509
+
510
+ # Combine with header
511
+ guidance_parts = [
512
+ "═══════════════════════════════════════════════════════════",
513
+ "CIGS PRE-RESPONSE GUIDANCE (Computational Imperative Guidance System)",
514
+ "═══════════════════════════════════════════════════════════",
515
+ "",
516
+ ]
517
+ guidance_parts.extend(imperatives)
518
+ guidance_parts.append("")
519
+ guidance_parts.append("═══════════════════════════════════════════════════════════")
520
+
521
+ return "\n".join(guidance_parts)
522
+
523
+
524
+ def create_user_query_event(context: HookContext, prompt: str) -> str | None:
525
+ """
526
+ Create UserQuery event in HtmlGraph database.
527
+
528
+ Records the user prompt as a UserQuery event that serves as the parent
529
+ for subsequent tool calls and delegations. Database is the single source
530
+ of truth - no file-based state is used.
531
+
532
+ Args:
533
+ context: HookContext with session and database access
534
+ prompt: User's prompt text
535
+
536
+ Returns:
537
+ UserQuery event_id if successful, None otherwise
538
+
539
+ Note:
540
+ Gracefully degrades if database is unavailable. Does not block
541
+ user interaction on failure.
542
+
543
+ Example:
544
+ >>> context = HookContext.from_input(hook_input)
545
+ >>> event_id = create_user_query_event(context, "Implement feature X")
546
+ >>> if event_id:
547
+ ... logger.info(f"Created event: {event_id}")
548
+ """
549
+ try:
550
+ session_id = context.session_id
551
+
552
+ if not session_id or session_id == "unknown":
553
+ logger.debug("No valid session ID for UserQuery event")
554
+ return None
555
+
556
+ # Create UserQuery event in database
557
+ try:
558
+ db = context.database
559
+
560
+ # Ensure session exists in database before creating event
561
+ # (sessions table has foreign key references, so we need to ensure it exists)
562
+ cursor = db.connection.cursor()
563
+ cursor.execute(
564
+ "SELECT COUNT(*) FROM sessions WHERE session_id = ?",
565
+ (session_id,),
566
+ )
567
+ session_exists = cursor.fetchone()[0] > 0
568
+
569
+ if not session_exists:
570
+ # Create session entry if it doesn't exist
571
+ cursor.execute(
572
+ """
573
+ INSERT INTO sessions (session_id, created_at, status)
574
+ VALUES (?, ?, 'active')
575
+ """,
576
+ (session_id, datetime.now(timezone.utc).isoformat()),
577
+ )
578
+ db.connection.commit()
579
+ logger.debug(f"Created session entry: {session_id}")
580
+
581
+ # Generate event ID
582
+ user_query_event_id = f"uq-{uuid.uuid4().hex[:8]}"
583
+
584
+ # Prepare event details
585
+ input_summary = prompt[:200]
586
+
587
+ # Insert UserQuery event into agent_events
588
+ # Database is the single source of truth for parent-child linking
589
+ # Subsequent tool calls query database via get_parent_user_query()
590
+ success = db.insert_event(
591
+ event_id=user_query_event_id,
592
+ agent_id="user",
593
+ event_type="tool_call", # Valid event_type; find by tool_name='UserQuery'
594
+ session_id=session_id,
595
+ tool_name="UserQuery",
596
+ input_summary=input_summary,
597
+ context={
598
+ "prompt": prompt[:500],
599
+ "session": session_id,
600
+ },
601
+ )
602
+
603
+ if not success:
604
+ logger.warning("Failed to insert UserQuery event into database")
605
+ return None
606
+
607
+ logger.info(f"Created UserQuery event: {user_query_event_id}")
608
+ return user_query_event_id
609
+
610
+ except Exception as e:
611
+ # Database tracking is optional - graceful degradation
612
+ logger.error(f"UserQuery event creation failed: {e}", exc_info=True)
613
+ return None
614
+
615
+ except Exception as e:
616
+ # Silent failure - don't block user interaction
617
+ logger.error(f"Unexpected error in create_user_query_event: {e}", exc_info=True)
618
+ return None
619
+
620
+
621
+ __all__ = [
622
+ "classify_prompt",
623
+ "classify_cigs_intent",
624
+ "get_session_violation_count",
625
+ "get_active_work_item",
626
+ "generate_guidance",
627
+ "generate_cigs_guidance",
628
+ "create_user_query_event",
629
+ # Pattern constants for testing/extension
630
+ "IMPLEMENTATION_PATTERNS",
631
+ "INVESTIGATION_PATTERNS",
632
+ "BUG_PATTERNS",
633
+ "CONTINUATION_PATTERNS",
634
+ "EXPLORATION_KEYWORDS",
635
+ "CODE_CHANGE_KEYWORDS",
636
+ "GIT_KEYWORDS",
637
+ ]