@jaguilar87/gaia-ops 4.4.0 → 4.7.2

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 (371) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/.claude-plugin/plugin.json +12 -3
  3. package/ARCHITECTURE.md +9 -8
  4. package/CHANGELOG.md +34 -0
  5. package/README.md +43 -11
  6. package/agents/terraform-architect.md +1 -1
  7. package/bin/README.md +2 -2
  8. package/bin/gaia-doctor.js +18 -5
  9. package/bin/gaia-history.js +0 -1
  10. package/bin/gaia-metrics.js +2 -2
  11. package/bin/gaia-scan.py +23 -1
  12. package/bin/gaia-update.js +346 -54
  13. package/bin/pre-publish-validate.js +33 -10
  14. package/commands/gaia.md +37 -0
  15. package/config/README.md +3 -9
  16. package/config/context-contracts.json +47 -15
  17. package/config/surface-routing.json +9 -1
  18. package/dist/gaia-ops/.claude-plugin/plugin.json +22 -0
  19. package/dist/gaia-ops/agents/cloud-troubleshooter.md +73 -0
  20. package/dist/gaia-ops/agents/devops-developer.md +57 -0
  21. package/dist/gaia-ops/agents/gaia-system.md +58 -0
  22. package/dist/gaia-ops/agents/gitops-operator.md +60 -0
  23. package/dist/gaia-ops/agents/speckit-planner.md +71 -0
  24. package/dist/gaia-ops/agents/terraform-architect.md +60 -0
  25. package/dist/gaia-ops/commands/gaia.md +37 -0
  26. package/dist/gaia-ops/config/README.md +58 -0
  27. package/dist/gaia-ops/config/cloud/aws.json +140 -0
  28. package/dist/gaia-ops/config/cloud/gcp.json +145 -0
  29. package/dist/gaia-ops/config/context-contracts.json +131 -0
  30. package/dist/gaia-ops/config/git_standards.json +72 -0
  31. package/dist/gaia-ops/config/surface-routing.json +197 -0
  32. package/dist/gaia-ops/config/universal-rules.json +10 -0
  33. package/dist/gaia-ops/hooks/adapters/__init__.py +52 -0
  34. package/dist/gaia-ops/hooks/adapters/base.py +219 -0
  35. package/dist/gaia-ops/hooks/adapters/channel.py +17 -0
  36. package/dist/gaia-ops/hooks/adapters/claude_code.py +1477 -0
  37. package/dist/gaia-ops/hooks/adapters/types.py +194 -0
  38. package/dist/gaia-ops/hooks/adapters/utils.py +25 -0
  39. package/dist/gaia-ops/hooks/hooks.json +126 -0
  40. package/dist/gaia-ops/hooks/modules/__init__.py +15 -0
  41. package/dist/gaia-ops/hooks/modules/agents/__init__.py +29 -0
  42. package/dist/gaia-ops/hooks/modules/agents/contract_validator.py +647 -0
  43. package/dist/gaia-ops/hooks/modules/agents/response_contract.py +496 -0
  44. package/dist/gaia-ops/hooks/modules/agents/skill_injection_verifier.py +124 -0
  45. package/dist/gaia-ops/hooks/modules/agents/task_info_builder.py +74 -0
  46. package/dist/gaia-ops/hooks/modules/agents/transcript_analyzer.py +458 -0
  47. package/dist/gaia-ops/hooks/modules/agents/transcript_reader.py +152 -0
  48. package/dist/gaia-ops/hooks/modules/audit/__init__.py +28 -0
  49. package/dist/gaia-ops/hooks/modules/audit/event_detector.py +168 -0
  50. package/dist/gaia-ops/hooks/modules/audit/logger.py +131 -0
  51. package/dist/gaia-ops/hooks/modules/audit/metrics.py +134 -0
  52. package/dist/gaia-ops/hooks/modules/audit/workflow_auditor.py +576 -0
  53. package/dist/gaia-ops/hooks/modules/audit/workflow_recorder.py +296 -0
  54. package/dist/gaia-ops/hooks/modules/context/__init__.py +11 -0
  55. package/dist/gaia-ops/hooks/modules/context/anchor_tracker.py +317 -0
  56. package/dist/gaia-ops/hooks/modules/context/compact_context_builder.py +215 -0
  57. package/dist/gaia-ops/hooks/modules/context/context_cache.py +129 -0
  58. package/dist/gaia-ops/hooks/modules/context/context_freshness.py +145 -0
  59. package/dist/gaia-ops/hooks/modules/context/context_injector.py +427 -0
  60. package/dist/gaia-ops/hooks/modules/context/context_writer.py +518 -0
  61. package/dist/gaia-ops/hooks/modules/context/contracts_loader.py +161 -0
  62. package/dist/gaia-ops/hooks/modules/core/__init__.py +40 -0
  63. package/dist/gaia-ops/hooks/modules/core/hook_entry.py +78 -0
  64. package/dist/gaia-ops/hooks/modules/core/paths.py +160 -0
  65. package/dist/gaia-ops/hooks/modules/core/plugin_mode.py +149 -0
  66. package/dist/gaia-ops/hooks/modules/core/plugin_setup.py +558 -0
  67. package/dist/gaia-ops/hooks/modules/core/state.py +179 -0
  68. package/dist/gaia-ops/hooks/modules/core/stdin.py +24 -0
  69. package/dist/gaia-ops/hooks/modules/events/__init__.py +1 -0
  70. package/dist/gaia-ops/hooks/modules/events/event_writer.py +210 -0
  71. package/dist/gaia-ops/hooks/modules/identity/__init__.py +0 -0
  72. package/dist/gaia-ops/hooks/modules/identity/identity_provider.py +21 -0
  73. package/dist/gaia-ops/hooks/modules/identity/ops_identity.py +34 -0
  74. package/dist/gaia-ops/hooks/modules/identity/security_identity.py +10 -0
  75. package/dist/gaia-ops/hooks/modules/memory/__init__.py +8 -0
  76. package/dist/gaia-ops/hooks/modules/memory/episode_writer.py +227 -0
  77. package/dist/gaia-ops/hooks/modules/orchestrator/__init__.py +1 -0
  78. package/dist/gaia-ops/hooks/modules/orchestrator/delegate_mode.py +128 -0
  79. package/dist/gaia-ops/hooks/modules/scanning/__init__.py +8 -0
  80. package/dist/gaia-ops/hooks/modules/scanning/scan_trigger.py +84 -0
  81. package/dist/gaia-ops/hooks/modules/security/__init__.py +89 -0
  82. package/dist/gaia-ops/hooks/modules/security/approval_cleanup.py +87 -0
  83. package/dist/gaia-ops/hooks/modules/security/approval_constants.py +23 -0
  84. package/dist/gaia-ops/hooks/modules/security/approval_grants.py +912 -0
  85. package/dist/gaia-ops/hooks/modules/security/approval_messages.py +71 -0
  86. package/dist/gaia-ops/hooks/modules/security/approval_scopes.py +153 -0
  87. package/dist/gaia-ops/hooks/modules/security/blocked_commands.py +584 -0
  88. package/dist/gaia-ops/hooks/modules/security/blocked_message_formatter.py +86 -0
  89. package/dist/gaia-ops/hooks/modules/security/command_semantics.py +130 -0
  90. package/dist/gaia-ops/hooks/modules/security/gitops_validator.py +179 -0
  91. package/dist/gaia-ops/hooks/modules/security/mutative_verbs.py +850 -0
  92. package/dist/gaia-ops/hooks/modules/security/prompt_validator.py +40 -0
  93. package/dist/gaia-ops/hooks/modules/security/tiers.py +196 -0
  94. package/dist/gaia-ops/hooks/modules/session/__init__.py +10 -0
  95. package/dist/gaia-ops/hooks/modules/session/session_context_writer.py +100 -0
  96. package/dist/gaia-ops/hooks/modules/session/session_event_injector.py +158 -0
  97. package/dist/gaia-ops/hooks/modules/session/session_manager.py +31 -0
  98. package/dist/gaia-ops/hooks/modules/tools/__init__.py +25 -0
  99. package/dist/gaia-ops/hooks/modules/tools/bash_validator.py +708 -0
  100. package/dist/gaia-ops/hooks/modules/tools/cloud_pipe_validator.py +181 -0
  101. package/dist/gaia-ops/hooks/modules/tools/hook_response.py +55 -0
  102. package/dist/gaia-ops/hooks/modules/tools/shell_parser.py +227 -0
  103. package/dist/gaia-ops/hooks/modules/tools/task_validator.py +283 -0
  104. package/dist/gaia-ops/hooks/modules/validation/__init__.py +23 -0
  105. package/dist/gaia-ops/hooks/modules/validation/commit_validator.py +380 -0
  106. package/dist/gaia-ops/hooks/post_compact.py +43 -0
  107. package/dist/gaia-ops/hooks/post_tool_use.py +54 -0
  108. package/dist/gaia-ops/hooks/pre_tool_use.py +383 -0
  109. package/dist/gaia-ops/hooks/session_start.py +69 -0
  110. package/dist/gaia-ops/hooks/stop_hook.py +69 -0
  111. package/dist/gaia-ops/hooks/subagent_start.py +71 -0
  112. package/dist/gaia-ops/hooks/subagent_stop.py +288 -0
  113. package/dist/gaia-ops/hooks/task_completed.py +70 -0
  114. package/dist/gaia-ops/hooks/user_prompt_submit.py +177 -0
  115. package/dist/gaia-ops/settings.json +72 -0
  116. package/dist/gaia-ops/skills/README.md +109 -0
  117. package/dist/gaia-ops/skills/agent-protocol/SKILL.md +105 -0
  118. package/dist/gaia-ops/skills/agent-protocol/examples.md +170 -0
  119. package/dist/gaia-ops/skills/agent-response/SKILL.md +53 -0
  120. package/dist/gaia-ops/skills/approval/SKILL.md +85 -0
  121. package/dist/gaia-ops/skills/approval/examples.md +140 -0
  122. package/dist/gaia-ops/skills/approval/reference.md +57 -0
  123. package/dist/gaia-ops/skills/command-execution/SKILL.md +64 -0
  124. package/dist/gaia-ops/skills/command-execution/reference.md +83 -0
  125. package/dist/gaia-ops/skills/context-updater/SKILL.md +76 -0
  126. package/dist/gaia-ops/skills/context-updater/examples.md +71 -0
  127. package/dist/gaia-ops/skills/developer-patterns/SKILL.md +93 -0
  128. package/dist/gaia-ops/skills/developer-patterns/reference.md +112 -0
  129. package/dist/gaia-ops/skills/execution/SKILL.md +66 -0
  130. package/dist/gaia-ops/skills/fast-queries/SKILL.md +47 -0
  131. package/dist/gaia-ops/skills/gaia-patterns/SKILL.md +92 -0
  132. package/dist/gaia-ops/skills/gaia-patterns/reference.md +22 -0
  133. package/dist/gaia-ops/skills/git-conventions/SKILL.md +48 -0
  134. package/dist/gaia-ops/skills/gitops-patterns/SKILL.md +73 -0
  135. package/dist/gaia-ops/skills/gitops-patterns/reference.md +183 -0
  136. package/dist/gaia-ops/skills/investigation/SKILL.md +77 -0
  137. package/dist/gaia-ops/skills/orchestrator-approval/SKILL.md +64 -0
  138. package/dist/gaia-ops/skills/reference.md +134 -0
  139. package/dist/gaia-ops/skills/security-tiers/SKILL.md +61 -0
  140. package/dist/gaia-ops/skills/security-tiers/destructive-commands-reference.md +623 -0
  141. package/dist/gaia-ops/skills/security-tiers/reference.md +39 -0
  142. package/dist/gaia-ops/skills/skill-creation/SKILL.md +119 -0
  143. package/dist/gaia-ops/skills/specification/SKILL.md +186 -0
  144. package/dist/gaia-ops/skills/speckit-workflow/SKILL.md +165 -0
  145. package/dist/gaia-ops/skills/speckit-workflow/reference.md +117 -0
  146. package/dist/gaia-ops/skills/terraform-patterns/SKILL.md +63 -0
  147. package/dist/gaia-ops/skills/terraform-patterns/reference.md +93 -0
  148. package/dist/gaia-ops/speckit/README.md +516 -0
  149. package/dist/gaia-ops/speckit/scripts/.gitkeep +0 -0
  150. package/dist/gaia-ops/speckit/templates/adr-template.md +118 -0
  151. package/dist/gaia-ops/speckit/templates/agent-file-template.md +23 -0
  152. package/dist/gaia-ops/speckit/templates/plan-template.md +227 -0
  153. package/dist/gaia-ops/speckit/templates/spec-template.md +140 -0
  154. package/dist/gaia-ops/speckit/templates/tasks-template.md +257 -0
  155. package/dist/gaia-ops/tools/context/README.md +132 -0
  156. package/dist/gaia-ops/tools/context/__init__.py +42 -0
  157. package/dist/gaia-ops/tools/context/_paths.py +20 -0
  158. package/dist/gaia-ops/tools/context/context_provider.py +476 -0
  159. package/dist/gaia-ops/tools/context/context_section_reader.py +330 -0
  160. package/dist/gaia-ops/tools/context/deep_merge.py +159 -0
  161. package/dist/gaia-ops/tools/context/pending_updates.py +760 -0
  162. package/dist/gaia-ops/tools/context/surface_router.py +278 -0
  163. package/dist/gaia-ops/tools/fast-queries/README.md +65 -0
  164. package/dist/gaia-ops/tools/fast-queries/__init__.py +30 -0
  165. package/dist/gaia-ops/tools/fast-queries/appservices/quicktriage_devops_developer.sh +75 -0
  166. package/dist/gaia-ops/tools/fast-queries/cloud/aws/quicktriage_aws_troubleshooter.sh +32 -0
  167. package/dist/gaia-ops/tools/fast-queries/cloud/gcp/quicktriage_gcp_troubleshooter.sh +88 -0
  168. package/dist/gaia-ops/tools/fast-queries/gitops/quicktriage_gitops_operator.sh +48 -0
  169. package/dist/gaia-ops/tools/fast-queries/run_triage.sh +59 -0
  170. package/dist/gaia-ops/tools/fast-queries/terraform/quicktriage_terraform_architect.sh +80 -0
  171. package/dist/gaia-ops/tools/gaia_simulator/__init__.py +33 -0
  172. package/dist/gaia-ops/tools/gaia_simulator/cli.py +354 -0
  173. package/dist/gaia-ops/tools/gaia_simulator/extractor.py +457 -0
  174. package/dist/gaia-ops/tools/gaia_simulator/reporter.py +258 -0
  175. package/dist/gaia-ops/tools/gaia_simulator/routing_simulator.py +334 -0
  176. package/dist/gaia-ops/tools/gaia_simulator/runner.py +539 -0
  177. package/dist/gaia-ops/tools/gaia_simulator/skills_mapper.py +262 -0
  178. package/dist/gaia-ops/tools/memory/README.md +0 -0
  179. package/dist/gaia-ops/tools/memory/__init__.py +20 -0
  180. package/dist/gaia-ops/tools/memory/episodic.py +1196 -0
  181. package/dist/gaia-ops/tools/persist_transcript_analysis.py +85 -0
  182. package/dist/gaia-ops/tools/review/__init__.py +1 -0
  183. package/dist/gaia-ops/tools/review/review_engine.py +157 -0
  184. package/dist/gaia-ops/tools/scan/__init__.py +35 -0
  185. package/dist/gaia-ops/tools/scan/config.py +247 -0
  186. package/dist/gaia-ops/tools/scan/merge.py +212 -0
  187. package/dist/gaia-ops/tools/scan/orchestrator.py +549 -0
  188. package/dist/gaia-ops/tools/scan/registry.py +127 -0
  189. package/dist/gaia-ops/tools/scan/scanners/__init__.py +18 -0
  190. package/dist/gaia-ops/tools/scan/scanners/base.py +137 -0
  191. package/dist/gaia-ops/tools/scan/scanners/environment.py +324 -0
  192. package/dist/gaia-ops/tools/scan/scanners/git.py +570 -0
  193. package/dist/gaia-ops/tools/scan/scanners/infrastructure.py +875 -0
  194. package/dist/gaia-ops/tools/scan/scanners/orchestration.py +600 -0
  195. package/dist/gaia-ops/tools/scan/scanners/stack.py +1085 -0
  196. package/dist/gaia-ops/tools/scan/scanners/tools.py +260 -0
  197. package/dist/gaia-ops/tools/scan/setup.py +753 -0
  198. package/dist/gaia-ops/tools/scan/tests/__init__.py +1 -0
  199. package/dist/gaia-ops/tools/scan/tests/conftest.py +796 -0
  200. package/dist/gaia-ops/tools/scan/tests/test_environment.py +323 -0
  201. package/dist/gaia-ops/tools/scan/tests/test_git.py +419 -0
  202. package/dist/gaia-ops/tools/scan/tests/test_infrastructure.py +382 -0
  203. package/dist/gaia-ops/tools/scan/tests/test_integration.py +920 -0
  204. package/dist/gaia-ops/tools/scan/tests/test_merge.py +269 -0
  205. package/dist/gaia-ops/tools/scan/tests/test_orchestration.py +304 -0
  206. package/dist/gaia-ops/tools/scan/tests/test_stack.py +604 -0
  207. package/dist/gaia-ops/tools/scan/tests/test_tools.py +349 -0
  208. package/dist/gaia-ops/tools/scan/ui.py +624 -0
  209. package/dist/gaia-ops/tools/scan/verify.py +266 -0
  210. package/dist/gaia-ops/tools/scan/walk.py +118 -0
  211. package/dist/gaia-ops/tools/scan/workspace.py +85 -0
  212. package/dist/gaia-ops/tools/validation/README.md +244 -0
  213. package/dist/gaia-ops/tools/validation/__init__.py +17 -0
  214. package/dist/gaia-ops/tools/validation/approval_gate.py +321 -0
  215. package/dist/gaia-ops/tools/validation/validate_skills.py +189 -0
  216. package/dist/gaia-security/.claude-plugin/plugin.json +22 -0
  217. package/dist/gaia-security/config/universal-rules.json +10 -0
  218. package/dist/gaia-security/hooks/adapters/__init__.py +52 -0
  219. package/dist/gaia-security/hooks/adapters/base.py +219 -0
  220. package/dist/gaia-security/hooks/adapters/channel.py +17 -0
  221. package/dist/gaia-security/hooks/adapters/claude_code.py +1477 -0
  222. package/dist/gaia-security/hooks/adapters/types.py +194 -0
  223. package/dist/gaia-security/hooks/adapters/utils.py +25 -0
  224. package/dist/gaia-security/hooks/hooks.json +57 -0
  225. package/dist/gaia-security/hooks/modules/__init__.py +15 -0
  226. package/dist/gaia-security/hooks/modules/agents/__init__.py +29 -0
  227. package/dist/gaia-security/hooks/modules/agents/contract_validator.py +647 -0
  228. package/dist/gaia-security/hooks/modules/agents/response_contract.py +496 -0
  229. package/dist/gaia-security/hooks/modules/agents/skill_injection_verifier.py +124 -0
  230. package/dist/gaia-security/hooks/modules/agents/task_info_builder.py +74 -0
  231. package/dist/gaia-security/hooks/modules/agents/transcript_analyzer.py +458 -0
  232. package/dist/gaia-security/hooks/modules/agents/transcript_reader.py +152 -0
  233. package/dist/gaia-security/hooks/modules/audit/__init__.py +28 -0
  234. package/dist/gaia-security/hooks/modules/audit/event_detector.py +168 -0
  235. package/dist/gaia-security/hooks/modules/audit/logger.py +131 -0
  236. package/dist/gaia-security/hooks/modules/audit/metrics.py +134 -0
  237. package/dist/gaia-security/hooks/modules/audit/workflow_auditor.py +576 -0
  238. package/dist/gaia-security/hooks/modules/audit/workflow_recorder.py +296 -0
  239. package/dist/gaia-security/hooks/modules/context/__init__.py +11 -0
  240. package/dist/gaia-security/hooks/modules/context/anchor_tracker.py +317 -0
  241. package/dist/gaia-security/hooks/modules/context/compact_context_builder.py +215 -0
  242. package/dist/gaia-security/hooks/modules/context/context_cache.py +129 -0
  243. package/dist/gaia-security/hooks/modules/context/context_freshness.py +145 -0
  244. package/dist/gaia-security/hooks/modules/context/context_injector.py +427 -0
  245. package/dist/gaia-security/hooks/modules/context/context_writer.py +518 -0
  246. package/dist/gaia-security/hooks/modules/context/contracts_loader.py +161 -0
  247. package/dist/gaia-security/hooks/modules/core/__init__.py +40 -0
  248. package/dist/gaia-security/hooks/modules/core/hook_entry.py +78 -0
  249. package/dist/gaia-security/hooks/modules/core/paths.py +160 -0
  250. package/dist/gaia-security/hooks/modules/core/plugin_mode.py +149 -0
  251. package/dist/gaia-security/hooks/modules/core/plugin_setup.py +558 -0
  252. package/dist/gaia-security/hooks/modules/core/state.py +179 -0
  253. package/dist/gaia-security/hooks/modules/core/stdin.py +24 -0
  254. package/dist/gaia-security/hooks/modules/events/__init__.py +1 -0
  255. package/dist/gaia-security/hooks/modules/events/event_writer.py +210 -0
  256. package/dist/gaia-security/hooks/modules/identity/__init__.py +0 -0
  257. package/dist/gaia-security/hooks/modules/identity/identity_provider.py +21 -0
  258. package/dist/gaia-security/hooks/modules/identity/ops_identity.py +34 -0
  259. package/dist/gaia-security/hooks/modules/identity/security_identity.py +10 -0
  260. package/dist/gaia-security/hooks/modules/memory/__init__.py +8 -0
  261. package/dist/gaia-security/hooks/modules/memory/episode_writer.py +227 -0
  262. package/dist/gaia-security/hooks/modules/orchestrator/__init__.py +1 -0
  263. package/dist/gaia-security/hooks/modules/orchestrator/delegate_mode.py +128 -0
  264. package/dist/gaia-security/hooks/modules/scanning/__init__.py +8 -0
  265. package/dist/gaia-security/hooks/modules/scanning/scan_trigger.py +84 -0
  266. package/dist/gaia-security/hooks/modules/security/__init__.py +89 -0
  267. package/dist/gaia-security/hooks/modules/security/approval_cleanup.py +87 -0
  268. package/dist/gaia-security/hooks/modules/security/approval_constants.py +23 -0
  269. package/dist/gaia-security/hooks/modules/security/approval_grants.py +912 -0
  270. package/dist/gaia-security/hooks/modules/security/approval_messages.py +71 -0
  271. package/dist/gaia-security/hooks/modules/security/approval_scopes.py +153 -0
  272. package/dist/gaia-security/hooks/modules/security/blocked_commands.py +584 -0
  273. package/dist/gaia-security/hooks/modules/security/blocked_message_formatter.py +86 -0
  274. package/dist/gaia-security/hooks/modules/security/command_semantics.py +130 -0
  275. package/dist/gaia-security/hooks/modules/security/gitops_validator.py +179 -0
  276. package/dist/gaia-security/hooks/modules/security/mutative_verbs.py +850 -0
  277. package/dist/gaia-security/hooks/modules/security/prompt_validator.py +40 -0
  278. package/dist/gaia-security/hooks/modules/security/tiers.py +196 -0
  279. package/dist/gaia-security/hooks/modules/session/__init__.py +10 -0
  280. package/dist/gaia-security/hooks/modules/session/session_context_writer.py +100 -0
  281. package/dist/gaia-security/hooks/modules/session/session_event_injector.py +158 -0
  282. package/dist/gaia-security/hooks/modules/session/session_manager.py +31 -0
  283. package/dist/gaia-security/hooks/modules/tools/__init__.py +25 -0
  284. package/dist/gaia-security/hooks/modules/tools/bash_validator.py +708 -0
  285. package/dist/gaia-security/hooks/modules/tools/cloud_pipe_validator.py +181 -0
  286. package/dist/gaia-security/hooks/modules/tools/hook_response.py +55 -0
  287. package/dist/gaia-security/hooks/modules/tools/shell_parser.py +227 -0
  288. package/dist/gaia-security/hooks/modules/tools/task_validator.py +283 -0
  289. package/dist/gaia-security/hooks/modules/validation/__init__.py +23 -0
  290. package/dist/gaia-security/hooks/modules/validation/commit_validator.py +380 -0
  291. package/dist/gaia-security/hooks/post_tool_use.py +54 -0
  292. package/dist/gaia-security/hooks/pre_tool_use.py +383 -0
  293. package/dist/gaia-security/hooks/session_start.py +69 -0
  294. package/dist/gaia-security/hooks/stop_hook.py +69 -0
  295. package/dist/gaia-security/hooks/user_prompt_submit.py +177 -0
  296. package/dist/gaia-security/settings.json +58 -0
  297. package/git-hooks/commit-msg +41 -0
  298. package/hooks/README.md +8 -6
  299. package/hooks/adapters/channel.py +0 -25
  300. package/hooks/adapters/claude_code.py +364 -125
  301. package/hooks/elicitation_result.py +132 -0
  302. package/hooks/hooks.json +10 -1
  303. package/hooks/modules/README.md +3 -2
  304. package/hooks/modules/agents/contract_validator.py +3 -51
  305. package/hooks/modules/agents/response_contract.py +4 -8
  306. package/hooks/modules/agents/transcript_reader.py +4 -5
  307. package/hooks/modules/audit/__init__.py +4 -6
  308. package/hooks/modules/audit/event_detector.py +0 -2
  309. package/hooks/modules/audit/metrics.py +108 -187
  310. package/hooks/modules/audit/workflow_auditor.py +0 -4
  311. package/hooks/modules/audit/workflow_recorder.py +0 -5
  312. package/hooks/modules/context/compact_context_builder.py +1 -0
  313. package/hooks/modules/context/context_cache.py +129 -0
  314. package/hooks/modules/context/context_injector.py +18 -40
  315. package/hooks/modules/context/context_writer.py +1 -25
  316. package/hooks/modules/context/contracts_loader.py +7 -10
  317. package/hooks/modules/core/hook_entry.py +1 -0
  318. package/hooks/modules/core/paths.py +12 -13
  319. package/hooks/modules/core/plugin_mode.py +74 -4
  320. package/hooks/modules/core/plugin_setup.py +395 -23
  321. package/hooks/modules/events/__init__.py +1 -0
  322. package/hooks/modules/events/event_writer.py +210 -0
  323. package/hooks/modules/identity/ops_identity.py +18 -27
  324. package/hooks/modules/memory/episode_writer.py +1 -6
  325. package/hooks/modules/orchestrator/__init__.py +1 -0
  326. package/hooks/modules/orchestrator/delegate_mode.py +128 -0
  327. package/hooks/modules/security/__init__.py +2 -4
  328. package/hooks/modules/security/approval_constants.py +5 -1
  329. package/hooks/modules/security/approval_grants.py +189 -6
  330. package/hooks/modules/security/approval_messages.py +9 -21
  331. package/hooks/modules/security/blocked_commands.py +98 -34
  332. package/hooks/modules/security/command_semantics.py +0 -4
  333. package/hooks/modules/security/gitops_validator.py +1 -11
  334. package/hooks/modules/security/mutative_verbs.py +179 -38
  335. package/hooks/modules/security/tiers.py +1 -19
  336. package/hooks/modules/session/session_event_injector.py +1 -25
  337. package/hooks/modules/tools/bash_validator.py +310 -94
  338. package/hooks/modules/tools/shell_parser.py +0 -1
  339. package/hooks/modules/tools/task_validator.py +9 -29
  340. package/hooks/post_tool_use.py +0 -72
  341. package/hooks/pre_tool_use.py +42 -102
  342. package/hooks/session_start.py +4 -2
  343. package/hooks/subagent_start.py +6 -2
  344. package/hooks/subagent_stop.py +1 -13
  345. package/hooks/user_prompt_submit.py +119 -37
  346. package/index.js +1 -1
  347. package/package.json +5 -3
  348. package/skills/README.md +3 -5
  349. package/skills/agent-protocol/SKILL.md +17 -16
  350. package/skills/agent-protocol/examples.md +6 -6
  351. package/skills/agent-response/SKILL.md +11 -14
  352. package/skills/approval/SKILL.md +28 -13
  353. package/skills/approval/reference.md +2 -2
  354. package/skills/execution/SKILL.md +1 -1
  355. package/skills/gaia-patterns/SKILL.md +2 -3
  356. package/skills/orchestrator-approval/SKILL.md +22 -50
  357. package/skills/security-tiers/SKILL.md +1 -1
  358. package/templates/README.md +9 -9
  359. package/templates/managed-settings.template.json +43 -0
  360. package/tools/gaia_simulator/runner.py +34 -1
  361. package/tools/scan/orchestrator.py +13 -0
  362. package/tools/scan/scanners/base.py +8 -0
  363. package/tools/scan/scanners/git.py +78 -0
  364. package/tools/scan/scanners/infrastructure.py +65 -0
  365. package/tools/scan/scanners/stack.py +110 -0
  366. package/tools/scan/setup.py +120 -13
  367. package/tools/scan/workspace.py +85 -0
  368. package/config/context-contracts.aws.json +0 -42
  369. package/config/context-contracts.gcp.json +0 -39
  370. package/skills/project-dispatch/SKILL.md +0 -34
  371. package/templates/settings.template.json +0 -226
