@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,419 @@
1
+ """
2
+ Unit tests for the Git Scanner (T022).
3
+
4
+ Tests platform detection from remote URLs, all remotes listing,
5
+ default branch detection, monorepo workspace detection, and
6
+ branch strategy detection.
7
+ """
8
+
9
+ import json
10
+ import textwrap
11
+ from pathlib import Path
12
+ from typing import Any, Dict
13
+
14
+ import pytest
15
+
16
+ from tools.scan.scanners.git import (
17
+ GitScanner,
18
+ _detect_branch_strategy,
19
+ _detect_default_branch,
20
+ _detect_platform_from_url,
21
+ _determine_primary_platform,
22
+ _parse_git_config,
23
+ )
24
+ from tools.scan.tests.conftest import create_git_dir
25
+
26
+
27
+ @pytest.fixture
28
+ def scanner() -> GitScanner:
29
+ """Create a GitScanner instance."""
30
+ return GitScanner()
31
+
32
+
33
+ # ---------------------------------------------------------------------------
34
+ # Scanner basics
35
+ # ---------------------------------------------------------------------------
36
+
37
+
38
+ class TestGitScannerBasics:
39
+ """Test scanner metadata and basic contract."""
40
+
41
+ def test_scanner_name(self, scanner: GitScanner) -> None:
42
+ assert scanner.SCANNER_NAME == "git"
43
+
44
+ def test_scanner_version(self, scanner: GitScanner) -> None:
45
+ assert scanner.SCANNER_VERSION == "1.0.0"
46
+
47
+ def test_owned_sections(self, scanner: GitScanner) -> None:
48
+ assert scanner.OWNED_SECTIONS == ["git"]
49
+
50
+ def test_source_tag(self, scanner: GitScanner) -> None:
51
+ assert scanner.source_tag == "scanner:git"
52
+
53
+
54
+ # ---------------------------------------------------------------------------
55
+ # Platform detection from URL
56
+ # ---------------------------------------------------------------------------
57
+
58
+
59
+ class TestPlatformDetection:
60
+ """Test platform detection from remote URLs."""
61
+
62
+ def test_github_ssh(self) -> None:
63
+ assert _detect_platform_from_url("git@github.com:org/repo.git") == "github"
64
+
65
+ def test_github_https(self) -> None:
66
+ assert _detect_platform_from_url("https://github.com/org/repo.git") == "github"
67
+
68
+ def test_gitlab_ssh(self) -> None:
69
+ assert _detect_platform_from_url("git@gitlab.com:group/project.git") == "gitlab"
70
+
71
+ def test_gitlab_https(self) -> None:
72
+ assert _detect_platform_from_url("https://gitlab.com/group/project.git") == "gitlab"
73
+
74
+ def test_bitbucket_ssh(self) -> None:
75
+ assert _detect_platform_from_url("git@bitbucket.org:team/repo.git") == "bitbucket"
76
+
77
+ def test_bitbucket_https(self) -> None:
78
+ assert _detect_platform_from_url("https://bitbucket.org/team/repo.git") == "bitbucket"
79
+
80
+ def test_self_hosted_ssh(self) -> None:
81
+ assert _detect_platform_from_url("git@git.internal.company.com:team/project.git") == "self-hosted"
82
+
83
+ def test_self_hosted_https(self) -> None:
84
+ assert _detect_platform_from_url("https://git.internal.company.com/team/project.git") == "self-hosted"
85
+
86
+ def test_empty_url(self) -> None:
87
+ assert _detect_platform_from_url("") is None
88
+
89
+ def test_none_url(self) -> None:
90
+ assert _detect_platform_from_url("") is None
91
+
92
+
93
+ # ---------------------------------------------------------------------------
94
+ # Remote detection
95
+ # ---------------------------------------------------------------------------
96
+
97
+
98
+ class TestRemoteDetection:
99
+ """Test all remotes listed from git config."""
100
+
101
+ def test_detect_github_platform(
102
+ self, scanner: GitScanner, git_project_github: Path
103
+ ) -> None:
104
+ result = scanner.scan(git_project_github)
105
+ git_section = result.sections["git"]
106
+ assert git_section["platform"] == "github"
107
+
108
+ def test_detect_gitlab_platform(
109
+ self, scanner: GitScanner, git_project_gitlab: Path
110
+ ) -> None:
111
+ result = scanner.scan(git_project_gitlab)
112
+ git_section = result.sections["git"]
113
+ assert git_section["platform"] == "gitlab"
114
+
115
+ def test_detect_bitbucket_platform(
116
+ self, scanner: GitScanner, git_project_bitbucket: Path
117
+ ) -> None:
118
+ result = scanner.scan(git_project_bitbucket)
119
+ git_section = result.sections["git"]
120
+ assert git_section["platform"] == "bitbucket"
121
+
122
+ def test_detect_selfhosted_platform(
123
+ self, scanner: GitScanner, git_project_selfhosted: Path
124
+ ) -> None:
125
+ result = scanner.scan(git_project_selfhosted)
126
+ git_section = result.sections["git"]
127
+ assert git_section["platform"] == "self-hosted"
128
+
129
+ def test_all_remotes_listed(
130
+ self, scanner: GitScanner, git_project_github: Path
131
+ ) -> None:
132
+ result = scanner.scan(git_project_github)
133
+ git_section = result.sections["git"]
134
+ remote_names = [r["name"] for r in git_section["remotes"]]
135
+ assert "origin" in remote_names
136
+ assert "upstream" in remote_names
137
+ assert len(remote_names) == 2
138
+
139
+ def test_remote_has_url_and_platform(
140
+ self, scanner: GitScanner, git_project_github: Path
141
+ ) -> None:
142
+ result = scanner.scan(git_project_github)
143
+ git_section = result.sections["git"]
144
+ origin = [r for r in git_section["remotes"] if r["name"] == "origin"][0]
145
+ assert "github.com" in origin["url"]
146
+ assert origin["platform"] == "github"
147
+
148
+ def test_multiple_remotes_different_platforms(
149
+ self, scanner: GitScanner, tmp_path: Path
150
+ ) -> None:
151
+ create_git_dir(
152
+ tmp_path,
153
+ remote_url="git@github.com:org/repo.git",
154
+ extra_remotes={"upstream": "git@gitlab.com:group/repo.git"},
155
+ )
156
+ result = scanner.scan(tmp_path)
157
+ git_section = result.sections["git"]
158
+ remote_names = [r["name"] for r in git_section["remotes"]]
159
+ assert "origin" in remote_names
160
+ assert "upstream" in remote_names
161
+
162
+
163
+ # ---------------------------------------------------------------------------
164
+ # Default branch detection
165
+ # ---------------------------------------------------------------------------
166
+
167
+
168
+ class TestDefaultBranchDetection:
169
+ """Test default branch detection from HEAD."""
170
+
171
+ def test_detect_main_branch(
172
+ self, scanner: GitScanner, git_project_github: Path
173
+ ) -> None:
174
+ result = scanner.scan(git_project_github)
175
+ git_section = result.sections["git"]
176
+ assert git_section["default_branch"] == "main"
177
+
178
+ def test_detect_master_branch(
179
+ self, scanner: GitScanner, git_project_bitbucket: Path
180
+ ) -> None:
181
+ result = scanner.scan(git_project_bitbucket)
182
+ git_section = result.sections["git"]
183
+ assert git_section["default_branch"] == "master"
184
+
185
+ def test_detect_custom_branch(
186
+ self, scanner: GitScanner, tmp_path: Path
187
+ ) -> None:
188
+ create_git_dir(tmp_path, default_branch="develop")
189
+ result = scanner.scan(tmp_path)
190
+ git_section = result.sections["git"]
191
+ assert git_section["default_branch"] == "develop"
192
+
193
+
194
+ # ---------------------------------------------------------------------------
195
+ # Monorepo workspace detection
196
+ # ---------------------------------------------------------------------------
197
+
198
+
199
+ class TestMonorepoWorkspaceDetection:
200
+ """Test monorepo workspace field in git scanner.
201
+
202
+ Note: Monorepo detection is now owned by StackScanner. The git scanner
203
+ always returns workspace_config=None. These tests verify the git scanner
204
+ no longer duplicates monorepo detection.
205
+ """
206
+
207
+ def test_monorepo_always_none_with_turbo(
208
+ self, scanner: GitScanner, tmp_path: Path
209
+ ) -> None:
210
+ create_git_dir(tmp_path)
211
+ (tmp_path / "turbo.json").write_text("{}")
212
+ result = scanner.scan(tmp_path)
213
+ git_section = result.sections["git"]
214
+ assert git_section["monorepo"]["workspace_config"] is None
215
+
216
+ def test_monorepo_always_none_with_nx(
217
+ self, scanner: GitScanner, tmp_path: Path
218
+ ) -> None:
219
+ create_git_dir(tmp_path)
220
+ (tmp_path / "nx.json").write_text("{}")
221
+ result = scanner.scan(tmp_path)
222
+ git_section = result.sections["git"]
223
+ assert git_section["monorepo"]["workspace_config"] is None
224
+
225
+ def test_monorepo_always_none_with_lerna(
226
+ self, scanner: GitScanner, tmp_path: Path
227
+ ) -> None:
228
+ create_git_dir(tmp_path)
229
+ (tmp_path / "lerna.json").write_text("{}")
230
+ result = scanner.scan(tmp_path)
231
+ git_section = result.sections["git"]
232
+ assert git_section["monorepo"]["workspace_config"] is None
233
+
234
+ def test_monorepo_always_none_with_pnpm(
235
+ self, scanner: GitScanner, tmp_path: Path
236
+ ) -> None:
237
+ create_git_dir(tmp_path)
238
+ (tmp_path / "pnpm-workspace.yaml").write_text("packages:\n - 'packages/*'\n")
239
+ result = scanner.scan(tmp_path)
240
+ git_section = result.sections["git"]
241
+ assert git_section["monorepo"]["workspace_config"] is None
242
+
243
+ def test_monorepo_always_none_with_npm(
244
+ self, scanner: GitScanner, tmp_path: Path
245
+ ) -> None:
246
+ create_git_dir(tmp_path)
247
+ pkg = {"name": "test", "workspaces": ["packages/*"]}
248
+ (tmp_path / "package.json").write_text(json.dumps(pkg))
249
+ result = scanner.scan(tmp_path)
250
+ git_section = result.sections["git"]
251
+ assert git_section["monorepo"]["workspace_config"] is None
252
+
253
+ def test_no_workspace_config(
254
+ self, scanner: GitScanner, git_project_github: Path
255
+ ) -> None:
256
+ result = scanner.scan(git_project_github)
257
+ git_section = result.sections["git"]
258
+ assert git_section["monorepo"]["workspace_config"] is None
259
+
260
+
261
+ # ---------------------------------------------------------------------------
262
+ # Branch strategy detection
263
+ # ---------------------------------------------------------------------------
264
+
265
+
266
+ class TestBranchStrategyDetection:
267
+ """Test branch strategy detection from branch patterns."""
268
+
269
+ def test_detect_gitflow(
270
+ self, scanner: GitScanner, git_project_gitflow: Path
271
+ ) -> None:
272
+ result = scanner.scan(git_project_gitflow)
273
+ git_section = result.sections["git"]
274
+ strategy = git_section["branch_strategy"]
275
+ assert strategy["detected"] is True
276
+ assert strategy["pattern"] == "gitflow"
277
+
278
+ def test_detect_trunk_based(
279
+ self, scanner: GitScanner, tmp_path: Path
280
+ ) -> None:
281
+ create_git_dir(tmp_path, default_branch="main")
282
+ result = scanner.scan(tmp_path)
283
+ git_section = result.sections["git"]
284
+ strategy = git_section["branch_strategy"]
285
+ assert strategy["detected"] is True
286
+ assert strategy["pattern"] == "trunk-based"
287
+
288
+ def test_detect_github_flow(
289
+ self, scanner: GitScanner, tmp_path: Path
290
+ ) -> None:
291
+ create_git_dir(
292
+ tmp_path,
293
+ default_branch="main",
294
+ branches=["feature/new-ui", "feature/api-v2", "fix/bug-123", "chore/deps"],
295
+ )
296
+ result = scanner.scan(tmp_path)
297
+ git_section = result.sections["git"]
298
+ strategy = git_section["branch_strategy"]
299
+ assert strategy["detected"] is True
300
+ assert strategy["pattern"] == "github-flow"
301
+
302
+ def test_gitflow_indicators_include_develop(
303
+ self, scanner: GitScanner, git_project_gitflow: Path
304
+ ) -> None:
305
+ result = scanner.scan(git_project_gitflow)
306
+ strategy = result.sections["git"]["branch_strategy"]
307
+ assert any("develop" in ind for ind in strategy["indicators"])
308
+
309
+
310
+ # ---------------------------------------------------------------------------
311
+ # No .git directory
312
+ # ---------------------------------------------------------------------------
313
+
314
+
315
+ class TestNoGitDirectory:
316
+ """Test behavior when no .git directory exists."""
317
+
318
+ def test_no_git_returns_section_with_nulls(
319
+ self, scanner: GitScanner, empty_project: Path
320
+ ) -> None:
321
+ result = scanner.scan(empty_project)
322
+ git_section = result.sections["git"]
323
+ assert git_section["platform"] is None
324
+ assert git_section["remotes"] == []
325
+ assert git_section["default_branch"] is None
326
+
327
+ def test_no_git_branch_strategy_not_detected(
328
+ self, scanner: GitScanner, empty_project: Path
329
+ ) -> None:
330
+ result = scanner.scan(empty_project)
331
+ strategy = result.sections["git"]["branch_strategy"]
332
+ assert strategy["detected"] is False
333
+
334
+ def test_no_git_still_has_source_tag(
335
+ self, scanner: GitScanner, empty_project: Path
336
+ ) -> None:
337
+ result = scanner.scan(empty_project)
338
+ assert result.sections["git"]["_source"] == "scanner:git"
339
+
340
+ def test_no_git_has_warning(
341
+ self, scanner: GitScanner, empty_project: Path
342
+ ) -> None:
343
+ result = scanner.scan(empty_project)
344
+ assert any("No .git" in w for w in result.warnings)
345
+
346
+
347
+ # ---------------------------------------------------------------------------
348
+ # Git in subdirectory (monorepo wrapper / nested repo)
349
+ # ---------------------------------------------------------------------------
350
+
351
+
352
+ class TestGitInSubdirectory:
353
+ """Test that scanner finds .git in immediate subdirectories."""
354
+
355
+ def test_finds_git_in_subdirectory(
356
+ self, scanner: GitScanner, tmp_path: Path
357
+ ) -> None:
358
+ sub = tmp_path / "my-monorepo"
359
+ sub.mkdir()
360
+ create_git_dir(
361
+ sub,
362
+ remote_url="git@gitlab.com:org/my-monorepo.git",
363
+ default_branch="main",
364
+ )
365
+ result = scanner.scan(tmp_path)
366
+ git_section = result.sections["git"]
367
+ assert git_section["platform"] == "gitlab"
368
+ assert git_section["default_branch"] == "main"
369
+ assert len(git_section["remotes"]) >= 1
370
+
371
+ def test_git_root_field_set_when_in_subdir(
372
+ self, scanner: GitScanner, tmp_path: Path
373
+ ) -> None:
374
+ sub = tmp_path / "qxo-monorepo"
375
+ sub.mkdir()
376
+ create_git_dir(sub)
377
+ result = scanner.scan(tmp_path)
378
+ git_section = result.sections["git"]
379
+ assert git_section["git_root"] == "qxo-monorepo"
380
+
381
+ def test_git_root_not_set_when_at_root(
382
+ self, scanner: GitScanner, tmp_path: Path
383
+ ) -> None:
384
+ create_git_dir(tmp_path)
385
+ result = scanner.scan(tmp_path)
386
+ git_section = result.sections["git"]
387
+ assert "git_root" not in git_section
388
+
389
+ def test_warning_when_git_in_subdir(
390
+ self, scanner: GitScanner, tmp_path: Path
391
+ ) -> None:
392
+ sub = tmp_path / "inner-repo"
393
+ sub.mkdir()
394
+ create_git_dir(sub)
395
+ result = scanner.scan(tmp_path)
396
+ assert any("subdirectory" in w for w in result.warnings)
397
+
398
+ def test_no_git_anywhere_returns_nulls(
399
+ self, scanner: GitScanner, tmp_path: Path
400
+ ) -> None:
401
+ (tmp_path / "some-dir").mkdir()
402
+ result = scanner.scan(tmp_path)
403
+ git_section = result.sections["git"]
404
+ assert git_section["platform"] is None
405
+ assert git_section["remotes"] == []
406
+
407
+ def test_skips_dotdirs_and_vendor(
408
+ self, scanner: GitScanner, tmp_path: Path
409
+ ) -> None:
410
+ # .git in a hidden dir should not be picked up as a subdirectory match
411
+ hidden = tmp_path / ".hidden-repo"
412
+ hidden.mkdir()
413
+ create_git_dir(hidden, remote_url="git@github.com:hidden/repo.git")
414
+ vendor = tmp_path / "vendor"
415
+ vendor.mkdir()
416
+ create_git_dir(vendor, remote_url="git@github.com:vendor/repo.git")
417
+ result = scanner.scan(tmp_path)
418
+ git_section = result.sections["git"]
419
+ assert git_section["platform"] is None