@jaguilar87/gaia 5.0.0-rc1

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 (609) hide show
  1. package/.claude-plugin/marketplace.json +33 -0
  2. package/.claude-plugin/plugin.json +26 -0
  3. package/ARCHITECTURE.md +335 -0
  4. package/CHANGELOG.md +1212 -0
  5. package/CODE_OF_CONDUCT.md +11 -0
  6. package/CONTRIBUTING.md +146 -0
  7. package/INSTALL.md +436 -0
  8. package/LICENSE +21 -0
  9. package/README.md +222 -0
  10. package/SECURITY.md +47 -0
  11. package/agents/README.md +78 -0
  12. package/agents/cloud-troubleshooter.md +73 -0
  13. package/agents/developer.md +65 -0
  14. package/agents/gaia-operator.md +64 -0
  15. package/agents/gaia-orchestrator.md +237 -0
  16. package/agents/gaia-planner.md +53 -0
  17. package/agents/gaia-system.md +70 -0
  18. package/agents/gitops-operator.md +61 -0
  19. package/agents/terraform-architect.md +63 -0
  20. package/bin/README.md +106 -0
  21. package/bin/cli/__init__.py +1 -0
  22. package/bin/cli/approvals.py +740 -0
  23. package/bin/cli/cleanup.py +562 -0
  24. package/bin/cli/context.py +283 -0
  25. package/bin/cli/doctor.py +628 -0
  26. package/bin/cli/history.py +305 -0
  27. package/bin/cli/memory.py +464 -0
  28. package/bin/cli/metrics.py +1068 -0
  29. package/bin/cli/plans.py +515 -0
  30. package/bin/cli/status.py +302 -0
  31. package/bin/cli/update.py +382 -0
  32. package/bin/gaia +112 -0
  33. package/bin/gaia-cleanup.js +531 -0
  34. package/bin/gaia-doctor.js +635 -0
  35. package/bin/gaia-evidence +126 -0
  36. package/bin/gaia-history.js +251 -0
  37. package/bin/gaia-metrics.js +1278 -0
  38. package/bin/gaia-review.js +269 -0
  39. package/bin/gaia-scan +44 -0
  40. package/bin/gaia-scan.py +589 -0
  41. package/bin/gaia-skills-diagnose.js +929 -0
  42. package/bin/gaia-status.js +278 -0
  43. package/bin/gaia-uninstall.js +111 -0
  44. package/bin/gaia-update.js +816 -0
  45. package/bin/pre-publish-validate.js +610 -0
  46. package/bin/python-detect.js +60 -0
  47. package/commands/README.md +64 -0
  48. package/commands/gaia.md +37 -0
  49. package/commands/scan-project.md +67 -0
  50. package/config/README.md +71 -0
  51. package/config/cloud/aws.json +134 -0
  52. package/config/cloud/gcp.json +139 -0
  53. package/config/context-contracts.json +158 -0
  54. package/config/crons-schema.md +81 -0
  55. package/config/git_standards.json +72 -0
  56. package/config/surface-routing.json +421 -0
  57. package/config/universal-rules.json +102 -0
  58. package/dist/gaia-ops/.claude-plugin/plugin.json +24 -0
  59. package/dist/gaia-ops/README.md +80 -0
  60. package/dist/gaia-ops/agents/cloud-troubleshooter.md +73 -0
  61. package/dist/gaia-ops/agents/developer.md +65 -0
  62. package/dist/gaia-ops/agents/gaia-operator.md +64 -0
  63. package/dist/gaia-ops/agents/gaia-orchestrator.md +237 -0
  64. package/dist/gaia-ops/agents/gaia-planner.md +53 -0
  65. package/dist/gaia-ops/agents/gaia-system.md +70 -0
  66. package/dist/gaia-ops/agents/gitops-operator.md +61 -0
  67. package/dist/gaia-ops/agents/terraform-architect.md +63 -0
  68. package/dist/gaia-ops/commands/gaia.md +37 -0
  69. package/dist/gaia-ops/config/README.md +71 -0
  70. package/dist/gaia-ops/config/cloud/aws.json +134 -0
  71. package/dist/gaia-ops/config/cloud/gcp.json +139 -0
  72. package/dist/gaia-ops/config/context-contracts.json +158 -0
  73. package/dist/gaia-ops/config/crons-schema.md +81 -0
  74. package/dist/gaia-ops/config/git_standards.json +72 -0
  75. package/dist/gaia-ops/config/surface-routing.json +421 -0
  76. package/dist/gaia-ops/config/universal-rules.json +102 -0
  77. package/dist/gaia-ops/hooks/adapters/__init__.py +52 -0
  78. package/dist/gaia-ops/hooks/adapters/base.py +219 -0
  79. package/dist/gaia-ops/hooks/adapters/channel.py +17 -0
  80. package/dist/gaia-ops/hooks/adapters/claude_code.py +1890 -0
  81. package/dist/gaia-ops/hooks/adapters/types.py +194 -0
  82. package/dist/gaia-ops/hooks/adapters/utils.py +25 -0
  83. package/dist/gaia-ops/hooks/hooks.json +163 -0
  84. package/dist/gaia-ops/hooks/modules/__init__.py +15 -0
  85. package/dist/gaia-ops/hooks/modules/agents/__init__.py +29 -0
  86. package/dist/gaia-ops/hooks/modules/agents/contract_validator.py +647 -0
  87. package/dist/gaia-ops/hooks/modules/agents/response_contract.py +496 -0
  88. package/dist/gaia-ops/hooks/modules/agents/skill_injection_verifier.py +120 -0
  89. package/dist/gaia-ops/hooks/modules/agents/state_tracker.py +267 -0
  90. package/dist/gaia-ops/hooks/modules/agents/task_info_builder.py +74 -0
  91. package/dist/gaia-ops/hooks/modules/agents/transcript_analyzer.py +458 -0
  92. package/dist/gaia-ops/hooks/modules/agents/transcript_reader.py +152 -0
  93. package/dist/gaia-ops/hooks/modules/audit/__init__.py +28 -0
  94. package/dist/gaia-ops/hooks/modules/audit/event_detector.py +168 -0
  95. package/dist/gaia-ops/hooks/modules/audit/logger.py +131 -0
  96. package/dist/gaia-ops/hooks/modules/audit/metrics.py +134 -0
  97. package/dist/gaia-ops/hooks/modules/audit/workflow_auditor.py +611 -0
  98. package/dist/gaia-ops/hooks/modules/audit/workflow_recorder.py +296 -0
  99. package/dist/gaia-ops/hooks/modules/context/__init__.py +11 -0
  100. package/dist/gaia-ops/hooks/modules/context/agentic_loop_detector.py +165 -0
  101. package/dist/gaia-ops/hooks/modules/context/anchor_tracker.py +317 -0
  102. package/dist/gaia-ops/hooks/modules/context/compact_context_builder.py +218 -0
  103. package/dist/gaia-ops/hooks/modules/context/context_freshness.py +145 -0
  104. package/dist/gaia-ops/hooks/modules/context/context_injector.py +558 -0
  105. package/dist/gaia-ops/hooks/modules/context/context_writer.py +530 -0
  106. package/dist/gaia-ops/hooks/modules/context/contracts_loader.py +161 -0
  107. package/dist/gaia-ops/hooks/modules/core/__init__.py +40 -0
  108. package/dist/gaia-ops/hooks/modules/core/hook_entry.py +78 -0
  109. package/dist/gaia-ops/hooks/modules/core/paths.py +160 -0
  110. package/dist/gaia-ops/hooks/modules/core/plugin_mode.py +149 -0
  111. package/dist/gaia-ops/hooks/modules/core/plugin_setup.py +577 -0
  112. package/dist/gaia-ops/hooks/modules/core/state.py +179 -0
  113. package/dist/gaia-ops/hooks/modules/core/stdin.py +24 -0
  114. package/dist/gaia-ops/hooks/modules/events/__init__.py +1 -0
  115. package/dist/gaia-ops/hooks/modules/events/event_writer.py +210 -0
  116. package/dist/gaia-ops/hooks/modules/memory/__init__.py +8 -0
  117. package/dist/gaia-ops/hooks/modules/memory/episode_writer.py +216 -0
  118. package/dist/gaia-ops/hooks/modules/orchestrator/__init__.py +1 -0
  119. package/dist/gaia-ops/hooks/modules/orchestrator/delegate_mode.py +122 -0
  120. package/dist/gaia-ops/hooks/modules/scanning/__init__.py +8 -0
  121. package/dist/gaia-ops/hooks/modules/scanning/scan_trigger.py +84 -0
  122. package/dist/gaia-ops/hooks/modules/security/__init__.py +120 -0
  123. package/dist/gaia-ops/hooks/modules/security/approval_cleanup.py +87 -0
  124. package/dist/gaia-ops/hooks/modules/security/approval_constants.py +23 -0
  125. package/dist/gaia-ops/hooks/modules/security/approval_grants.py +1638 -0
  126. package/dist/gaia-ops/hooks/modules/security/approval_messages.py +71 -0
  127. package/dist/gaia-ops/hooks/modules/security/approval_scopes.py +222 -0
  128. package/dist/gaia-ops/hooks/modules/security/blocked_commands.py +595 -0
  129. package/dist/gaia-ops/hooks/modules/security/blocked_message_formatter.py +87 -0
  130. package/dist/gaia-ops/hooks/modules/security/command_semantics.py +181 -0
  131. package/dist/gaia-ops/hooks/modules/security/composition_rules.py +547 -0
  132. package/dist/gaia-ops/hooks/modules/security/flag_classifiers.py +873 -0
  133. package/dist/gaia-ops/hooks/modules/security/gitops_validator.py +179 -0
  134. package/dist/gaia-ops/hooks/modules/security/mutative_verbs.py +1131 -0
  135. package/dist/gaia-ops/hooks/modules/security/network_hosts.py +481 -0
  136. package/dist/gaia-ops/hooks/modules/security/prompt_validator.py +40 -0
  137. package/dist/gaia-ops/hooks/modules/security/shell_unwrapper.py +165 -0
  138. package/dist/gaia-ops/hooks/modules/security/tiers.py +196 -0
  139. package/dist/gaia-ops/hooks/modules/session/__init__.py +10 -0
  140. package/dist/gaia-ops/hooks/modules/session/pending_scanner.py +174 -0
  141. package/dist/gaia-ops/hooks/modules/session/session_context_writer.py +100 -0
  142. package/dist/gaia-ops/hooks/modules/session/session_event_injector.py +160 -0
  143. package/dist/gaia-ops/hooks/modules/session/session_manager.py +31 -0
  144. package/dist/gaia-ops/hooks/modules/session/session_registry.py +232 -0
  145. package/dist/gaia-ops/hooks/modules/tools/__init__.py +29 -0
  146. package/dist/gaia-ops/hooks/modules/tools/bash_validator.py +1008 -0
  147. package/dist/gaia-ops/hooks/modules/tools/cloud_pipe_validator.py +231 -0
  148. package/dist/gaia-ops/hooks/modules/tools/hook_response.py +55 -0
  149. package/dist/gaia-ops/hooks/modules/tools/shell_parser.py +227 -0
  150. package/dist/gaia-ops/hooks/modules/tools/stage_decomposer.py +315 -0
  151. package/dist/gaia-ops/hooks/modules/tools/task_validator.py +294 -0
  152. package/dist/gaia-ops/hooks/modules/validation/__init__.py +23 -0
  153. package/dist/gaia-ops/hooks/modules/validation/commit_validator.py +380 -0
  154. package/dist/gaia-ops/hooks/post_compact.py +43 -0
  155. package/dist/gaia-ops/hooks/post_tool_use.py +54 -0
  156. package/dist/gaia-ops/hooks/pre_compact.py +60 -0
  157. package/dist/gaia-ops/hooks/pre_tool_use.py +413 -0
  158. package/dist/gaia-ops/hooks/session_start.py +81 -0
  159. package/dist/gaia-ops/hooks/stop_hook.py +82 -0
  160. package/dist/gaia-ops/hooks/subagent_start.py +71 -0
  161. package/dist/gaia-ops/hooks/subagent_stop.py +295 -0
  162. package/dist/gaia-ops/hooks/task_completed.py +70 -0
  163. package/dist/gaia-ops/hooks/user_prompt_submit.py +246 -0
  164. package/dist/gaia-ops/settings.json +72 -0
  165. package/dist/gaia-ops/skills/README.md +154 -0
  166. package/dist/gaia-ops/skills/agent-protocol/SKILL.md +93 -0
  167. package/dist/gaia-ops/skills/agent-protocol/examples.md +223 -0
  168. package/dist/gaia-ops/skills/agent-response/SKILL.md +69 -0
  169. package/dist/gaia-ops/skills/agentic-loop/SKILL.md +80 -0
  170. package/dist/gaia-ops/skills/agentic-loop/reference.md +378 -0
  171. package/dist/gaia-ops/skills/blog-writing/SKILL.md +98 -0
  172. package/dist/gaia-ops/skills/blog-writing/reference.md +130 -0
  173. package/dist/gaia-ops/skills/brief-spec/SKILL.md +182 -0
  174. package/dist/gaia-ops/skills/command-execution/SKILL.md +64 -0
  175. package/dist/gaia-ops/skills/command-execution/reference.md +83 -0
  176. package/dist/gaia-ops/skills/context-updater/SKILL.md +87 -0
  177. package/dist/gaia-ops/skills/context-updater/examples.md +71 -0
  178. package/dist/gaia-ops/skills/developer-patterns/SKILL.md +50 -0
  179. package/dist/gaia-ops/skills/developer-patterns/reference.md +112 -0
  180. package/dist/gaia-ops/skills/execution/SKILL.md +99 -0
  181. package/dist/gaia-ops/skills/fast-queries/SKILL.md +43 -0
  182. package/dist/gaia-ops/skills/gaia-compact/SKILL.md +74 -0
  183. package/dist/gaia-ops/skills/gaia-patterns/SKILL.md +108 -0
  184. package/dist/gaia-ops/skills/gaia-patterns/reference.md +395 -0
  185. package/dist/gaia-ops/skills/gaia-planner/SKILL.md +37 -0
  186. package/dist/gaia-ops/skills/gaia-planner/reference.md +107 -0
  187. package/dist/gaia-ops/skills/gaia-release/SKILL.md +82 -0
  188. package/dist/gaia-ops/skills/gaia-release/reference.md +102 -0
  189. package/dist/gaia-ops/skills/gaia-self-check/SKILL.md +114 -0
  190. package/dist/gaia-ops/skills/gaia-self-check/reference.md +453 -0
  191. package/dist/gaia-ops/skills/gaia-verify/SKILL.md +77 -0
  192. package/dist/gaia-ops/skills/gaia-verify/reference.md +80 -0
  193. package/dist/gaia-ops/skills/git-conventions/SKILL.md +47 -0
  194. package/dist/gaia-ops/skills/gitops-patterns/SKILL.md +60 -0
  195. package/dist/gaia-ops/skills/gitops-patterns/reference.md +183 -0
  196. package/dist/gaia-ops/skills/gmail-policy/SKILL.md +200 -0
  197. package/dist/gaia-ops/skills/gmail-policy/reference.md +150 -0
  198. package/dist/gaia-ops/skills/gmail-triage/SKILL.md +100 -0
  199. package/dist/gaia-ops/skills/gws-setup/SKILL.md +99 -0
  200. package/dist/gaia-ops/skills/gws-setup/reference.md +73 -0
  201. package/dist/gaia-ops/skills/investigation/SKILL.md +100 -0
  202. package/dist/gaia-ops/skills/memory-curation/SKILL.md +83 -0
  203. package/dist/gaia-ops/skills/memory-search/SKILL.md +88 -0
  204. package/dist/gaia-ops/skills/orchestrator-approval/SKILL.md +160 -0
  205. package/dist/gaia-ops/skills/orchestrator-approval/reference.md +174 -0
  206. package/dist/gaia-ops/skills/pending-approvals/SKILL.md +72 -0
  207. package/dist/gaia-ops/skills/pending-approvals/reference.md +214 -0
  208. package/dist/gaia-ops/skills/readme-writing/SKILL.md +71 -0
  209. package/dist/gaia-ops/skills/readme-writing/reference.md +188 -0
  210. package/dist/gaia-ops/skills/reference.md +135 -0
  211. package/dist/gaia-ops/skills/request-approval/SKILL.md +140 -0
  212. package/dist/gaia-ops/skills/request-approval/examples.md +140 -0
  213. package/dist/gaia-ops/skills/request-approval/reference.md +57 -0
  214. package/dist/gaia-ops/skills/schedule-task/SKILL.md +64 -0
  215. package/dist/gaia-ops/skills/schedule-task/reference.md +233 -0
  216. package/dist/gaia-ops/skills/security-tiers/SKILL.md +141 -0
  217. package/dist/gaia-ops/skills/security-tiers/destructive-commands-reference.md +623 -0
  218. package/dist/gaia-ops/skills/security-tiers/reference.md +39 -0
  219. package/dist/gaia-ops/skills/skill-creation/SKILL.md +92 -0
  220. package/dist/gaia-ops/skills/skill-creation/reference.md +29 -0
  221. package/dist/gaia-ops/skills/terraform-patterns/SKILL.md +89 -0
  222. package/dist/gaia-ops/skills/terraform-patterns/reference.md +93 -0
  223. package/dist/gaia-ops/tools/__init__.py +9 -0
  224. package/dist/gaia-ops/tools/agentic-loop/decide-status.py +210 -0
  225. package/dist/gaia-ops/tools/agentic-loop/parse-metric.py +106 -0
  226. package/dist/gaia-ops/tools/agentic-loop/record-iteration.py +221 -0
  227. package/dist/gaia-ops/tools/context/README.md +132 -0
  228. package/dist/gaia-ops/tools/context/__init__.py +42 -0
  229. package/dist/gaia-ops/tools/context/_paths.py +20 -0
  230. package/dist/gaia-ops/tools/context/context_provider.py +721 -0
  231. package/dist/gaia-ops/tools/context/context_section_reader.py +342 -0
  232. package/dist/gaia-ops/tools/context/deep_merge.py +159 -0
  233. package/dist/gaia-ops/tools/context/pending_updates.py +760 -0
  234. package/dist/gaia-ops/tools/context/surface_router.py +278 -0
  235. package/dist/gaia-ops/tools/fast-queries/README.md +65 -0
  236. package/dist/gaia-ops/tools/fast-queries/__init__.py +30 -0
  237. package/dist/gaia-ops/tools/fast-queries/appservices/quicktriage_devops_developer.sh +75 -0
  238. package/dist/gaia-ops/tools/fast-queries/cloud/aws/quicktriage_aws_troubleshooter.sh +32 -0
  239. package/dist/gaia-ops/tools/fast-queries/cloud/gcp/quicktriage_gcp_troubleshooter.sh +88 -0
  240. package/dist/gaia-ops/tools/fast-queries/gitops/quicktriage_gitops_operator.sh +48 -0
  241. package/dist/gaia-ops/tools/fast-queries/run_triage.sh +59 -0
  242. package/dist/gaia-ops/tools/fast-queries/terraform/quicktriage_terraform_architect.sh +80 -0
  243. package/dist/gaia-ops/tools/gaia_simulator/__init__.py +33 -0
  244. package/dist/gaia-ops/tools/gaia_simulator/cli.py +354 -0
  245. package/dist/gaia-ops/tools/gaia_simulator/extractor.py +457 -0
  246. package/dist/gaia-ops/tools/gaia_simulator/reporter.py +258 -0
  247. package/dist/gaia-ops/tools/gaia_simulator/routing_simulator.py +334 -0
  248. package/dist/gaia-ops/tools/gaia_simulator/runner.py +539 -0
  249. package/dist/gaia-ops/tools/gaia_simulator/skills_mapper.py +264 -0
  250. package/dist/gaia-ops/tools/memory/README.md +0 -0
  251. package/dist/gaia-ops/tools/memory/__init__.py +20 -0
  252. package/dist/gaia-ops/tools/memory/backfill_fts5.py +107 -0
  253. package/dist/gaia-ops/tools/memory/conflict_detector.py +295 -0
  254. package/dist/gaia-ops/tools/memory/episodic.py +1210 -0
  255. package/dist/gaia-ops/tools/memory/git_invalidator.py +262 -0
  256. package/dist/gaia-ops/tools/memory/paths.py +102 -0
  257. package/dist/gaia-ops/tools/memory/scoring.py +193 -0
  258. package/dist/gaia-ops/tools/memory/search_store.py +360 -0
  259. package/dist/gaia-ops/tools/persist_transcript_analysis.py +85 -0
  260. package/dist/gaia-ops/tools/review/__init__.py +1 -0
  261. package/dist/gaia-ops/tools/review/review_engine.py +157 -0
  262. package/dist/gaia-ops/tools/scan/__init__.py +35 -0
  263. package/dist/gaia-ops/tools/scan/config.py +247 -0
  264. package/dist/gaia-ops/tools/scan/merge.py +212 -0
  265. package/dist/gaia-ops/tools/scan/orchestrator.py +549 -0
  266. package/dist/gaia-ops/tools/scan/registry.py +127 -0
  267. package/dist/gaia-ops/tools/scan/scanners/__init__.py +18 -0
  268. package/dist/gaia-ops/tools/scan/scanners/base.py +137 -0
  269. package/dist/gaia-ops/tools/scan/scanners/environment.py +349 -0
  270. package/dist/gaia-ops/tools/scan/scanners/git.py +570 -0
  271. package/dist/gaia-ops/tools/scan/scanners/infrastructure.py +875 -0
  272. package/dist/gaia-ops/tools/scan/scanners/orchestration.py +600 -0
  273. package/dist/gaia-ops/tools/scan/scanners/stack.py +1085 -0
  274. package/dist/gaia-ops/tools/scan/scanners/tools.py +260 -0
  275. package/dist/gaia-ops/tools/scan/setup.py +686 -0
  276. package/dist/gaia-ops/tools/scan/tests/__init__.py +1 -0
  277. package/dist/gaia-ops/tools/scan/tests/conftest.py +796 -0
  278. package/dist/gaia-ops/tools/scan/tests/test_environment.py +323 -0
  279. package/dist/gaia-ops/tools/scan/tests/test_git.py +419 -0
  280. package/dist/gaia-ops/tools/scan/tests/test_infrastructure.py +382 -0
  281. package/dist/gaia-ops/tools/scan/tests/test_integration.py +920 -0
  282. package/dist/gaia-ops/tools/scan/tests/test_merge.py +269 -0
  283. package/dist/gaia-ops/tools/scan/tests/test_orchestration.py +304 -0
  284. package/dist/gaia-ops/tools/scan/tests/test_stack.py +604 -0
  285. package/dist/gaia-ops/tools/scan/tests/test_tools.py +349 -0
  286. package/dist/gaia-ops/tools/scan/ui.py +624 -0
  287. package/dist/gaia-ops/tools/scan/verify.py +270 -0
  288. package/dist/gaia-ops/tools/scan/walk.py +118 -0
  289. package/dist/gaia-ops/tools/scan/workspace.py +85 -0
  290. package/dist/gaia-ops/tools/validation/README.md +244 -0
  291. package/dist/gaia-ops/tools/validation/__init__.py +17 -0
  292. package/dist/gaia-ops/tools/validation/approval_gate.py +321 -0
  293. package/dist/gaia-ops/tools/validation/validate_skills.py +189 -0
  294. package/dist/gaia-security/.claude-plugin/plugin.json +24 -0
  295. package/dist/gaia-security/README.md +90 -0
  296. package/dist/gaia-security/config/universal-rules.json +102 -0
  297. package/dist/gaia-security/hooks/adapters/__init__.py +52 -0
  298. package/dist/gaia-security/hooks/adapters/base.py +219 -0
  299. package/dist/gaia-security/hooks/adapters/channel.py +17 -0
  300. package/dist/gaia-security/hooks/adapters/claude_code.py +1890 -0
  301. package/dist/gaia-security/hooks/adapters/types.py +194 -0
  302. package/dist/gaia-security/hooks/adapters/utils.py +25 -0
  303. package/dist/gaia-security/hooks/hooks.json +84 -0
  304. package/dist/gaia-security/hooks/modules/__init__.py +15 -0
  305. package/dist/gaia-security/hooks/modules/agents/__init__.py +29 -0
  306. package/dist/gaia-security/hooks/modules/agents/contract_validator.py +647 -0
  307. package/dist/gaia-security/hooks/modules/agents/response_contract.py +496 -0
  308. package/dist/gaia-security/hooks/modules/agents/skill_injection_verifier.py +120 -0
  309. package/dist/gaia-security/hooks/modules/agents/state_tracker.py +267 -0
  310. package/dist/gaia-security/hooks/modules/agents/task_info_builder.py +74 -0
  311. package/dist/gaia-security/hooks/modules/agents/transcript_analyzer.py +458 -0
  312. package/dist/gaia-security/hooks/modules/agents/transcript_reader.py +152 -0
  313. package/dist/gaia-security/hooks/modules/audit/__init__.py +28 -0
  314. package/dist/gaia-security/hooks/modules/audit/event_detector.py +168 -0
  315. package/dist/gaia-security/hooks/modules/audit/logger.py +131 -0
  316. package/dist/gaia-security/hooks/modules/audit/metrics.py +134 -0
  317. package/dist/gaia-security/hooks/modules/audit/workflow_auditor.py +611 -0
  318. package/dist/gaia-security/hooks/modules/audit/workflow_recorder.py +296 -0
  319. package/dist/gaia-security/hooks/modules/context/__init__.py +11 -0
  320. package/dist/gaia-security/hooks/modules/context/agentic_loop_detector.py +165 -0
  321. package/dist/gaia-security/hooks/modules/context/anchor_tracker.py +317 -0
  322. package/dist/gaia-security/hooks/modules/context/compact_context_builder.py +218 -0
  323. package/dist/gaia-security/hooks/modules/context/context_freshness.py +145 -0
  324. package/dist/gaia-security/hooks/modules/context/context_injector.py +558 -0
  325. package/dist/gaia-security/hooks/modules/context/context_writer.py +530 -0
  326. package/dist/gaia-security/hooks/modules/context/contracts_loader.py +161 -0
  327. package/dist/gaia-security/hooks/modules/core/__init__.py +40 -0
  328. package/dist/gaia-security/hooks/modules/core/hook_entry.py +78 -0
  329. package/dist/gaia-security/hooks/modules/core/paths.py +160 -0
  330. package/dist/gaia-security/hooks/modules/core/plugin_mode.py +149 -0
  331. package/dist/gaia-security/hooks/modules/core/plugin_setup.py +577 -0
  332. package/dist/gaia-security/hooks/modules/core/state.py +179 -0
  333. package/dist/gaia-security/hooks/modules/core/stdin.py +24 -0
  334. package/dist/gaia-security/hooks/modules/events/__init__.py +1 -0
  335. package/dist/gaia-security/hooks/modules/events/event_writer.py +210 -0
  336. package/dist/gaia-security/hooks/modules/memory/__init__.py +8 -0
  337. package/dist/gaia-security/hooks/modules/memory/episode_writer.py +216 -0
  338. package/dist/gaia-security/hooks/modules/orchestrator/__init__.py +1 -0
  339. package/dist/gaia-security/hooks/modules/orchestrator/delegate_mode.py +122 -0
  340. package/dist/gaia-security/hooks/modules/scanning/__init__.py +8 -0
  341. package/dist/gaia-security/hooks/modules/scanning/scan_trigger.py +84 -0
  342. package/dist/gaia-security/hooks/modules/security/__init__.py +120 -0
  343. package/dist/gaia-security/hooks/modules/security/approval_cleanup.py +87 -0
  344. package/dist/gaia-security/hooks/modules/security/approval_constants.py +23 -0
  345. package/dist/gaia-security/hooks/modules/security/approval_grants.py +1638 -0
  346. package/dist/gaia-security/hooks/modules/security/approval_messages.py +71 -0
  347. package/dist/gaia-security/hooks/modules/security/approval_scopes.py +222 -0
  348. package/dist/gaia-security/hooks/modules/security/blocked_commands.py +595 -0
  349. package/dist/gaia-security/hooks/modules/security/blocked_message_formatter.py +87 -0
  350. package/dist/gaia-security/hooks/modules/security/command_semantics.py +181 -0
  351. package/dist/gaia-security/hooks/modules/security/composition_rules.py +547 -0
  352. package/dist/gaia-security/hooks/modules/security/flag_classifiers.py +873 -0
  353. package/dist/gaia-security/hooks/modules/security/gitops_validator.py +179 -0
  354. package/dist/gaia-security/hooks/modules/security/mutative_verbs.py +1131 -0
  355. package/dist/gaia-security/hooks/modules/security/network_hosts.py +481 -0
  356. package/dist/gaia-security/hooks/modules/security/prompt_validator.py +40 -0
  357. package/dist/gaia-security/hooks/modules/security/shell_unwrapper.py +165 -0
  358. package/dist/gaia-security/hooks/modules/security/tiers.py +196 -0
  359. package/dist/gaia-security/hooks/modules/session/__init__.py +10 -0
  360. package/dist/gaia-security/hooks/modules/session/pending_scanner.py +174 -0
  361. package/dist/gaia-security/hooks/modules/session/session_context_writer.py +100 -0
  362. package/dist/gaia-security/hooks/modules/session/session_event_injector.py +160 -0
  363. package/dist/gaia-security/hooks/modules/session/session_manager.py +31 -0
  364. package/dist/gaia-security/hooks/modules/session/session_registry.py +232 -0
  365. package/dist/gaia-security/hooks/modules/tools/__init__.py +29 -0
  366. package/dist/gaia-security/hooks/modules/tools/bash_validator.py +1008 -0
  367. package/dist/gaia-security/hooks/modules/tools/cloud_pipe_validator.py +231 -0
  368. package/dist/gaia-security/hooks/modules/tools/hook_response.py +55 -0
  369. package/dist/gaia-security/hooks/modules/tools/shell_parser.py +227 -0
  370. package/dist/gaia-security/hooks/modules/tools/stage_decomposer.py +315 -0
  371. package/dist/gaia-security/hooks/modules/tools/task_validator.py +294 -0
  372. package/dist/gaia-security/hooks/modules/validation/__init__.py +23 -0
  373. package/dist/gaia-security/hooks/modules/validation/commit_validator.py +380 -0
  374. package/dist/gaia-security/hooks/post_tool_use.py +54 -0
  375. package/dist/gaia-security/hooks/pre_tool_use.py +413 -0
  376. package/dist/gaia-security/hooks/session_start.py +81 -0
  377. package/dist/gaia-security/hooks/stop_hook.py +82 -0
  378. package/dist/gaia-security/hooks/user_prompt_submit.py +246 -0
  379. package/dist/gaia-security/settings.json +58 -0
  380. package/git-hooks/commit-msg +41 -0
  381. package/hooks/README.md +100 -0
  382. package/hooks/adapters/__init__.py +52 -0
  383. package/hooks/adapters/base.py +219 -0
  384. package/hooks/adapters/channel.py +17 -0
  385. package/hooks/adapters/claude_code.py +1890 -0
  386. package/hooks/adapters/types.py +194 -0
  387. package/hooks/adapters/utils.py +25 -0
  388. package/hooks/elicitation_result.py +179 -0
  389. package/hooks/hooks.json +84 -0
  390. package/hooks/modules/README.md +189 -0
  391. package/hooks/modules/__init__.py +15 -0
  392. package/hooks/modules/agents/__init__.py +29 -0
  393. package/hooks/modules/agents/contract_validator.py +647 -0
  394. package/hooks/modules/agents/response_contract.py +496 -0
  395. package/hooks/modules/agents/skill_injection_verifier.py +120 -0
  396. package/hooks/modules/agents/state_tracker.py +267 -0
  397. package/hooks/modules/agents/task_info_builder.py +74 -0
  398. package/hooks/modules/agents/transcript_analyzer.py +458 -0
  399. package/hooks/modules/agents/transcript_reader.py +152 -0
  400. package/hooks/modules/audit/__init__.py +28 -0
  401. package/hooks/modules/audit/event_detector.py +168 -0
  402. package/hooks/modules/audit/logger.py +131 -0
  403. package/hooks/modules/audit/metrics.py +134 -0
  404. package/hooks/modules/audit/workflow_auditor.py +611 -0
  405. package/hooks/modules/audit/workflow_recorder.py +296 -0
  406. package/hooks/modules/context/__init__.py +11 -0
  407. package/hooks/modules/context/agentic_loop_detector.py +165 -0
  408. package/hooks/modules/context/anchor_tracker.py +317 -0
  409. package/hooks/modules/context/compact_context_builder.py +218 -0
  410. package/hooks/modules/context/context_freshness.py +145 -0
  411. package/hooks/modules/context/context_injector.py +558 -0
  412. package/hooks/modules/context/context_writer.py +530 -0
  413. package/hooks/modules/context/contracts_loader.py +161 -0
  414. package/hooks/modules/core/__init__.py +40 -0
  415. package/hooks/modules/core/hook_entry.py +78 -0
  416. package/hooks/modules/core/paths.py +160 -0
  417. package/hooks/modules/core/plugin_mode.py +149 -0
  418. package/hooks/modules/core/plugin_setup.py +577 -0
  419. package/hooks/modules/core/state.py +179 -0
  420. package/hooks/modules/core/stdin.py +24 -0
  421. package/hooks/modules/events/__init__.py +1 -0
  422. package/hooks/modules/events/event_writer.py +210 -0
  423. package/hooks/modules/evidence/__init__.py +34 -0
  424. package/hooks/modules/evidence/assertions.py +137 -0
  425. package/hooks/modules/evidence/index_writer.py +57 -0
  426. package/hooks/modules/evidence/loader.py +126 -0
  427. package/hooks/modules/evidence/runner.py +241 -0
  428. package/hooks/modules/memory/__init__.py +8 -0
  429. package/hooks/modules/memory/episode_writer.py +216 -0
  430. package/hooks/modules/orchestrator/__init__.py +1 -0
  431. package/hooks/modules/orchestrator/delegate_mode.py +122 -0
  432. package/hooks/modules/scanning/__init__.py +8 -0
  433. package/hooks/modules/scanning/scan_trigger.py +84 -0
  434. package/hooks/modules/security/__init__.py +120 -0
  435. package/hooks/modules/security/approval_cleanup.py +87 -0
  436. package/hooks/modules/security/approval_constants.py +23 -0
  437. package/hooks/modules/security/approval_grants.py +1638 -0
  438. package/hooks/modules/security/approval_messages.py +71 -0
  439. package/hooks/modules/security/approval_scopes.py +222 -0
  440. package/hooks/modules/security/blocked_commands.py +595 -0
  441. package/hooks/modules/security/blocked_message_formatter.py +87 -0
  442. package/hooks/modules/security/command_semantics.py +181 -0
  443. package/hooks/modules/security/composition_rules.py +547 -0
  444. package/hooks/modules/security/flag_classifiers.py +873 -0
  445. package/hooks/modules/security/gitops_validator.py +179 -0
  446. package/hooks/modules/security/mutative_verbs.py +1131 -0
  447. package/hooks/modules/security/network_hosts.py +481 -0
  448. package/hooks/modules/security/prompt_validator.py +40 -0
  449. package/hooks/modules/security/shell_unwrapper.py +165 -0
  450. package/hooks/modules/security/tiers.py +196 -0
  451. package/hooks/modules/session/__init__.py +10 -0
  452. package/hooks/modules/session/pending_scanner.py +174 -0
  453. package/hooks/modules/session/session_context_writer.py +100 -0
  454. package/hooks/modules/session/session_event_injector.py +160 -0
  455. package/hooks/modules/session/session_manager.py +31 -0
  456. package/hooks/modules/session/session_registry.py +232 -0
  457. package/hooks/modules/tools/__init__.py +29 -0
  458. package/hooks/modules/tools/bash_validator.py +1008 -0
  459. package/hooks/modules/tools/cloud_pipe_validator.py +231 -0
  460. package/hooks/modules/tools/hook_response.py +55 -0
  461. package/hooks/modules/tools/shell_parser.py +227 -0
  462. package/hooks/modules/tools/stage_decomposer.py +315 -0
  463. package/hooks/modules/tools/task_validator.py +294 -0
  464. package/hooks/modules/validation/__init__.py +23 -0
  465. package/hooks/modules/validation/commit_validator.py +380 -0
  466. package/hooks/post_compact.py +43 -0
  467. package/hooks/post_tool_use.py +54 -0
  468. package/hooks/pre_compact.py +60 -0
  469. package/hooks/pre_tool_use.py +413 -0
  470. package/hooks/session_start.py +81 -0
  471. package/hooks/stop_hook.py +82 -0
  472. package/hooks/subagent_start.py +71 -0
  473. package/hooks/subagent_stop.py +295 -0
  474. package/hooks/task_completed.py +70 -0
  475. package/hooks/user_prompt_submit.py +246 -0
  476. package/index.js +83 -0
  477. package/package.json +99 -0
  478. package/pyproject.toml +32 -0
  479. package/skills/README.md +154 -0
  480. package/skills/agent-protocol/SKILL.md +93 -0
  481. package/skills/agent-protocol/examples.md +223 -0
  482. package/skills/agent-response/SKILL.md +69 -0
  483. package/skills/agentic-loop/SKILL.md +80 -0
  484. package/skills/agentic-loop/reference.md +378 -0
  485. package/skills/blog-writing/SKILL.md +98 -0
  486. package/skills/blog-writing/reference.md +130 -0
  487. package/skills/brief-spec/SKILL.md +182 -0
  488. package/skills/command-execution/SKILL.md +64 -0
  489. package/skills/command-execution/reference.md +83 -0
  490. package/skills/context-updater/SKILL.md +87 -0
  491. package/skills/context-updater/examples.md +71 -0
  492. package/skills/developer-patterns/SKILL.md +50 -0
  493. package/skills/developer-patterns/reference.md +112 -0
  494. package/skills/execution/SKILL.md +99 -0
  495. package/skills/fast-queries/SKILL.md +43 -0
  496. package/skills/gaia-compact/SKILL.md +74 -0
  497. package/skills/gaia-patterns/SKILL.md +108 -0
  498. package/skills/gaia-patterns/reference.md +395 -0
  499. package/skills/gaia-planner/SKILL.md +37 -0
  500. package/skills/gaia-planner/reference.md +107 -0
  501. package/skills/gaia-release/SKILL.md +82 -0
  502. package/skills/gaia-release/reference.md +102 -0
  503. package/skills/gaia-self-check/SKILL.md +114 -0
  504. package/skills/gaia-self-check/reference.md +453 -0
  505. package/skills/gaia-verify/SKILL.md +77 -0
  506. package/skills/gaia-verify/reference.md +80 -0
  507. package/skills/git-conventions/SKILL.md +47 -0
  508. package/skills/gitops-patterns/SKILL.md +60 -0
  509. package/skills/gitops-patterns/reference.md +183 -0
  510. package/skills/gmail-policy/SKILL.md +200 -0
  511. package/skills/gmail-policy/reference.md +150 -0
  512. package/skills/gmail-triage/SKILL.md +100 -0
  513. package/skills/gws-setup/SKILL.md +99 -0
  514. package/skills/gws-setup/reference.md +73 -0
  515. package/skills/investigation/SKILL.md +100 -0
  516. package/skills/memory-curation/SKILL.md +83 -0
  517. package/skills/memory-search/SKILL.md +88 -0
  518. package/skills/orchestrator-approval/SKILL.md +160 -0
  519. package/skills/orchestrator-approval/reference.md +174 -0
  520. package/skills/pending-approvals/SKILL.md +72 -0
  521. package/skills/pending-approvals/reference.md +214 -0
  522. package/skills/readme-writing/SKILL.md +71 -0
  523. package/skills/readme-writing/reference.md +188 -0
  524. package/skills/reference.md +135 -0
  525. package/skills/request-approval/SKILL.md +140 -0
  526. package/skills/request-approval/examples.md +140 -0
  527. package/skills/request-approval/reference.md +57 -0
  528. package/skills/schedule-task/SKILL.md +64 -0
  529. package/skills/schedule-task/reference.md +233 -0
  530. package/skills/security-tiers/SKILL.md +141 -0
  531. package/skills/security-tiers/destructive-commands-reference.md +623 -0
  532. package/skills/security-tiers/reference.md +39 -0
  533. package/skills/skill-creation/SKILL.md +92 -0
  534. package/skills/skill-creation/reference.md +29 -0
  535. package/skills/terraform-patterns/SKILL.md +89 -0
  536. package/skills/terraform-patterns/reference.md +93 -0
  537. package/templates/README.md +69 -0
  538. package/templates/managed-settings.template.json +43 -0
  539. package/tools/__init__.py +9 -0
  540. package/tools/agentic-loop/decide-status.py +210 -0
  541. package/tools/agentic-loop/parse-metric.py +106 -0
  542. package/tools/agentic-loop/record-iteration.py +221 -0
  543. package/tools/context/README.md +132 -0
  544. package/tools/context/__init__.py +42 -0
  545. package/tools/context/_paths.py +20 -0
  546. package/tools/context/context_provider.py +721 -0
  547. package/tools/context/context_section_reader.py +342 -0
  548. package/tools/context/deep_merge.py +159 -0
  549. package/tools/context/pending_updates.py +760 -0
  550. package/tools/context/surface_router.py +278 -0
  551. package/tools/fast-queries/README.md +65 -0
  552. package/tools/fast-queries/__init__.py +30 -0
  553. package/tools/fast-queries/appservices/quicktriage_devops_developer.sh +75 -0
  554. package/tools/fast-queries/cloud/aws/quicktriage_aws_troubleshooter.sh +32 -0
  555. package/tools/fast-queries/cloud/gcp/quicktriage_gcp_troubleshooter.sh +88 -0
  556. package/tools/fast-queries/gitops/quicktriage_gitops_operator.sh +48 -0
  557. package/tools/fast-queries/run_triage.sh +59 -0
  558. package/tools/fast-queries/terraform/quicktriage_terraform_architect.sh +80 -0
  559. package/tools/gaia_simulator/__init__.py +33 -0
  560. package/tools/gaia_simulator/cli.py +354 -0
  561. package/tools/gaia_simulator/extractor.py +457 -0
  562. package/tools/gaia_simulator/reporter.py +258 -0
  563. package/tools/gaia_simulator/routing_simulator.py +334 -0
  564. package/tools/gaia_simulator/runner.py +539 -0
  565. package/tools/gaia_simulator/skills_mapper.py +264 -0
  566. package/tools/memory/README.md +0 -0
  567. package/tools/memory/__init__.py +20 -0
  568. package/tools/memory/backfill_fts5.py +107 -0
  569. package/tools/memory/conflict_detector.py +295 -0
  570. package/tools/memory/episodic.py +1210 -0
  571. package/tools/memory/git_invalidator.py +262 -0
  572. package/tools/memory/paths.py +102 -0
  573. package/tools/memory/scoring.py +193 -0
  574. package/tools/memory/search_store.py +360 -0
  575. package/tools/persist_transcript_analysis.py +85 -0
  576. package/tools/review/__init__.py +1 -0
  577. package/tools/review/review_engine.py +157 -0
  578. package/tools/scan/__init__.py +35 -0
  579. package/tools/scan/config.py +247 -0
  580. package/tools/scan/merge.py +212 -0
  581. package/tools/scan/orchestrator.py +549 -0
  582. package/tools/scan/registry.py +127 -0
  583. package/tools/scan/scanners/__init__.py +18 -0
  584. package/tools/scan/scanners/base.py +137 -0
  585. package/tools/scan/scanners/environment.py +349 -0
  586. package/tools/scan/scanners/git.py +570 -0
  587. package/tools/scan/scanners/infrastructure.py +875 -0
  588. package/tools/scan/scanners/orchestration.py +600 -0
  589. package/tools/scan/scanners/stack.py +1085 -0
  590. package/tools/scan/scanners/tools.py +260 -0
  591. package/tools/scan/setup.py +686 -0
  592. package/tools/scan/tests/__init__.py +1 -0
  593. package/tools/scan/tests/conftest.py +796 -0
  594. package/tools/scan/tests/test_environment.py +323 -0
  595. package/tools/scan/tests/test_git.py +419 -0
  596. package/tools/scan/tests/test_infrastructure.py +382 -0
  597. package/tools/scan/tests/test_integration.py +920 -0
  598. package/tools/scan/tests/test_merge.py +269 -0
  599. package/tools/scan/tests/test_orchestration.py +304 -0
  600. package/tools/scan/tests/test_stack.py +604 -0
  601. package/tools/scan/tests/test_tools.py +349 -0
  602. package/tools/scan/ui.py +624 -0
  603. package/tools/scan/verify.py +270 -0
  604. package/tools/scan/walk.py +118 -0
  605. package/tools/scan/workspace.py +85 -0
  606. package/tools/validation/README.md +244 -0
  607. package/tools/validation/__init__.py +17 -0
  608. package/tools/validation/approval_gate.py +321 -0
  609. package/tools/validation/validate_skills.py +189 -0
