@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,137 @@
1
+ """
2
+ Base Scanner Protocol
3
+
4
+ Defines the abstract base class that all scanner modules must implement.
5
+ Each scanner is a pure function: it reads filesystem state and returns
6
+ structured section data without side effects.
7
+
8
+ Contract: contracts/scanner-interface.md
9
+ """
10
+
11
+ from abc import ABC, abstractmethod
12
+ from dataclasses import dataclass, field
13
+ from pathlib import Path
14
+ from typing import Any, Dict, List, Optional
15
+
16
+
17
+ @dataclass(frozen=True)
18
+ class ScanResult:
19
+ """Immutable result from a single scanner execution.
20
+
21
+ Attributes:
22
+ scanner: Scanner name that produced this result.
23
+ sections: Mapping of section names to section data.
24
+ warnings: Non-fatal warnings encountered during scanning.
25
+ duration_ms: Execution time in milliseconds.
26
+ """
27
+
28
+ scanner: str = ""
29
+ sections: Dict[str, Any] = field(default_factory=dict)
30
+ warnings: List[str] = field(default_factory=list)
31
+ duration_ms: float = 0.0
32
+
33
+
34
+ class BaseScanner(ABC):
35
+ """Abstract base class for all scanner modules.
36
+
37
+ Every scanner MUST implement:
38
+ - SCANNER_NAME: Unique scanner identifier (e.g., "stack", "git")
39
+ - SCANNER_VERSION: Semver string for schema tracking (e.g., "1.0.0")
40
+ - OWNED_SECTIONS: List of section names this scanner owns in project-context.json
41
+ - scan(root): Pure function that scans the project and returns a dict of sections
42
+
43
+ Pure Function Contract:
44
+ - No file writes
45
+ - No state modification
46
+ - No network calls
47
+ - No command execution that modifies state
48
+ - Only reads: filesystem reads, command -v, <tool> --version
49
+ - MUST NOT raise exceptions to caller
50
+ - MUST catch all internal errors and return {} or partial results
51
+ - Individual file read failures MUST NOT abort the scanner
52
+
53
+ Performance:
54
+ - SHOULD complete in under 3 seconds for typical projects
55
+ - MUST respect 2-second timeout for --version calls
56
+
57
+ Optional workspace_info attribute:
58
+ - Set by the orchestrator before scan() when workspace type has been
59
+ pre-detected. Scanners can check self.workspace_info for multi-repo
60
+ awareness. Defaults to None (single-repo assumed).
61
+ """
62
+
63
+ def __init__(self) -> None:
64
+ self.workspace_info = None # Set by orchestrator if available
65
+
66
+ @property
67
+ @abstractmethod
68
+ def SCANNER_NAME(self) -> str:
69
+ """Unique scanner identifier (e.g., 'stack', 'git')."""
70
+ ...
71
+
72
+ @property
73
+ @abstractmethod
74
+ def SCANNER_VERSION(self) -> str:
75
+ """Scanner version for schema tracking (semver)."""
76
+ ...
77
+
78
+ @property
79
+ @abstractmethod
80
+ def OWNED_SECTIONS(self) -> List[str]:
81
+ """Section names this scanner owns in project-context.json."""
82
+ ...
83
+
84
+ @abstractmethod
85
+ def scan(self, root: Path) -> Dict[str, Any]:
86
+ """Scan the project at root and return detected sections.
87
+
88
+ Args:
89
+ root: Absolute path to the project root directory.
90
+ MUST be validated by caller (exists, is directory).
91
+
92
+ Returns:
93
+ Dict mapping section names to section data.
94
+ Empty dict on complete failure.
95
+ Partial dict when some detection succeeds and some fails.
96
+
97
+ Side Effects:
98
+ NONE. This function is pure.
99
+ """
100
+ ...
101
+
102
+ @property
103
+ def source_tag(self) -> str:
104
+ """Return the _source metadata tag for sections produced by this scanner."""
105
+ return f"scanner:{self.SCANNER_NAME}"
106
+
107
+ def make_result(
108
+ self,
109
+ sections: Dict[str, Any],
110
+ warnings: Optional[List[str]] = None,
111
+ duration_ms: float = 0.0,
112
+ ) -> ScanResult:
113
+ """Create a ScanResult with this scanner's metadata.
114
+
115
+ Automatically injects _source tag into each section.
116
+
117
+ Args:
118
+ sections: Section name to section data mapping.
119
+ warnings: Optional list of non-fatal warnings.
120
+ duration_ms: Execution time in milliseconds.
121
+
122
+ Returns:
123
+ Frozen ScanResult instance.
124
+ """
125
+ tagged_sections = {}
126
+ for name, data in sections.items():
127
+ if isinstance(data, dict):
128
+ tagged_sections[name] = {"_source": self.source_tag, **data}
129
+ else:
130
+ tagged_sections[name] = data
131
+
132
+ return ScanResult(
133
+ scanner=self.SCANNER_NAME,
134
+ sections=tagged_sections,
135
+ warnings=warnings or [],
136
+ duration_ms=duration_ms,
137
+ )
@@ -0,0 +1,324 @@
1
+ """
2
+ Environment Scanner
3
+
4
+ Detects OS information (platform, architecture, WSL), installed language
5
+ runtimes, and .env file patterns. Outputs environment.os, environment.runtimes,
6
+ and environment.env_files subsections.
7
+
8
+ Pure Function Contract:
9
+ - No file writes
10
+ - No state modification
11
+ - No network calls
12
+ - NEVER reads .env file contents (FR-043) -- only Path.exists() and Path.name
13
+ - Only reads: /proc/version (for WSL detection), runtime --version output
14
+ """
15
+
16
+ import logging
17
+ import platform
18
+ import shutil
19
+ import subprocess
20
+ import sys
21
+ import time
22
+ from pathlib import Path
23
+ from typing import Any, Dict, List, Optional, Tuple
24
+
25
+ from tools.scan.scanners.base import BaseScanner, ScanResult
26
+
27
+ logger = logging.getLogger(__name__)
28
+
29
+ # Runtimes to detect: (binary_name, version_flag)
30
+ _RUNTIME_DEFINITIONS: List[Tuple[str, str]] = [
31
+ ("python3", "--version"),
32
+ ("node", "--version"),
33
+ ("go", "version"),
34
+ ("cargo", "--version"),
35
+ ("java", "--version"),
36
+ ]
37
+
38
+ # Env file names to check for (presence ONLY -- never read contents)
39
+ _ENV_FILE_NAMES: List[str] = [
40
+ ".env",
41
+ ".env.local",
42
+ ".env.example",
43
+ ".env.development",
44
+ ".env.production",
45
+ ]
46
+
47
+ # Architecture mapping from platform.machine() to canonical names
48
+ _ARCH_MAP: Dict[str, str] = {
49
+ "x86_64": "x64",
50
+ "AMD64": "x64",
51
+ "aarch64": "arm64",
52
+ "arm64": "arm64",
53
+ }
54
+
55
+ # Platform mapping from sys.platform to canonical names
56
+ _PLATFORM_MAP: Dict[str, str] = {
57
+ "linux": "linux",
58
+ "darwin": "darwin",
59
+ "win32": "win32",
60
+ "cygwin": "win32",
61
+ }
62
+
63
+
64
+ class EnvironmentScanner(BaseScanner):
65
+ """Scanner for OS, runtime, and env file detection.
66
+
67
+ Detects:
68
+ - OS: platform (linux/darwin/win32), architecture (x64/arm64), WSL
69
+ - Runtimes: python3, node, go, cargo, java versions via --version
70
+ - Env files: .env, .env.local, .env.example, etc. by Path.exists() ONLY
71
+
72
+ CRITICAL: NEVER calls open() or read() on any .env file.
73
+ """
74
+
75
+ @property
76
+ def SCANNER_NAME(self) -> str:
77
+ return "environment"
78
+
79
+ @property
80
+ def SCANNER_VERSION(self) -> str:
81
+ return "1.0.0"
82
+
83
+ @property
84
+ def OWNED_SECTIONS(self) -> List[str]:
85
+ return ["environment.runtimes", "environment.os", "environment.env_files"]
86
+
87
+ def scan(self, root: Path) -> ScanResult:
88
+ """Scan for OS info, runtimes, and env files.
89
+
90
+ Args:
91
+ root: Absolute path to the project root directory.
92
+
93
+ Returns:
94
+ ScanResult with 'environment' section containing os, runtimes,
95
+ and env_files subsections.
96
+ """
97
+ start = time.monotonic()
98
+ warnings: List[str] = []
99
+
100
+ os_info = self._detect_os(warnings)
101
+ runtimes = self._detect_runtimes(warnings)
102
+ env_files = self._detect_env_files(root, warnings)
103
+
104
+ elapsed_ms = (time.monotonic() - start) * 1000
105
+
106
+ sections: Dict[str, Any] = {
107
+ "environment": {
108
+ "os": os_info,
109
+ "runtimes": runtimes,
110
+ "env_files": env_files,
111
+ }
112
+ }
113
+
114
+ return self.make_result(
115
+ sections=sections,
116
+ warnings=warnings,
117
+ duration_ms=elapsed_ms,
118
+ )
119
+
120
+ def _detect_os(self, warnings: List[str]) -> Dict[str, Any]:
121
+ """Detect OS platform, architecture, and WSL status.
122
+
123
+ Platform and architecture are always available via stdlib.
124
+ WSL detection reads /proc/version if on Linux.
125
+ """
126
+ raw_platform = sys.platform
127
+ canonical_platform = _PLATFORM_MAP.get(raw_platform, raw_platform)
128
+
129
+ raw_arch = platform.machine()
130
+ canonical_arch = _ARCH_MAP.get(raw_arch, raw_arch)
131
+
132
+ wsl = False
133
+ wsl_version: Optional[str] = None
134
+
135
+ if canonical_platform == "linux":
136
+ wsl, wsl_version = self._detect_wsl(warnings)
137
+
138
+ return {
139
+ "platform": canonical_platform,
140
+ "architecture": canonical_arch,
141
+ "wsl": wsl,
142
+ "wsl_version": wsl_version,
143
+ }
144
+
145
+ def _detect_wsl(self, warnings: List[str]) -> Tuple[bool, Optional[str]]:
146
+ """Detect WSL by reading /proc/version for 'microsoft' or 'WSL'.
147
+
148
+ Returns:
149
+ Tuple of (is_wsl, wsl_version). wsl_version is '1' or '2' when
150
+ detectable, None otherwise.
151
+ """
152
+ proc_version_path = Path("/proc/version")
153
+
154
+ try:
155
+ if not proc_version_path.exists():
156
+ return False, None
157
+
158
+ content = proc_version_path.read_text()
159
+ content_lower = content.lower()
160
+
161
+ if "microsoft" not in content_lower and "wsl" not in content_lower:
162
+ return False, None
163
+
164
+ # WSL2 uses a real Linux kernel and identifies as "microsoft-standard-WSL2"
165
+ # WSL1 uses "Microsoft" in the version string but not "WSL2"
166
+ wsl_version: Optional[str] = None
167
+ if "wsl2" in content_lower:
168
+ wsl_version = "2"
169
+ elif "microsoft" in content_lower:
170
+ # Could be WSL1 or WSL2 without explicit marker
171
+ # WSL2 kernels typically contain "microsoft-standard-WSL2"
172
+ # WSL1 kernels contain "Microsoft" but not "WSL2"
173
+ wsl_version = "1"
174
+
175
+ return True, wsl_version
176
+
177
+ except OSError as exc:
178
+ warnings.append(f"WSL detection failed: {exc}")
179
+ return False, None
180
+
181
+ def _detect_runtimes(self, warnings: List[str]) -> List[Dict[str, str]]:
182
+ """Detect installed language runtimes via --version commands.
183
+
184
+ Uses shutil.which() to find binaries, then subprocess with 2s timeout
185
+ to get version strings.
186
+ """
187
+ runtimes: List[Dict[str, str]] = []
188
+
189
+ for binary_name, version_flag in _RUNTIME_DEFINITIONS:
190
+ try:
191
+ binary_path = shutil.which(binary_name)
192
+ if binary_path is None:
193
+ continue
194
+
195
+ version = self._get_version(binary_name, version_flag, warnings)
196
+ if version is not None:
197
+ runtimes.append({
198
+ "name": binary_name,
199
+ "version": version,
200
+ "path": binary_path,
201
+ })
202
+
203
+ except Exception as exc:
204
+ warnings.append(f"Runtime detection failed for {binary_name}: {exc}")
205
+
206
+ return runtimes
207
+
208
+ def _get_version(
209
+ self, binary: str, flag: str, warnings: List[str]
210
+ ) -> Optional[str]:
211
+ """Run '<binary> <flag>' and extract version string.
212
+
213
+ Args:
214
+ binary: Binary name to execute.
215
+ flag: Version flag (e.g., '--version', 'version').
216
+ warnings: List to append non-fatal warnings to.
217
+
218
+ Returns:
219
+ Version string or None on failure.
220
+ """
221
+ try:
222
+ result = subprocess.run(
223
+ [binary, flag],
224
+ capture_output=True,
225
+ text=True,
226
+ timeout=2,
227
+ )
228
+
229
+ # Some tools output version to stderr (e.g., java --version)
230
+ output = result.stdout.strip() or result.stderr.strip()
231
+
232
+ if not output:
233
+ return "unknown"
234
+
235
+ # Extract the first line and clean it
236
+ first_line = output.splitlines()[0].strip()
237
+
238
+ # Try to extract version number from common patterns
239
+ version = self._parse_version(first_line)
240
+ return version if version else first_line
241
+
242
+ except subprocess.TimeoutExpired:
243
+ warnings.append(f"{binary} {flag} timed out after 2s")
244
+ return "unknown"
245
+ except FileNotFoundError:
246
+ return None
247
+ except OSError as exc:
248
+ warnings.append(f"{binary} {flag} failed: {exc}")
249
+ return "unknown"
250
+
251
+ @staticmethod
252
+ def _parse_version(line: str) -> Optional[str]:
253
+ """Extract a version number from a version string line.
254
+
255
+ Handles common formats:
256
+ - 'Python 3.11.5' -> '3.11.5'
257
+ - 'v20.10.0' -> '20.10.0'
258
+ - 'go version go1.21.0 linux/amd64' -> '1.21.0'
259
+ - 'cargo 1.72.0 (103a7ff2e 2023-08-15)' -> '1.72.0'
260
+ - 'openjdk 21.0.1 2023-10-17' -> '21.0.1'
261
+
262
+ Returns:
263
+ Cleaned version string or None if no version pattern found.
264
+ """
265
+ import re
266
+
267
+ # Match 'go1.21.0' pattern (go-specific)
268
+ go_match = re.search(r"go(\d+\.\d+(?:\.\d+)?)", line)
269
+ if go_match:
270
+ return go_match.group(1)
271
+
272
+ # Match standard version patterns: v1.2.3, 1.2.3, 1.2
273
+ version_match = re.search(r"v?(\d+\.\d+(?:\.\d+)?(?:[._-]\w+)*)", line)
274
+ if version_match:
275
+ return version_match.group(1)
276
+
277
+ return None
278
+
279
+ def _detect_env_files(
280
+ self, root: Path, warnings: List[str]
281
+ ) -> List[Dict[str, str]]:
282
+ """Detect .env file patterns by existence check ONLY.
283
+
284
+ CRITICAL: NEVER calls open() or read() on any .env file.
285
+ Only uses Path.exists() and Path.name.
286
+
287
+ Args:
288
+ root: Project root directory.
289
+ warnings: List to append non-fatal warnings to.
290
+
291
+ Returns:
292
+ List of dicts with 'name' and 'path' for each found env file.
293
+ """
294
+ env_files: List[Dict[str, str]] = []
295
+
296
+ for env_name in _ENV_FILE_NAMES:
297
+ try:
298
+ env_path = root / env_name
299
+ if env_path.exists():
300
+ env_files.append({
301
+ "name": env_path.name,
302
+ "path": str(env_path.relative_to(root)),
303
+ })
304
+ except (OSError, ValueError) as exc:
305
+ warnings.append(f"Env file check failed for {env_name}: {exc}")
306
+
307
+ return env_files
308
+
309
+
310
+ def scan(root: Path) -> Dict[str, Any]:
311
+ """Module-level convenience function for environment scanning.
312
+
313
+ This function provides backward compatibility with the module-level scan()
314
+ pattern used by the scanner registry auto-discovery.
315
+
316
+ Args:
317
+ root: Absolute path to the project root directory.
318
+
319
+ Returns:
320
+ Dict with 'environment' section containing os, runtimes, and env_files.
321
+ """
322
+ scanner = EnvironmentScanner()
323
+ result = scanner.scan(root)
324
+ return result.sections