@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,330 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Context Section Reader for Claude Agent System
4
+
5
+ Reads specific sections from project-context.json for selective loading by agents.
6
+ Called by Claude orchestrator BEFORE invoking agents to reduce token usage.
7
+
8
+ Architecture:
9
+ - Claude orchestrator executes this script (NOT agents)
10
+ - Agents receive pre-filtered context in their prompts
11
+ - Reduces token usage by ~70% per agent invocation
12
+
13
+ Usage:
14
+ from .claude.tools.context_section_reader import ContextSectionReader
15
+
16
+ reader = ContextSectionReader()
17
+ context = reader.get_for_agent('gitops-operator')
18
+
19
+ # Pass context to agent in Task tool prompt
20
+ """
21
+
22
+ from pathlib import Path
23
+ from typing import List, Dict, Optional, Any
24
+ import json
25
+
26
+
27
+ def find_claude_dir() -> Path:
28
+ """Find the .claude directory by searching upward from current location"""
29
+ current = Path.cwd()
30
+
31
+ # If we're already in a .claude directory, return it
32
+ if current.name == ".claude":
33
+ return current
34
+
35
+ # Look for .claude in current directory
36
+ claude_dir = current / ".claude"
37
+ if claude_dir.exists():
38
+ return claude_dir
39
+
40
+ # Search upward through parent directories
41
+ for parent in current.parents:
42
+ claude_dir = parent / ".claude"
43
+ if claude_dir.exists():
44
+ return claude_dir
45
+
46
+ # Fallback - raise error if not found
47
+ raise FileNotFoundError(
48
+ "No .claude directory found. Please run from a project directory "
49
+ "or specify context_file explicitly."
50
+ )
51
+
52
+
53
+ class ContextSectionReader:
54
+ """
55
+ Read and filter sections from project-context.json for agent-specific loading.
56
+
57
+ Token Optimization:
58
+ - Without filtering: ~328 lines (1,312 tokens)
59
+ - With filtering: ~80-100 lines (320-400 tokens)
60
+ - Savings: ~70% per agent invocation
61
+ """
62
+
63
+ # Define which sections each agent needs (JSON keys in snake_case)
64
+ # Aligned with v2 scanner sections from context-contracts.json v3
65
+ AGENT_SECTIONS = {
66
+ 'gitops-operator': [
67
+ 'project_identity',
68
+ 'stack',
69
+ 'git',
70
+ 'environment',
71
+ 'infrastructure',
72
+ 'orchestration',
73
+ 'gitops_configuration',
74
+ 'cluster_details',
75
+ 'operational_guidelines',
76
+ 'application_services',
77
+ ],
78
+ 'cloud-troubleshooter': [
79
+ 'project_identity',
80
+ 'stack',
81
+ 'git',
82
+ 'environment',
83
+ 'infrastructure',
84
+ 'orchestration',
85
+ 'cluster_details',
86
+ 'infrastructure_topology',
87
+ 'terraform_infrastructure',
88
+ 'gitops_configuration',
89
+ 'application_services',
90
+ 'monitoring_observability',
91
+ ],
92
+ 'terraform-architect': [
93
+ 'project_identity',
94
+ 'stack',
95
+ 'git',
96
+ 'environment',
97
+ 'infrastructure',
98
+ 'orchestration',
99
+ 'terraform_infrastructure',
100
+ 'infrastructure_topology',
101
+ 'operational_guidelines',
102
+ 'cluster_details',
103
+ 'application_services',
104
+ ],
105
+ 'devops-developer': [
106
+ 'project_identity',
107
+ 'stack',
108
+ 'git',
109
+ 'environment',
110
+ 'infrastructure',
111
+ 'application_services',
112
+ 'operational_guidelines',
113
+ ],
114
+ }
115
+
116
+ def __init__(self, context_file: Optional[str] = None):
117
+ """
118
+ Initialize reader with project context file.
119
+
120
+ Args:
121
+ context_file: Path to project-context.json (default: searches for .claude/project-context/project-context.json)
122
+ """
123
+ if context_file is None:
124
+ # Find the .claude directory by searching upward
125
+ claude_dir = find_claude_dir()
126
+ # Try project-context/ subdirectory first (new location)
127
+ context_file = claude_dir / "project-context" / "project-context.json"
128
+ if not Path(context_file).exists():
129
+ # Fallback to root .claude/ (old location)
130
+ context_file = claude_dir / "project-context.json"
131
+
132
+ self.path = Path(context_file)
133
+
134
+ if not self.path.exists():
135
+ raise FileNotFoundError(f"Context file not found: {self.path}")
136
+
137
+ with open(self.path, 'r', encoding='utf-8') as f:
138
+ self.data = json.load(f)
139
+
140
+ self._parse_sections()
141
+
142
+ def _parse_sections(self) -> None:
143
+ """Extract sections from JSON data."""
144
+ self.sections: Dict[str, Any] = {}
145
+
146
+ # Extract sections from JSON
147
+ if 'sections' in self.data:
148
+ self.sections = self.data['sections']
149
+ else:
150
+ raise ValueError("Invalid JSON structure: 'sections' key not found")
151
+
152
+ def get_sections(self, section_names: List[str]) -> str:
153
+ """
154
+ Get specific sections as formatted JSON string.
155
+
156
+ Args:
157
+ section_names: List of section names to retrieve
158
+
159
+ Returns:
160
+ Formatted JSON string with requested sections
161
+ """
162
+ result = {}
163
+ missing = []
164
+
165
+ for name in section_names:
166
+ if name in self.sections:
167
+ result[name] = self.sections[name]
168
+ else:
169
+ missing.append(name)
170
+
171
+ if missing:
172
+ print(f"Warning: Sections not found: {missing}")
173
+
174
+ if not result:
175
+ return json.dumps({
176
+ "error": "No sections found",
177
+ "message": "Requested sections were not available."
178
+ }, indent=2)
179
+
180
+ # Format as JSON for agent consumption
181
+ return json.dumps(result, indent=2, ensure_ascii=False)
182
+
183
+ def get_for_agent(self, agent_name: str) -> str:
184
+ """
185
+ Get sections needed by specific agent.
186
+
187
+ Args:
188
+ agent_name: Name of the agent (e.g., 'gitops-operator')
189
+
190
+ Returns:
191
+ Markdown string with agent-specific context
192
+
193
+ Raises:
194
+ ValueError: If agent_name is not recognized
195
+ """
196
+ if agent_name not in self.AGENT_SECTIONS:
197
+ available = ', '.join(self.AGENT_SECTIONS.keys())
198
+ raise ValueError(
199
+ f"Unknown agent: {agent_name}. "
200
+ f"Available agents: {available}"
201
+ )
202
+
203
+ sections = self.AGENT_SECTIONS[agent_name]
204
+ return self.get_sections(sections)
205
+
206
+ def list_sections(self) -> List[str]:
207
+ """Get list of all available sections."""
208
+ return list(self.sections.keys())
209
+
210
+ def get_stats(self) -> Dict[str, Any]:
211
+ """
212
+ Get statistics about the context file.
213
+
214
+ Returns:
215
+ Dictionary with size and token estimates
216
+ """
217
+ # Calculate total JSON size
218
+ total_json = json.dumps(self.data, ensure_ascii=False)
219
+ total_chars = len(total_json)
220
+ total_tokens = total_chars // 4 # Rough estimate: 4 chars per token
221
+
222
+ return {
223
+ 'total_chars': total_chars,
224
+ 'total_tokens_estimated': total_tokens,
225
+ 'total_sections': len(self.sections),
226
+ 'sections': {
227
+ name: {
228
+ 'chars': len(json.dumps(content, ensure_ascii=False)),
229
+ 'tokens_estimated': len(json.dumps(content, ensure_ascii=False)) // 4
230
+ }
231
+ for name, content in self.sections.items()
232
+ }
233
+ }
234
+
235
+ def get_agent_stats(self, agent_name: str) -> Dict[str, Any]:
236
+ """
237
+ Get statistics for a specific agent's context.
238
+
239
+ Args:
240
+ agent_name: Name of the agent
241
+
242
+ Returns:
243
+ Dictionary with character and token counts for agent
244
+ """
245
+ context = self.get_for_agent(agent_name)
246
+ chars = len(context)
247
+ tokens = chars // 4
248
+
249
+ full_stats = self.get_stats()
250
+ savings = {
251
+ 'chars': full_stats['total_chars'] - chars,
252
+ 'tokens': full_stats['total_tokens_estimated'] - tokens,
253
+ 'percentage': round((1 - chars / full_stats['total_chars']) * 100, 1)
254
+ }
255
+
256
+ return {
257
+ 'agent': agent_name,
258
+ 'chars_loaded': chars,
259
+ 'tokens_estimated': tokens,
260
+ 'savings': savings
261
+ }
262
+
263
+
264
+ def main():
265
+ """CLI interface for testing and debugging."""
266
+ import sys
267
+ import json
268
+
269
+ reader = ContextSectionReader()
270
+
271
+ if len(sys.argv) < 2:
272
+ print("Context Section Reader")
273
+ print("\nUsage:")
274
+ print(" python context_section_reader.py <command> [args]")
275
+ print("\nCommands:")
276
+ print(" list - List all available sections")
277
+ print(" stats - Show statistics for context file")
278
+ print(" agent <name> - Get context for specific agent")
279
+ print(" agent-stats <name> - Show stats for agent's context")
280
+ print(" sections <name1> <name2> - Get specific sections")
281
+ print("\nAvailable agents:")
282
+ for agent in reader.AGENT_SECTIONS.keys():
283
+ print(f" - {agent}")
284
+ sys.exit(0)
285
+
286
+ command = sys.argv[1]
287
+
288
+ if command == 'list':
289
+ print("Available sections:")
290
+ for section in reader.list_sections():
291
+ print(f" - {section}")
292
+
293
+ elif command == 'stats':
294
+ stats = reader.get_stats()
295
+ print(json.dumps(stats, indent=2))
296
+
297
+ elif command == 'agent':
298
+ if len(sys.argv) < 3:
299
+ print("Error: Agent name required")
300
+ sys.exit(1)
301
+
302
+ agent_name = sys.argv[2]
303
+ context = reader.get_for_agent(agent_name)
304
+ print(context)
305
+
306
+ elif command == 'agent-stats':
307
+ if len(sys.argv) < 3:
308
+ print("Error: Agent name required")
309
+ sys.exit(1)
310
+
311
+ agent_name = sys.argv[2]
312
+ stats = reader.get_agent_stats(agent_name)
313
+ print(json.dumps(stats, indent=2))
314
+
315
+ elif command == 'sections':
316
+ if len(sys.argv) < 3:
317
+ print("Error: Section names required")
318
+ sys.exit(1)
319
+
320
+ section_names = sys.argv[2:]
321
+ context = reader.get_sections(section_names)
322
+ print(context)
323
+
324
+ else:
325
+ print(f"Unknown command: {command}")
326
+ sys.exit(1)
327
+
328
+
329
+ if __name__ == '__main__':
330
+ main()
@@ -0,0 +1,159 @@
1
+ """
2
+ Deep merge utility for project-context.json updates.
3
+
4
+ Merges two dicts recursively following the gaia-ops merge decision tree:
5
+ 1. Key missing in current -> ADD
6
+ 2. Both values are dicts -> RECURSE (deep merge)
7
+ 3. Both values are lists -> UNION (primitives: sorted set union;
8
+ dicts with "name": merge by name;
9
+ other dicts: concatenate + deduplicate)
10
+ 4. Both values are scalars -> OVERWRITE (new replaces old)
11
+ 5. Type mismatch -> OVERWRITE with warning
12
+
13
+ No-Delete Policy: keys in current but NOT in update are always preserved.
14
+ """
15
+
16
+ import copy
17
+ import json
18
+ import logging
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+
23
+ def deep_merge(current: dict, update: dict) -> tuple[dict, dict]:
24
+ """Merge *update* into *current* returning ``(merged, diff)``.
25
+
26
+ Parameters
27
+ ----------
28
+ current:
29
+ The existing data (will NOT be mutated).
30
+ update:
31
+ New data to merge on top of *current*.
32
+
33
+ Returns
34
+ -------
35
+ tuple[dict, dict]
36
+ ``merged`` – the result of the merge.
37
+ ``diff`` – audit trail recording changes (``{key: {old, new}}``).
38
+ """
39
+ merged = copy.deepcopy(current)
40
+ diff: dict = {}
41
+
42
+ for key, new_value in update.items():
43
+ if key not in merged:
44
+ # Rule 1: ADD missing key
45
+ merged[key] = copy.deepcopy(new_value)
46
+ continue
47
+
48
+ old_value = merged[key]
49
+
50
+ # Rule 2: Both dicts -> recurse
51
+ if isinstance(old_value, dict) and isinstance(new_value, dict):
52
+ sub_merged, sub_diff = deep_merge(old_value, new_value)
53
+ merged[key] = sub_merged
54
+ if sub_diff:
55
+ diff[key] = sub_diff
56
+ continue
57
+
58
+ # Rule 3: Both lists -> union strategy
59
+ if isinstance(old_value, list) and isinstance(new_value, list):
60
+ merged_list = _merge_lists(old_value, new_value)
61
+ if merged_list != old_value:
62
+ diff[key] = {"old": old_value, "new": merged_list}
63
+ merged[key] = merged_list
64
+ continue
65
+
66
+ # Rule 5: Type mismatch -> overwrite with warning
67
+ if type(old_value) is not type(new_value):
68
+ logger.warning(
69
+ "Type mismatch for key '%s': %s -> %s. New value wins.",
70
+ key,
71
+ type(old_value).__name__,
72
+ type(new_value).__name__,
73
+ )
74
+ diff[key] = {"old": old_value, "new": new_value}
75
+ merged[key] = copy.deepcopy(new_value)
76
+ continue
77
+
78
+ # Rule 4: Both scalars -> overwrite
79
+ if old_value != new_value:
80
+ diff[key] = {"old": old_value, "new": new_value}
81
+ merged[key] = copy.deepcopy(new_value)
82
+
83
+ return merged, diff
84
+
85
+
86
+ # ---------------------------------------------------------------------------
87
+ # List merge helpers
88
+ # ---------------------------------------------------------------------------
89
+
90
+ def _merge_lists(current: list, update: list) -> list:
91
+ """Merge two lists following the union strategy.
92
+
93
+ a) All items are primitives (str, int, float, bool) -> sorted set union.
94
+ b) Items are dicts with a ``"name"`` key -> merge by name, preserve missing.
95
+ c) Otherwise -> concatenate, deduplicate by JSON equality.
96
+ """
97
+ if _all_primitives(current) and _all_primitives(update):
98
+ return sorted(set(current) | set(update))
99
+
100
+ if _all_dicts_with_name(current) and _all_dicts_with_name(update):
101
+ return _merge_named_dicts(current, update)
102
+
103
+ # Fallback: concatenate + deduplicate by JSON equality
104
+ return _concat_deduplicate(current, update)
105
+
106
+
107
+ def _all_primitives(items: list) -> bool:
108
+ """Return True if every item is a primitive (str, int, float, bool)."""
109
+ return all(isinstance(i, (str, int, float, bool)) for i in items)
110
+
111
+
112
+ def _all_dicts_with_name(items: list) -> bool:
113
+ """Return True if every item is a dict containing a ``"name"`` key."""
114
+ return bool(items) and all(
115
+ isinstance(i, dict) and "name" in i for i in items
116
+ )
117
+
118
+
119
+ def _merge_named_dicts(current: list[dict], update: list[dict]) -> list[dict]:
120
+ """Merge lists of dicts by their ``"name"`` field.
121
+
122
+ - Matching names: deep-merge the dict fields.
123
+ - Names only in current: preserved (no-delete).
124
+ - Names only in update: appended.
125
+ """
126
+ result_by_name: dict[str, dict] = {}
127
+ order: list[str] = []
128
+
129
+ # Seed with current entries (preserves order + no-delete)
130
+ for item in current:
131
+ name = item["name"]
132
+ result_by_name[name] = copy.deepcopy(item)
133
+ order.append(name)
134
+
135
+ # Merge / add from update
136
+ for item in update:
137
+ name = item["name"]
138
+ if name in result_by_name:
139
+ merged_item, _ = deep_merge(result_by_name[name], item)
140
+ result_by_name[name] = merged_item
141
+ else:
142
+ result_by_name[name] = copy.deepcopy(item)
143
+ order.append(name)
144
+
145
+ return [result_by_name[n] for n in order]
146
+
147
+
148
+ def _concat_deduplicate(current: list, update: list) -> list:
149
+ """Concatenate two lists, deduplicating by JSON equality."""
150
+ seen: list[str] = []
151
+ result: list = []
152
+
153
+ for item in current + update:
154
+ serialized = json.dumps(item, sort_keys=True)
155
+ if serialized not in seen:
156
+ seen.append(serialized)
157
+ result.append(copy.deepcopy(item))
158
+
159
+ return result