@@ -0,0 +1,360 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ FTS5-Backed Search Store for GAIA-OPS
4
+
5
+ Provides full-text search over episodic memory using SQLite FTS5 (default)
6
+ with an optional Chroma vector-search backend.
7
+
8
+ Zero external dependencies for core operation — stdlib only (sqlite3, shutil,
9
+ os, pathlib, typing, abc). chromadb is imported lazily and only used if
10
+ available and not suppressed via GAIA_TEST_NO_CHROMA.
11
+
12
+ Architecture:
13
+ - SearchProvider ABC defines the interface
14
+ - FTS5Provider wraps SQLite FTS5 (always available)
15
+ - ChromaProvider stub that activates only when chromadb is importable and
16
+ GAIA_TEST_NO_CHROMA is not set
17
+ - Module-level get_backend() / index_episode() / search() / count()
18
+ delegate to the active provider (resolved once at import time)
19
+ - Lazy init: DB/table created on first FTS5 call
20
+ - Fail-safe: all public functions wrapped in try/except
21
+
22
+ Environment:
23
+ GAIA_SEARCH_DB_PATH: Override the default SQLite DB path.
24
+ GAIA_TEST_NO_CHROMA: Set to any non-empty value to force FTS5 backend.
25
+
26
+ Functions:
27
+ index_episode -- Insert or ignore an episode into the active backend
28
+ search -- Query backend, returns ranked results
29
+ count -- Count indexed episodes
30
+ get_backend -- Returns "chroma" or "fts5"
31
+ has_engram -- Returns True if engram binary is on PATH
32
+ """
33
+
34
+ import abc
35
+ import os
36
+ import shutil
37
+ import sqlite3
38
+ from pathlib import Path
39
+ from typing import Dict, List, Optional
40
+
41
+
42
+ # ---------------------------------------------------------------------------
43
+ # DB path resolution (used by FTS5Provider)
44
+ # ---------------------------------------------------------------------------
45
+
46
+ _DEFAULT_RELATIVE_PATH = ".claude/project-context/episodic-memory/search.db"
47
+
48
+
49
+ def _resolve_db_path() -> Path:
50
+ """Resolve the search DB path.
51
+
52
+ Priority:
53
+ 1. GAIA_SEARCH_DB_PATH environment variable
54
+ 2. Highest ancestor with a .claude/ directory (closest to HOME),
55
+ so that a nested .claude/ in a sub-repository or dev checkout
56
+ never shadows the real Gaia instance.
57
+ 3. Bare relative path fallback (last resort, same as before).
58
+ """
59
+ env_path = os.environ.get("GAIA_SEARCH_DB_PATH")
60
+ if env_path:
61
+ return Path(env_path)
62
+
63
+ try:
64
+ from memory.paths import find_highest_claude_root
65
+ root = find_highest_claude_root()
66
+ if root is not None:
67
+ return root / _DEFAULT_RELATIVE_PATH
68
+ except ImportError:
69
+ pass
70
+
71
+ # Fallback: original first-match walk (keeps behaviour if paths.py is
72
+ # somehow unavailable, e.g. during isolated unit tests that only add
73
+ # the tools/ root to sys.path after import).
74
+ current = Path.cwd()
75
+ for parent in [current, *current.parents]:
76
+ if (parent / ".claude").is_dir():
77
+ return parent / _DEFAULT_RELATIVE_PATH
78
+
79
+ return Path(_DEFAULT_RELATIVE_PATH)
80
+
81
+
82
+ # ---------------------------------------------------------------------------
83
+ # SearchProvider ABC
84
+ # ---------------------------------------------------------------------------
85
+
86
+ class SearchProvider(abc.ABC):
87
+ """Abstract base for search backends."""
88
+
89
+ @abc.abstractmethod
90
+ def index(self, episode_id: str, text: str, **kwargs) -> None:
91
+ """Insert or update an episode in the index."""
92
+
93
+ @abc.abstractmethod
94
+ def search(self, query: str, max_results: int = 10) -> List[Dict]:
95
+ """Return a ranked list of dicts with at least 'episode_id' key."""
96
+
97
+ @abc.abstractmethod
98
+ def count(self) -> int:
99
+ """Return the total number of indexed episodes."""
100
+
101
+
102
+ # ---------------------------------------------------------------------------
103
+ # FTS5Provider
104
+ # ---------------------------------------------------------------------------
105
+
106
+ class FTS5Provider(SearchProvider):
107
+ """SQLite FTS5 backend — always available, zero external dependencies."""
108
+
109
+ def __init__(self) -> None:
110
+ self._connection: Optional[sqlite3.Connection] = None
111
+
112
+ # -- internal helpers ---------------------------------------------------
113
+
114
+ def _get_connection(self) -> sqlite3.Connection:
115
+ if self._connection is not None:
116
+ return self._connection
117
+
118
+ db_path = _resolve_db_path()
119
+ db_path.parent.mkdir(parents=True, exist_ok=True)
120
+
121
+ conn = sqlite3.connect(str(db_path), check_same_thread=False)
122
+ conn.execute("PRAGMA journal_mode=WAL")
123
+ conn.execute(
124
+ """
125
+ CREATE VIRTUAL TABLE IF NOT EXISTS episodes_fts USING fts5(
126
+ episode_id,
127
+ prompt,
128
+ enriched_prompt,
129
+ tags,
130
+ title
131
+ )
132
+ """
133
+ )
134
+ conn.commit()
135
+ self._connection = conn
136
+ return self._connection
137
+
138
+ @staticmethod
139
+ def _sanitize_query(query: str) -> str:
140
+ """Append * wildcard to each word for FTS5 prefix matching.
141
+
142
+ Uses prefix matching instead of exact quoted tokens so that
143
+ "approval" matches "approvals", "approving", etc.
144
+ Special characters that would break FTS5 syntax are stripped.
145
+
146
+ Hyphens are replaced with spaces before tokenisation so that
147
+ queries like "brief-spec" or "context-v5" are treated as two
148
+ separate prefix terms ("brief*" "spec*") rather than a single
149
+ phrase that FTS5 cannot match (FTS5 treats hyphens as token
150
+ separators at index time, so the stored tokens never contain
151
+ hyphens).
152
+ """
153
+ # Replace hyphens with spaces so "brief-spec" → "brief spec"
154
+ query = query.replace("-", " ")
155
+ words = query.split()
156
+ # Strip characters that break FTS5 syntax, then append wildcard
157
+ safe = [w.replace('"', '').replace("'", '').strip('*') for w in words if w]
158
+ return " ".join(w + "*" for w in safe if w)
159
+
160
+ # -- SearchProvider interface ------------------------------------------
161
+
162
+ def index(self, episode_id: str, text: str, **kwargs) -> None:
163
+ """Insert episode into FTS5 table (no-op if already present).
164
+
165
+ Keyword arguments are mapped to FTS5 columns:
166
+ enriched_prompt, tags, title
167
+ The ``text`` positional argument maps to the ``prompt`` column.
168
+ """
169
+ enriched_prompt = kwargs.get("enriched_prompt", "")
170
+ tags = kwargs.get("tags", "")
171
+ title = kwargs.get("title", "")
172
+ try:
173
+ conn = self._get_connection()
174
+ existing = conn.execute(
175
+ "SELECT rowid FROM episodes_fts WHERE episode_id = ?",
176
+ (episode_id,),
177
+ ).fetchone()
178
+ if existing is not None:
179
+ return
180
+ conn.execute(
181
+ "INSERT INTO episodes_fts"
182
+ "(episode_id, prompt, enriched_prompt, tags, title) "
183
+ "VALUES (?, ?, ?, ?, ?)",
184
+ (episode_id, text, enriched_prompt, tags, title),
185
+ )
186
+ conn.commit()
187
+ except Exception: # noqa: BLE001
188
+ pass
189
+
190
+ def search(self, query: str, max_results: int = 10) -> List[Dict]:
191
+ if not query or not query.strip():
192
+ return []
193
+ try:
194
+ conn = self._get_connection()
195
+ sanitized = self._sanitize_query(query.strip())
196
+ rows = conn.execute(
197
+ "SELECT episode_id, rank FROM episodes_fts "
198
+ "WHERE episodes_fts MATCH ? "
199
+ "ORDER BY rank "
200
+ "LIMIT ?",
201
+ (sanitized, max_results),
202
+ ).fetchall()
203
+ return [{"episode_id": row[0], "rank": row[1]} for row in rows]
204
+ except Exception: # noqa: BLE001
205
+ return []
206
+
207
+ def count(self) -> int:
208
+ try:
209
+ conn = self._get_connection()
210
+ row = conn.execute("SELECT COUNT(*) FROM episodes_fts").fetchone()
211
+ return int(row[0]) if row else 0
212
+ except Exception: # noqa: BLE001
213
+ return 0
214
+
215
+
216
+ # ---------------------------------------------------------------------------
217
+ # ChromaProvider (stub)
218
+ # ---------------------------------------------------------------------------
219
+
220
+ class ChromaProvider(SearchProvider):
221
+ """Chroma vector-search backend.
222
+
223
+ Only instantiated when:
224
+ - ``chromadb`` is importable, AND
225
+ - ``GAIA_TEST_NO_CHROMA`` env var is NOT set
226
+
227
+ Raises ``ImportError`` in __init__ if either condition is not met so
228
+ that the factory can fall back to FTS5Provider transparently.
229
+ """
230
+
231
+ def __init__(self) -> None:
232
+ if os.environ.get("GAIA_TEST_NO_CHROMA"):
233
+ raise ImportError("GAIA_TEST_NO_CHROMA is set — Chroma disabled")
234
+ import chromadb # noqa: F401 -- intentional optional import
235
+ # Future: initialise a persistent Chroma client and collection here.
236
+ # For now this is a stub; raise to signal not-yet-implemented.
237
+ raise NotImplementedError(
238
+ "ChromaProvider is a stub — not yet fully implemented"
239
+ )
240
+
241
+ def index(self, episode_id: str, text: str, **kwargs) -> None: # pragma: no cover
242
+ raise NotImplementedError
243
+
244
+ def search(self, query: str, max_results: int = 10) -> List[Dict]: # pragma: no cover
245
+ raise NotImplementedError
246
+
247
+ def count(self) -> int: # pragma: no cover
248
+ raise NotImplementedError
249
+
250
+
251
+ # ---------------------------------------------------------------------------
252
+ # Provider resolution (module-level singleton)
253
+ # ---------------------------------------------------------------------------
254
+
255
+ def _resolve_provider() -> SearchProvider:
256
+ """Return the best available SearchProvider.
257
+
258
+ Tries ChromaProvider first; falls back to FTS5Provider silently on any
259
+ ImportError or NotImplementedError.
260
+ """
261
+ try:
262
+ return ChromaProvider()
263
+ except (ImportError, NotImplementedError):
264
+ return FTS5Provider()
265
+
266
+
267
+ _provider: SearchProvider = _resolve_provider()
268
+
269
+
270
+ # ---------------------------------------------------------------------------
271
+ # Public API — delegates to active provider
272
+ # ---------------------------------------------------------------------------
273
+
274
+ def index_episode(
275
+ episode_id: str,
276
+ prompt: str,
277
+ enriched_prompt: str = "",
278
+ tags: str = "",
279
+ title: str = "",
280
+ ) -> None:
281
+ """Insert an episode into the active backend (no-op if already present).
282
+
283
+ Parameters
284
+ ----------
285
+ episode_id:
286
+ Unique identifier for the episode.
287
+ prompt:
288
+ Original user prompt text.
289
+ enriched_prompt:
290
+ Expanded / enriched version of the prompt (may be empty).
291
+ tags:
292
+ Space- or comma-separated tags string (may be empty).
293
+ title:
294
+ Short title for the episode (may be empty).
295
+ """
296
+ _provider.index(
297
+ episode_id,
298
+ prompt,
299
+ enriched_prompt=enriched_prompt,
300
+ tags=tags,
301
+ title=title,
302
+ )
303
+
304
+
305
+ def search(query: str, max_results: int = 10) -> List[Dict]:
306
+ """Search the active backend using the configured ranking strategy.
307
+
308
+ Parameters
309
+ ----------
310
+ query:
311
+ Free-text search query.
312
+ max_results:
313
+ Maximum number of results to return (default: 10).
314
+
315
+ Returns
316
+ -------
317
+ list of dict
318
+ Each dict contains at minimum ``{"episode_id": str}``. FTS5 backend
319
+ also includes ``{"rank": float}``. Returns empty list on error.
320
+ """
321
+ return _provider.search(query, max_results)
322
+
323
+
324
+ def count() -> int:
325
+ """Return the total number of episodes indexed in the active backend.
326
+
327
+ Returns
328
+ -------
329
+ int
330
+ Row count, or 0 on any error.
331
+ """
332
+ return _provider.count()
333
+
334
+
335
+ def get_backend() -> str:
336
+ """Return the active search backend identifier.
337
+
338
+ Returns
339
+ -------
340
+ str
341
+ ``"chroma"`` if ChromaProvider is active, ``"fts5"`` otherwise.
342
+ """
343
+ if isinstance(_provider, ChromaProvider):
344
+ return "chroma"
345
+ return "fts5"
346
+
347
+
348
+ def has_engram() -> bool:
349
+ """Check whether the engram binary is available on PATH.
350
+
351
+ Returns
352
+ -------
353
+ bool
354
+ True if ``engram`` is found via shutil.which, False otherwise.
355
+ Never raises an exception.
356
+ """
357
+ try:
358
+ return shutil.which("engram") is not None
359
+ except Exception: # noqa: BLE001
360
+ return False
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env python3
2
+ """Retroactive transcript analysis: analyze .output files and persist metrics.
3
+
4
+ Reads all .output transcript files from a session's tasks directory,
5
+ runs analyze() and compute_compliance_score() from transcript_analyzer,
6
+ and appends non-empty results as JSON lines to the episodic-memory metrics file.
7
+ """
8
+
9
+ import json
10
+ import sys
11
+ from datetime import datetime, timezone
12
+ from pathlib import Path
13
+
14
+ # Ensure the hooks package is importable
15
+ PLUGIN_ROOT = Path(__file__).resolve().parent.parent
16
+ sys.path.insert(0, str(PLUGIN_ROOT))
17
+
18
+ from hooks.modules.agents.transcript_analyzer import analyze, compute_compliance_score
19
+
20
+ SESSION_ID = "5da6ec0a-5471-4af9-b301-794748b21f62"
21
+ TASKS_DIR = Path(
22
+ f"/tmp/claude-1000/-home-jaguilar-aaxis-qxo/{SESSION_ID}/tasks"
23
+ )
24
+ METRICS_FILE = Path(
25
+ "/home/jaguilar/aaxis/qxo/.claude/project-context"
26
+ "/workflow-episodic-memory/metrics.jsonl"
27
+ )
28
+
29
+
30
+ def main() -> None:
31
+ if not TASKS_DIR.exists():
32
+ print(f"Tasks directory not found: {TASKS_DIR}")
33
+ sys.exit(1)
34
+
35
+ output_files = sorted(TASKS_DIR.glob("*.output"))
36
+ if not output_files:
37
+ print("No .output files found.")
38
+ sys.exit(0)
39
+
40
+ METRICS_FILE.parent.mkdir(parents=True, exist_ok=True)
41
+
42
+ persisted = 0
43
+
44
+ with open(METRICS_FILE, "a") as f:
45
+ for output_path in output_files:
46
+ task_id = output_path.stem # filename without .output
47
+
48
+ analysis = analyze(str(output_path))
49
+
50
+ if analysis.api_call_count == 0:
51
+ continue
52
+
53
+ score = compute_compliance_score(analysis, True, False, 0.5)
54
+
55
+ timestamp = analysis.first_timestamp or datetime.now(
56
+ timezone.utc
57
+ ).isoformat()
58
+
59
+ entry = {
60
+ "timestamp": timestamp,
61
+ "session_id": SESSION_ID,
62
+ "task_id": task_id,
63
+ "agent": "retroactive-analysis",
64
+ "source": "transcript_analyzer_retroactive",
65
+ "input_tokens": analysis.input_tokens,
66
+ "cache_creation_tokens": analysis.cache_creation_tokens,
67
+ "cache_read_tokens": analysis.cache_read_tokens,
68
+ "output_tokens": analysis.output_tokens,
69
+ "duration_ms": analysis.duration_ms,
70
+ "tool_call_count": analysis.tool_call_count,
71
+ "skills_injected": analysis.skills_injected,
72
+ "model_used": analysis.model,
73
+ "compliance_score": score.total,
74
+ "compliance_grade": score.grade,
75
+ "api_call_count": analysis.api_call_count,
76
+ }
77
+
78
+ f.write(json.dumps(entry, separators=(",", ":")) + "\n")
79
+ persisted += 1
80
+
81
+ print(f"Persisted {persisted} entries to {METRICS_FILE}")
82
+
83
+
84
+ if __name__ == "__main__":
85
+ main()
@@ -0,0 +1 @@
1
+ # Review tools for pending update management
@@ -0,0 +1,157 @@
1
+ """Review engine for managing pending context update suggestions.
2
+
3
+ This module provides the review logic for pending update suggestions,
4
+ including listing, approving, rejecting, and viewing statistics of
5
+ updates discovered by agents.
6
+ """
7
+
8
+ import json
9
+ import sys
10
+ from pathlib import Path
11
+ from typing import Optional
12
+
13
+ # Import PendingUpdateStore from the context module
14
+ sys.path.insert(0, str(Path(__file__).parent.parent))
15
+ from context.pending_updates import PendingUpdateStore
16
+
17
+
18
+ def review_pending(
19
+ action: str,
20
+ update_id: Optional[str] = None,
21
+ context_path: Optional[Path] = None,
22
+ store: Optional["PendingUpdateStore"] = None
23
+ ) -> dict:
24
+ """Execute a review action on pending updates.
25
+
26
+ Args:
27
+ action: One of "list", "approve", "reject", "stats"
28
+ update_id: Required for approve/reject actions
29
+ context_path: Optional path to project-context.json (for apply)
30
+ store: Optional PendingUpdateStore instance (for testing)
31
+
32
+ Returns:
33
+ dict: Action-specific results
34
+
35
+ Raises:
36
+ ValueError: If action is invalid or required parameters are missing
37
+ """
38
+ valid_actions = {"list", "approve", "reject", "stats"}
39
+
40
+ if action not in valid_actions:
41
+ raise ValueError(
42
+ f"Invalid action: {action}. Must be one of: {', '.join(sorted(valid_actions))}"
43
+ )
44
+
45
+ # Validate update_id requirement for approve/reject
46
+ if action in {"approve", "reject"} and not update_id:
47
+ raise ValueError(f"update_id is required for {action} action")
48
+
49
+ # Use provided store or create default
50
+ if store is None:
51
+ store = PendingUpdateStore()
52
+
53
+ # Execute action
54
+ if action == "list":
55
+ updates = store.list_pending()
56
+ # Convert dataclass instances to dicts for JSON serialization
57
+ updates_dict = [
58
+ {
59
+ "update_id": u.update_id,
60
+ "category": u.category,
61
+ "target_section": u.target_section,
62
+ "summary": u.summary,
63
+ "confidence": u.confidence,
64
+ "source_agent": u.source_agent,
65
+ "status": u.status,
66
+ "created_at": u.created_at,
67
+ "seen_count": u.seen_count,
68
+ }
69
+ for u in updates
70
+ ]
71
+ return {
72
+ "action": "list",
73
+ "updates": updates_dict,
74
+ "count": len(updates_dict)
75
+ }
76
+
77
+ elif action == "approve":
78
+ # Approve the update
79
+ store.approve(update_id)
80
+
81
+ # Apply the update to project-context.json
82
+ result = store.apply(update_id, context_path)
83
+
84
+ return {
85
+ "action": "approve",
86
+ "update_id": update_id,
87
+ "applied": result.get("success", False),
88
+ "result": result
89
+ }
90
+
91
+ elif action == "reject":
92
+ store.reject(update_id)
93
+ return {
94
+ "action": "reject",
95
+ "update_id": update_id,
96
+ "success": True
97
+ }
98
+
99
+ elif action == "stats":
100
+ statistics = store.get_statistics()
101
+ return {
102
+ "action": "stats",
103
+ "statistics": statistics
104
+ }
105
+
106
+
107
+ def main():
108
+ """CLI entry point for review operations."""
109
+ import argparse
110
+
111
+ parser = argparse.ArgumentParser(
112
+ description="Review pending context updates"
113
+ )
114
+ parser.add_argument(
115
+ "action",
116
+ choices=["list", "approve", "reject", "stats"],
117
+ help="Action to perform"
118
+ )
119
+ parser.add_argument(
120
+ "--update-id",
121
+ help="Update ID (required for approve/reject)"
122
+ )
123
+ parser.add_argument(
124
+ "--context-path",
125
+ help="Path to project-context.json"
126
+ )
127
+ parser.add_argument(
128
+ "--json",
129
+ action="store_true",
130
+ help="Output as JSON (default behavior)"
131
+ )
132
+
133
+ args = parser.parse_args()
134
+
135
+ try:
136
+ # Execute review action
137
+ result = review_pending(
138
+ args.action,
139
+ args.update_id,
140
+ Path(args.context_path) if args.context_path else None
141
+ )
142
+
143
+ # Output result as JSON
144
+ print(json.dumps(result, indent=2))
145
+
146
+ except Exception as e:
147
+ # Output error as JSON
148
+ error_result = {
149
+ "error": str(e),
150
+ "action": args.action
151
+ }
152
+ print(json.dumps(error_result, indent=2))
153
+ sys.exit(1)
154
+
155
+
156
+ if __name__ == "__main__":
157
+ main()
@@ -0,0 +1,35 @@
1
+ """
2
+ Scan Module: Modular project scanner for gaia-ops
3
+
4
+ This module provides a pluggable scanner system that detects project stack,
5
+ infrastructure, git configuration, tools, orchestration, and environment.
6
+ Each scanner is a pure function (filesystem path -> JSON sections) that runs
7
+ independently and in parallel. The system produces an agnostic project-context.json
8
+ schema that works for any project type.
9
+
10
+ Main components:
11
+ - BaseScanner: Abstract base class for scanner modules
12
+ - ScannerRegistry: Auto-discovery registry for scanner modules
13
+ - ScanOrchestrator: Parallel scanner execution and result aggregation
14
+ - ScanConfig: Scanner configuration and tool definitions
15
+ """
16
+
17
+ import json as _json
18
+ from pathlib import Path as _Path
19
+
20
+
21
+ def _read_version() -> str:
22
+ """Read version from package.json (single source of truth)."""
23
+ try:
24
+ pkg_path = _Path(__file__).resolve().parent.parent.parent / "package.json"
25
+ with open(pkg_path) as f:
26
+ return _json.load(f)["version"]
27
+ except Exception:
28
+ return "unknown"
29
+
30
+
31
+ __version__ = _read_version()
32
+
33
+ __all__ = [
34
+ "__version__",
35
+ ]