@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,266 @@
1
+ """
2
+ Health Check / Verification Functions for gaia-scan
3
+
4
+ Provides post-install verification checks to confirm that the
5
+ gaia-ops installation is healthy. Used after fresh install (Mode 1)
6
+ and after rescan+sync (Mode 2).
7
+
8
+ Functions:
9
+ - run_verification: run all checks, return summary
10
+ - check_symlinks: verify symlinks exist and are valid
11
+ - check_claude_md: legacy check (CLAUDE.md no longer generated)
12
+ - check_settings_json: verify valid JSON
13
+ - check_project_context: verify exists and has sections
14
+ - check_python: verify python3 available
15
+ - check_hooks: verify pre_tool_use.py exists
16
+ """
17
+
18
+ import json
19
+ import logging
20
+ import subprocess
21
+ import sys
22
+ from dataclasses import dataclass
23
+ from pathlib import Path
24
+ from typing import List, Optional
25
+
26
+ logger = logging.getLogger(__name__)
27
+
28
+
29
+ @dataclass
30
+ class CheckResult:
31
+ """Result of a single health check.
32
+
33
+ Attributes:
34
+ name: Check name for display.
35
+ ok: Whether the check passed.
36
+ detail: Human-readable detail string.
37
+ fix: Optional fix suggestion if check failed.
38
+ """
39
+ name: str
40
+ ok: bool
41
+ detail: str = ""
42
+ fix: Optional[str] = None
43
+
44
+
45
+ def check_symlinks(project_root: Path) -> CheckResult:
46
+ """Verify that all expected symlinks exist in .claude/.
47
+
48
+ Checks for: agents, tools, hooks, commands, templates, config,
49
+ speckit, skills, CHANGELOG.md (9 total).
50
+
51
+ Args:
52
+ project_root: Project root directory.
53
+
54
+ Returns:
55
+ CheckResult with count of valid symlinks.
56
+ """
57
+ names = [
58
+ "agents", "tools", "hooks", "commands",
59
+ "templates", "config", "speckit", "skills",
60
+ "CHANGELOG.md",
61
+ ]
62
+ valid = 0
63
+ for name in names:
64
+ link_path = project_root / ".claude" / name
65
+ if link_path.exists() or link_path.is_symlink():
66
+ valid += 1
67
+
68
+ return CheckResult(
69
+ name="Symlinks",
70
+ ok=valid == len(names),
71
+ detail=f"{valid}/{len(names)} valid",
72
+ fix="Run gaia-scan to recreate symlinks" if valid < len(names) else None,
73
+ )
74
+
75
+
76
+ def check_claude_md(project_root: Path) -> CheckResult:
77
+ """Check for CLAUDE.md presence. No longer required -- identity injected by hook.
78
+
79
+ Kept for backward compatibility with callers that expect this check.
80
+ """
81
+ path = project_root / "CLAUDE.md"
82
+ if path.is_file():
83
+ return CheckResult(
84
+ name="CLAUDE.md",
85
+ ok=True,
86
+ detail="Present (legacy -- identity now injected by hook)",
87
+ )
88
+ return CheckResult(
89
+ name="CLAUDE.md",
90
+ ok=True,
91
+ detail="Not present (identity injected by UserPromptSubmit hook)",
92
+ )
93
+
94
+
95
+ def check_settings_json(project_root: Path) -> CheckResult:
96
+ """Verify that .claude/settings.json exists and is valid JSON.
97
+
98
+ Args:
99
+ project_root: Project root directory.
100
+
101
+ Returns:
102
+ CheckResult.
103
+ """
104
+ path = project_root / ".claude" / "settings.json"
105
+ if not path.is_file():
106
+ return CheckResult(
107
+ name="settings.json",
108
+ ok=False,
109
+ detail="Missing",
110
+ fix="Run gaia-scan",
111
+ )
112
+
113
+ try:
114
+ json.loads(path.read_text())
115
+ return CheckResult(name="settings.json", ok=True, detail="Valid JSON")
116
+ except (json.JSONDecodeError, OSError):
117
+ return CheckResult(
118
+ name="settings.json",
119
+ ok=False,
120
+ detail="Invalid JSON",
121
+ fix="Delete and run gaia-scan",
122
+ )
123
+
124
+
125
+ def check_project_context(project_root: Path) -> CheckResult:
126
+ """Verify that project-context.json exists and has sections.
127
+
128
+ Args:
129
+ project_root: Project root directory.
130
+
131
+ Returns:
132
+ CheckResult with section count.
133
+ """
134
+ path = project_root / ".claude" / "project-context" / "project-context.json"
135
+ if not path.is_file():
136
+ return CheckResult(
137
+ name="project-context",
138
+ ok=False,
139
+ detail="Missing",
140
+ fix="Run gaia-scan",
141
+ )
142
+
143
+ try:
144
+ data = json.loads(path.read_text())
145
+ sections = len(data.get("sections", {}))
146
+ return CheckResult(
147
+ name="project-context",
148
+ ok=sections >= 3,
149
+ detail=f"{sections} sections",
150
+ fix="Run gaia-scan to regenerate" if sections < 3 else None,
151
+ )
152
+ except (json.JSONDecodeError, OSError):
153
+ return CheckResult(
154
+ name="project-context",
155
+ ok=False,
156
+ detail="Invalid JSON",
157
+ fix="Run gaia-scan to regenerate",
158
+ )
159
+
160
+
161
+ def check_python() -> CheckResult:
162
+ """Verify that python3 is available.
163
+
164
+ Returns:
165
+ CheckResult with Python version.
166
+ """
167
+ try:
168
+ result = subprocess.run(
169
+ ["python3", "--version"],
170
+ capture_output=True,
171
+ text=True,
172
+ timeout=5,
173
+ )
174
+ if result.returncode == 0:
175
+ version = result.stdout.strip()
176
+ return CheckResult(name="Python", ok=True, detail=version)
177
+ except (subprocess.TimeoutExpired, FileNotFoundError, OSError):
178
+ pass
179
+
180
+ return CheckResult(
181
+ name="Python",
182
+ ok=False,
183
+ detail="Not found",
184
+ fix="Install Python 3.9+",
185
+ )
186
+
187
+
188
+ def check_hooks(project_root: Path) -> CheckResult:
189
+ """Verify that pre_tool_use.py hook exists.
190
+
191
+ Args:
192
+ project_root: Project root directory.
193
+
194
+ Returns:
195
+ CheckResult.
196
+ """
197
+ hook_path = project_root / ".claude" / "hooks" / "pre_tool_use.py"
198
+ if hook_path.exists():
199
+ return CheckResult(name="Hooks", ok=True, detail="pre_tool_use.py found")
200
+
201
+ return CheckResult(
202
+ name="Hooks",
203
+ ok=False,
204
+ detail="pre_tool_use.py missing",
205
+ fix="Run gaia-scan to recreate symlinks",
206
+ )
207
+
208
+
209
+ def run_verification(project_root: Path) -> List[CheckResult]:
210
+ """Run all post-install verification checks.
211
+
212
+ Args:
213
+ project_root: Project root directory.
214
+
215
+ Returns:
216
+ List of CheckResult objects (all checks always run).
217
+ """
218
+ checks = [
219
+ check_symlinks(project_root),
220
+ check_claude_md(project_root),
221
+ check_settings_json(project_root),
222
+ check_project_context(project_root),
223
+ check_python(),
224
+ check_hooks(project_root),
225
+ ]
226
+ return checks
227
+
228
+
229
+ def print_verification(results: List[CheckResult]) -> bool:
230
+ """Print verification results in a human-readable format.
231
+
232
+ Args:
233
+ results: List of CheckResult objects.
234
+
235
+ Returns:
236
+ True if all checks passed.
237
+ """
238
+ supports_color = hasattr(sys.stderr, "isatty") and sys.stderr.isatty()
239
+
240
+ def _green(t: str) -> str:
241
+ return f"\033[32m{t}\033[0m" if supports_color else t
242
+
243
+ def _yellow(t: str) -> str:
244
+ return f"\033[33m{t}\033[0m" if supports_color else t
245
+
246
+ def _red(t: str) -> str:
247
+ return f"\033[31m{t}\033[0m" if supports_color else t
248
+
249
+ def _gray(t: str) -> str:
250
+ return f"\033[90m{t}\033[0m" if supports_color else t
251
+
252
+ print("\n Verifying installation...\n", file=sys.stderr)
253
+
254
+ all_passed = True
255
+ for r in results:
256
+ padded = r.name.ljust(18)
257
+ if r.ok:
258
+ print(_green(f" ✓ {padded} {r.detail}"), file=sys.stderr)
259
+ else:
260
+ print(_yellow(f" ⚠ {padded} {r.detail}"), file=sys.stderr)
261
+ if r.fix:
262
+ print(_gray(f" Fix: {r.fix}"), file=sys.stderr)
263
+ all_passed = False
264
+
265
+ print("", file=sys.stderr)
266
+ return all_passed
@@ -0,0 +1,118 @@
1
+ """
2
+ Filtered os.walk utility for scan performance.
3
+
4
+ Replaces pathlib.rglob with a single filtered os.walk pass that prunes
5
+ expensive directories (node_modules, .git, .terraform, etc.) before descending.
6
+ """
7
+
8
+ import os
9
+ from pathlib import Path
10
+ from typing import FrozenSet, Iterator, Sequence
11
+
12
+ # Directories to skip during scanning -- shared across all scanners
13
+ SKIP_DIRS: FrozenSet[str] = frozenset({
14
+ "node_modules",
15
+ ".git",
16
+ "__pycache__",
17
+ ".terraform",
18
+ ".terragrunt-cache",
19
+ "vendor",
20
+ "dist",
21
+ "build",
22
+ ".venv",
23
+ "venv",
24
+ ".cache",
25
+ ".npm",
26
+ ".next",
27
+ ".nuxt",
28
+ "target",
29
+ ".pytest_cache",
30
+ ".mypy_cache",
31
+ ".ruff_cache",
32
+ ".tox",
33
+ })
34
+
35
+
36
+ def walk_project(root: Path, extensions: Sequence[str]) -> Iterator[Path]:
37
+ """Walk project tree yielding files matching given extensions.
38
+
39
+ Prunes SKIP_DIRS and hidden directories (starting with '.') to avoid
40
+ descending into expensive subtrees like node_modules or .terraform.
41
+
42
+ Much faster than pathlib.rglob on large monorepos because rglob
43
+ traverses every directory before filtering.
44
+
45
+ Args:
46
+ root: Absolute path to start walking from.
47
+ extensions: Sequence of file extensions to match (e.g., [".tf", ".hcl"]).
48
+
49
+ Yields:
50
+ Path objects for matching files.
51
+ """
52
+ root_str = str(root)
53
+ ext_set = set(extensions)
54
+
55
+ for dirpath, dirnames, filenames in os.walk(root_str):
56
+ # Prune in-place to prevent os.walk from descending
57
+ dirnames[:] = [
58
+ d for d in dirnames
59
+ if d not in SKIP_DIRS and not d.startswith(".")
60
+ ]
61
+
62
+ for f in filenames:
63
+ # Check extension by finding the last dot
64
+ dot_idx = f.rfind(".")
65
+ if dot_idx >= 0 and f[dot_idx:] in ext_set:
66
+ yield Path(dirpath) / f
67
+
68
+
69
+ def walk_project_prefix(root: Path, prefixes: Sequence[str]) -> Iterator[Path]:
70
+ """Walk project tree yielding files whose names start with given prefixes.
71
+
72
+ Useful for patterns like 'Dockerfile.*' where the prefix is 'Dockerfile.'.
73
+
74
+ Args:
75
+ root: Absolute path to start walking from.
76
+ prefixes: Sequence of filename prefixes to match.
77
+
78
+ Yields:
79
+ Path objects for matching files.
80
+ """
81
+ root_str = str(root)
82
+
83
+ for dirpath, dirnames, filenames in os.walk(root_str):
84
+ dirnames[:] = [
85
+ d for d in dirnames
86
+ if d not in SKIP_DIRS and not d.startswith(".")
87
+ ]
88
+
89
+ for f in filenames:
90
+ if any(f.startswith(p) for p in prefixes):
91
+ yield Path(dirpath) / f
92
+
93
+
94
+ def walk_project_named(root: Path, filenames: Sequence[str]) -> Iterator[Path]:
95
+ """Walk project tree yielding files matching exact filenames.
96
+
97
+ Same pruning as walk_project but matches on exact filename rather than
98
+ extension. Useful for files like 'Dockerfile', 'Chart.yaml', etc.
99
+
100
+ Args:
101
+ root: Absolute path to start walking from.
102
+ filenames: Sequence of exact filenames to match.
103
+
104
+ Yields:
105
+ Path objects for matching files.
106
+ """
107
+ root_str = str(root)
108
+ name_set = set(filenames)
109
+
110
+ for dirpath, dirnames, fnames in os.walk(root_str):
111
+ dirnames[:] = [
112
+ d for d in dirnames
113
+ if d not in SKIP_DIRS and not d.startswith(".")
114
+ ]
115
+
116
+ for f in fnames:
117
+ if f in name_set:
118
+ yield Path(dirpath) / f
@@ -0,0 +1,85 @@
1
+ """
2
+ Workspace Type Detection
3
+
4
+ Detects whether the scan root is a single-repo, monorepo, or multi-repo workspace.
5
+ Called by the orchestrator before individual scanners run, and importable by scanners
6
+ that need workspace-aware behavior.
7
+
8
+ Detection logic:
9
+ - If root has .git -> single-repo or monorepo (determined by stack scanner)
10
+ - If root has NO .git but 2+ immediate subdirectories have .git -> multi-repo-workspace
11
+ - Otherwise -> single-repo (default)
12
+ """
13
+
14
+ import logging
15
+ from dataclasses import dataclass, field
16
+ from pathlib import Path
17
+ from typing import List, Optional
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+ # Directories to always skip during workspace scanning
22
+ _SKIP_DIRS = frozenset({
23
+ "node_modules", "__pycache__", ".tox", ".venv",
24
+ "venv", "dist", "build", ".next", ".nuxt", "target",
25
+ ".pytest_cache", ".mypy_cache", ".ruff_cache", "vendor",
26
+ ".terraform", ".terragrunt-cache",
27
+ })
28
+
29
+
30
+ @dataclass(frozen=True)
31
+ class WorkspaceInfo:
32
+ """Result of workspace type detection.
33
+
34
+ Attributes:
35
+ workspace_type: One of 'single-repo', 'monorepo', 'multi-repo-workspace'.
36
+ repo_dirs: For multi-repo, list of subdirectory Paths that contain .git.
37
+ Empty for single-repo/monorepo.
38
+ """
39
+
40
+ workspace_type: str = "single-repo"
41
+ repo_dirs: List[Path] = field(default_factory=list)
42
+
43
+ @property
44
+ def is_multi_repo(self) -> bool:
45
+ return self.workspace_type == "multi-repo-workspace"
46
+
47
+
48
+ def detect_workspace_type(root: Path) -> WorkspaceInfo:
49
+ """Detect the workspace type for the given root directory.
50
+
51
+ Args:
52
+ root: Absolute path to the project root directory.
53
+
54
+ Returns:
55
+ WorkspaceInfo with the detected workspace type and repo directories.
56
+ """
57
+ # If root itself has .git, it's a normal repo (single or monorepo)
58
+ if (root / ".git").is_dir():
59
+ return WorkspaceInfo(workspace_type="single-repo")
60
+
61
+ # Check immediate subdirectories for .git
62
+ git_subdirs: List[Path] = []
63
+ try:
64
+ for entry in sorted(root.iterdir()):
65
+ if not entry.is_dir():
66
+ continue
67
+ if entry.name.startswith(".") or entry.name in _SKIP_DIRS:
68
+ continue
69
+ if (entry / ".git").is_dir():
70
+ git_subdirs.append(entry)
71
+ except (PermissionError, OSError) as exc:
72
+ logger.debug("Failed to scan subdirectories of %s: %s", root, exc)
73
+
74
+ if len(git_subdirs) >= 2:
75
+ logger.info(
76
+ "Multi-repo workspace detected: %d repos in %s",
77
+ len(git_subdirs),
78
+ root,
79
+ )
80
+ return WorkspaceInfo(
81
+ workspace_type="multi-repo-workspace",
82
+ repo_dirs=git_subdirs,
83
+ )
84
+
85
+ return WorkspaceInfo(workspace_type="single-repo")