@@ -0,0 +1,457 @@
1
+ """
2
+ Log parser for gaia-ops hook replay testing.
3
+
4
+ Extracts ReplayEvent instances from production hook logs and audit JSONL files.
5
+ Completely decoupled from hooks -- only understands log formats.
6
+
7
+ Supported log formats:
8
+ hooks-YYYY-MM-DD.log - Human-readable hook execution logs
9
+ audit-YYYY-MM-DD.jsonl - Structured JSON audit trail (post_tool_use events)
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import json
15
+ import re
16
+ from dataclasses import dataclass, field
17
+ from pathlib import Path
18
+ from typing import Any, Optional
19
+
20
+
21
+ @dataclass(frozen=True)
22
+ class ReplayEvent:
23
+ """A single hook invocation extracted from logs."""
24
+
25
+ timestamp: str
26
+ hook_name: str # "pre_tool_use", "post_tool_use", "subagent_stop"
27
+ tool_name: str # "Bash", "Agent", "Read", etc.
28
+ stdin_payload: dict # The JSON that was sent to the hook
29
+ expected_decision: str # "ALLOW", "BLOCK", "DENY"
30
+ expected_exit_code: int # 0, 1, 2
31
+ expected_tier: str # "T0", "T1", "T2", "T3", "" for non-bash
32
+ source_file: str # Which log file this came from
33
+ expected_metadata: dict[str, Any] = field(default_factory=dict)
34
+ compare_tier: bool = False
35
+ limitations: tuple[str, ...] = field(default_factory=tuple)
36
+
37
+
38
+ # ---------------------------------------------------------------------------
39
+ # Internal regex patterns for hooks-*.log parsing
40
+ # ---------------------------------------------------------------------------
41
+
42
+ # Matches: 2026-03-11 00:03:32,080 [pre_tool_use] __main__ - INFO - Hook invoked: tool=Bash, params={...}
43
+ _RE_HOOK_INVOKED = re.compile(
44
+ r"^(?P<ts>\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2},\d+)"
45
+ r"\s+\[(?P<hook>[^\]]+)\]\s+"
46
+ r"__main__\s+-\s+INFO\s+-\s+"
47
+ r"Hook invoked:\s+tool=(?P<tool>\w+),\s+params=(?P<params>\{.+)"
48
+ )
49
+
50
+ # Matches: ... - INFO - ALLOWED: <command> - tier=T0
51
+ _RE_ALLOWED_BASH = re.compile(
52
+ r"^(?P<ts>\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2},\d+)"
53
+ r"\s+\[(?P<hook>[^\]]+)\]\s+"
54
+ r"__main__\s+-\s+INFO\s+-\s+"
55
+ r"ALLOWED:\s+(?P<cmd>.+?)\s+-\s+tier=(?P<tier>T\d)"
56
+ )
57
+
58
+ # Matches: ... - INFO - ALLOWED Task: <agent-name>
59
+ _RE_ALLOWED_TASK = re.compile(
60
+ r"^(?P<ts>\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2},\d+)"
61
+ r"\s+\[(?P<hook>[^\]]+)\]\s+"
62
+ r"__main__\s+-\s+INFO\s+-\s+"
63
+ r"ALLOWED Task:\s+(?P<agent>\S+)"
64
+ )
65
+
66
+ # Matches: ... - WARNING - BLOCKED: <command> - <reason>
67
+ _RE_BLOCKED = re.compile(
68
+ r"^(?P<ts>\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2},\d+)"
69
+ r"\s+\[(?P<hook>[^\]]+)\]\s+"
70
+ r"__main__\s+-\s+WARNING\s+-\s+"
71
+ r"BLOCKED:\s+(?P<cmd>.+?)\s+-\s+(?P<reason>.+)"
72
+ )
73
+
74
+ # Matches: ... - WARNING - BLOCKED Task: <agent> - <reason>
75
+ _RE_BLOCKED_TASK = re.compile(
76
+ r"^(?P<ts>\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2},\d+)"
77
+ r"\s+\[(?P<hook>[^\]]+)\]\s+"
78
+ r"__main__\s+-\s+WARNING\s+-\s+"
79
+ r"BLOCKED Task:\s+(?P<agent>\S+)\s+-\s+(?P<reason>.+)"
80
+ )
81
+
82
+ # Matches: ... - INFO - Hook event: SubagentStop, agent: <agent-name>
83
+ _RE_SUBAGENT_STOP = re.compile(
84
+ r"^(?P<ts>\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2},\d+)"
85
+ r"\s+\[subagent_stop\]\s+"
86
+ r"__main__\s+-\s+INFO\s+-\s+"
87
+ r"Hook event:\s+SubagentStop,\s+agent:\s+(?P<agent>\S+)"
88
+ )
89
+
90
+ # Matches: ... - INFO - Post-hook event: PostToolUse
91
+ _RE_POST_TOOL_USE = re.compile(
92
+ r"^(?P<ts>\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2},\d+)"
93
+ r"\s+\[post_tool_use\]\s+"
94
+ r"__main__\s+-\s+INFO\s+-\s+"
95
+ r"Post-hook event:\s+PostToolUse"
96
+ )
97
+
98
+ # Matches: ... - INFO - Stop: reason=user_requested, quality_sufficient=True, score=1.00
99
+ _RE_STOP_RESULT = re.compile(
100
+ r"^(?P<ts>\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2},\d+)"
101
+ r"\s+\[stop_hook\]\s+"
102
+ r"__main__\s+-\s+INFO\s+-\s+"
103
+ r"Stop:\s+reason=(?P<reason>[^,]+),\s+quality_sufficient=(?P<quality>True|False),\s+score=(?P<score>\d+(?:\.\d+)?)"
104
+ )
105
+
106
+
107
+ def _try_parse_params(raw: str) -> Optional[dict]:
108
+ """Try to parse the params JSON from a Hook invoked log line.
109
+
110
+ The params value may be truncated in the log, so we attempt parsing
111
+ and return None on failure.
112
+ """
113
+ try:
114
+ return json.loads(raw)
115
+ except json.JSONDecodeError:
116
+ pass
117
+
118
+ # Truncated JSON -- try to find a valid JSON prefix
119
+ # The log line cuts off params, so we try progressively shorter substrings
120
+ # that end with }
121
+ for i in range(len(raw) - 1, 0, -1):
122
+ if raw[i] == "}":
123
+ try:
124
+ return json.loads(raw[: i + 1])
125
+ except json.JSONDecodeError:
126
+ continue
127
+ return None
128
+
129
+
130
+ class LogExtractor:
131
+ """Extracts ReplayEvents from gaia-ops hook logs.
132
+
133
+ Parses two log formats:
134
+ - hooks-YYYY-MM-DD.log: Human-readable hook execution logs
135
+ - audit-YYYY-MM-DD.jsonl: Structured JSON audit trail
136
+
137
+ Each format produces ReplayEvent instances that can be replayed
138
+ against current hooks to detect regressions.
139
+ """
140
+
141
+ def extract_from_hooks_log(self, path: Path) -> list[ReplayEvent]:
142
+ """Parse hooks-YYYY-MM-DD.log and extract hook invocation events.
143
+
144
+ Strategy:
145
+ 1. Find "Hook invoked" lines to get the tool + params (stdin payload)
146
+ 2. Find the corresponding ALLOWED/BLOCKED line to get the decision
147
+ 3. Pair them by timestamp proximity to build ReplayEvents
148
+
149
+ Returns:
150
+ List of ReplayEvent instances, ordered by timestamp.
151
+ """
152
+ if not path.exists():
153
+ return []
154
+
155
+ lines = path.read_text(encoding="utf-8", errors="replace").splitlines()
156
+ source = path.name
157
+ events: list[ReplayEvent] = []
158
+
159
+ # Two-pass approach:
160
+ # Pass 1: collect all "Hook invoked" entries with their params
161
+ # Pass 2: match them to ALLOWED/BLOCKED outcomes
162
+
163
+ pending_invocations: list[dict] = []
164
+ outcomes: list[dict] = []
165
+
166
+ for line in lines:
167
+ # Hook invoked line
168
+ m = _RE_HOOK_INVOKED.match(line)
169
+ if m:
170
+ params = _try_parse_params(m.group("params"))
171
+ pending_invocations.append({
172
+ "ts": m.group("ts"),
173
+ "hook": m.group("hook"),
174
+ "tool": m.group("tool"),
175
+ "params": params,
176
+ })
177
+ continue
178
+
179
+ # ALLOWED bash command
180
+ m = _RE_ALLOWED_BASH.match(line)
181
+ if m:
182
+ outcomes.append({
183
+ "ts": m.group("ts"),
184
+ "hook": m.group("hook"),
185
+ "decision": "ALLOW",
186
+ "exit_code": 0,
187
+ "tier": m.group("tier"),
188
+ "type": "bash",
189
+ })
190
+ continue
191
+
192
+ # ALLOWED task (agent)
193
+ m = _RE_ALLOWED_TASK.match(line)
194
+ if m:
195
+ outcomes.append({
196
+ "ts": m.group("ts"),
197
+ "hook": m.group("hook"),
198
+ "decision": "ALLOW",
199
+ "exit_code": 0,
200
+ "tier": "",
201
+ "type": "task",
202
+ "agent": m.group("agent"),
203
+ })
204
+ continue
205
+
206
+ # BLOCKED bash command
207
+ m = _RE_BLOCKED.match(line)
208
+ if m:
209
+ reason = m.group("reason")
210
+ # The hook logs "BLOCKED:" for both permanent blocks (exit 2,
211
+ # plain string) and structured deny responses (exit 0, JSON
212
+ # with permissionDecision: "deny"). Distinguish them by
213
+ # reason text:
214
+ #
215
+ # Exit 0 DENY (block_response is set):
216
+ # - "Dangerous ..." -- mutative verb T3 nonce flow
217
+ # - "Command-execution rule violated ..." -- cloud pipe
218
+ # - "Failed to persist pending approval ..." -- T3 nonce write error
219
+ # - Compound wrappers that propagate a component's block_response
220
+ #
221
+ # Exit 2 BLOCK (block_response is None):
222
+ # - "Command blocked by security policy ..." -- permanent deny list
223
+ # - "Commit message validation failed ..." -- validation error
224
+ # - "GitOps policy violation ..." -- GitOps validation
225
+ # - "Empty command not allowed"
226
+ if (
227
+ reason.startswith("Dangerous")
228
+ or reason.startswith("Command-execution rule violated")
229
+ or reason.startswith("Failed to persist pending approval")
230
+ or (reason.startswith("Compound command blocked") and "Dangerous" in reason)
231
+ ):
232
+ decision = "DENY"
233
+ exit_code = 0
234
+ else:
235
+ decision = "BLOCK"
236
+ exit_code = 2
237
+ outcomes.append({
238
+ "ts": m.group("ts"),
239
+ "hook": m.group("hook"),
240
+ "decision": decision,
241
+ "exit_code": exit_code,
242
+ "tier": "",
243
+ "type": "bash",
244
+ "reason": reason,
245
+ })
246
+ continue
247
+
248
+ # BLOCKED task
249
+ m = _RE_BLOCKED_TASK.match(line)
250
+ if m:
251
+ outcomes.append({
252
+ "ts": m.group("ts"),
253
+ "hook": m.group("hook"),
254
+ "decision": "BLOCK",
255
+ "exit_code": 2,
256
+ "tier": "",
257
+ "type": "task",
258
+ "agent": m.group("agent"),
259
+ "reason": m.group("reason"),
260
+ })
261
+ continue
262
+
263
+ # Stop hook result (minimal replayable payload)
264
+ m = _RE_STOP_RESULT.match(line)
265
+ if m:
266
+ quality_sufficient = m.group("quality") == "True"
267
+ events.append(ReplayEvent(
268
+ timestamp=m.group("ts"),
269
+ hook_name="stop_hook",
270
+ tool_name="Stop",
271
+ stdin_payload={
272
+ "hook_event_name": "Stop",
273
+ "session_id": "replay",
274
+ "stop_reason": m.group("reason"),
275
+ },
276
+ expected_decision="PASS",
277
+ expected_exit_code=0,
278
+ expected_tier="",
279
+ source_file=source,
280
+ expected_metadata={
281
+ "quality_sufficient": quality_sufficient,
282
+ "score": float(m.group("score")),
283
+ },
284
+ limitations=(
285
+ "hooks log captures stop reason and quality summary, but not last_assistant_message",
286
+ ),
287
+ ))
288
+ continue
289
+
290
+ # Match invocations to outcomes by sequential pairing
291
+ # Each Hook invoked is followed by exactly one ALLOWED or BLOCKED
292
+ outcome_idx = 0
293
+ for inv in pending_invocations:
294
+ if outcome_idx >= len(outcomes):
295
+ break
296
+
297
+ outcome = outcomes[outcome_idx]
298
+ outcome_idx += 1
299
+
300
+ # Build the stdin_payload that the hook expects
301
+ tool = inv["tool"]
302
+ params = inv["params"]
303
+
304
+ # Skip events with truncated/unparseable params -- they cannot
305
+ # be replayed meaningfully. The log line was cut off before the
306
+ # JSON closed, so we don't have the full payload.
307
+ if params is None:
308
+ continue
309
+
310
+ # Validate minimum payload: Bash needs "command", Agent needs
311
+ # at least "subagent_type" or "description"
312
+ if tool == "Bash" and "command" not in params:
313
+ continue
314
+ if tool == "Agent" and not any(
315
+ k in params for k in ("subagent_type", "description", "prompt")
316
+ ):
317
+ continue
318
+
319
+ stdin_payload = {
320
+ "tool_name": tool,
321
+ "tool_input": params,
322
+ "hook_event_name": "PreToolUse",
323
+ "session_id": "replay",
324
+ }
325
+
326
+ events.append(ReplayEvent(
327
+ timestamp=inv["ts"],
328
+ hook_name=inv["hook"],
329
+ tool_name=tool,
330
+ stdin_payload=stdin_payload,
331
+ expected_decision=outcome["decision"],
332
+ expected_exit_code=outcome["exit_code"],
333
+ expected_tier=outcome.get("tier", ""),
334
+ source_file=source,
335
+ compare_tier=tool in {"Bash", "Task", "Agent"} and inv["hook"] == "pre_tool_use",
336
+ ))
337
+
338
+ return sorted(events, key=lambda event: event.timestamp)
339
+
340
+ def extract_from_audit_jsonl(self, path: Path) -> list[ReplayEvent]:
341
+ """Parse audit-YYYY-MM-DD.jsonl for structured event data.
342
+
343
+ Audit JSONL files contain post_tool_use records with:
344
+ - timestamp, session_id, tool_name, command, parameters, duration_ms,
345
+ exit_code, tier
346
+
347
+ These records are emitted by the post_tool_use hook after a tool ran,
348
+ so they are replayed back into post_tool_use with the best available
349
+ synthetic tool_result payload reconstructed from the audit entry.
350
+
351
+ Returns:
352
+ List of ReplayEvent instances, ordered by timestamp.
353
+ """
354
+ if not path.exists():
355
+ return []
356
+
357
+ source = path.name
358
+ events: list[ReplayEvent] = []
359
+
360
+ for line_text in path.read_text(encoding="utf-8", errors="replace").splitlines():
361
+ line_text = line_text.strip()
362
+ if not line_text:
363
+ continue
364
+
365
+ try:
366
+ record = json.loads(line_text)
367
+ except json.JSONDecodeError:
368
+ continue
369
+
370
+ tool_name = record.get("tool_name", "")
371
+ if not tool_name:
372
+ continue
373
+
374
+ # Build stdin payload matching PostToolUse format. The audit log does
375
+ # not persist tool stdout/stderr, so replay can only restore the
376
+ # tool metadata, exit code, and duration.
377
+ params = record.get("parameters", {})
378
+ tool_exit_code = int(record.get("exit_code", 0) or 0)
379
+ duration_ms = record.get("duration_ms", 0)
380
+ stdin_payload = {
381
+ "tool_name": tool_name,
382
+ "tool_input": params,
383
+ "tool_result": {
384
+ "output": "",
385
+ "stdout": "",
386
+ "exit_code": tool_exit_code,
387
+ "duration_ms": duration_ms,
388
+ },
389
+ "hook_event_name": "PostToolUse",
390
+ "session_id": record.get("session_id", "replay") or "replay",
391
+ }
392
+
393
+ tier = record.get("tier", "")
394
+
395
+ events.append(ReplayEvent(
396
+ timestamp=record.get("timestamp", ""),
397
+ hook_name="post_tool_use",
398
+ tool_name=tool_name,
399
+ stdin_payload=stdin_payload,
400
+ expected_decision="PASS",
401
+ expected_exit_code=0,
402
+ expected_tier=tier,
403
+ source_file=source,
404
+ expected_metadata={
405
+ "tool_exit_code": tool_exit_code,
406
+ },
407
+ compare_tier=bool(tier),
408
+ limitations=(
409
+ "audit JSONL does not persist tool output, so post_tool_use replay cannot validate output-dependent critical-event detection",
410
+ ),
411
+ ))
412
+
413
+ return events
414
+
415
+ def extract_all(
416
+ self,
417
+ logs_dir: Path,
418
+ date_filter: Optional[str] = None,
419
+ hook_filter: Optional[str] = None,
420
+ ) -> list[ReplayEvent]:
421
+ """Extract from all log files in a directory, merge by timestamp.
422
+
423
+ Args:
424
+ logs_dir: Directory containing hooks-*.log and audit-*.jsonl files.
425
+ date_filter: Optional YYYY-MM-DD string to filter by date.
426
+ hook_filter: Optional hook name to filter (e.g. "pre_tool_use").
427
+
428
+ Returns:
429
+ Merged list of ReplayEvent instances, sorted by timestamp.
430
+ """
431
+ events: list[ReplayEvent] = []
432
+
433
+ # Process hooks logs
434
+ pattern = f"hooks-{date_filter}.log" if date_filter else "hooks-*.log"
435
+ for log_path in sorted(logs_dir.glob(pattern)):
436
+ events.extend(self.extract_from_hooks_log(log_path))
437
+
438
+ # Process audit JSONL
439
+ pattern = f"audit-{date_filter}.jsonl" if date_filter else "audit-*.jsonl"
440
+ for jsonl_path in sorted(logs_dir.glob(pattern)):
441
+ events.extend(self.extract_from_audit_jsonl(jsonl_path))
442
+
443
+ # Apply hook filter
444
+ if hook_filter:
445
+ events = [e for e in events if e.hook_name == hook_filter]
446
+
447
+ # Deduplicate: same timestamp + same tool_name + same expected_decision
448
+ # Keep the hooks-log version (richer data) over audit version
449
+ seen: dict[tuple, ReplayEvent] = {}
450
+ for ev in events:
451
+ key = (ev.timestamp, ev.tool_name, ev.expected_decision)
452
+ if key not in seen or ev.source_file.startswith("hooks-"):
453
+ seen[key] = ev
454
+
455
+ # Sort by timestamp
456
+ result = sorted(seen.values(), key=lambda e: e.timestamp)
457
+ return result