@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
@@ -8,7 +8,7 @@
8
8
  {
9
9
  "name": "gaia-security",
10
10
  "description": "Keeps you in the loop only when it matters. Gaia Security analyzes every command and classifies it into risk tiers: read-only queries run freely, simulations and validations pass through, and state-changing operations (create, delete, apply, push) pause for your explicit approval before executing. Irreversible commands like dropping databases or deleting cloud infrastructure are permanently blocked.",
11
- "version": "4.4.0",
11
+ "version": "4.7.2",
12
12
  "source": "./dist/gaia-security"
13
13
  }
14
14
  ]
@@ -1,15 +1,24 @@
1
1
  {
2
2
  "name": "gaia-ops",
3
- "version": "4.4.0",
3
+ "version": "4.7.2",
4
4
  "description": "Security-first orchestrator with specialized agents, hooks, and governance for AI coding",
5
5
  "author": {
6
6
  "name": "jaguilar87"
7
7
  },
8
8
  "repository": "https://github.com/metraton/gaia-ops",
9
9
  "license": "MIT",
10
- "keywords": ["security", "devops", "orchestrator", "governance"],
10
+ "keywords": [
11
+ "security",
12
+ "devops",
13
+ "orchestrator",
14
+ "governance"
15
+ ],
11
16
  "engines": {
12
17
  "claude-code": ">=2.1.0"
13
18
  },
14
- "categories": ["devops", "security", "orchestration"]
19
+ "categories": [
20
+ "devops",
21
+ "security",
22
+ "orchestration"
23
+ ]
15
24
  }
package/ARCHITECTURE.md CHANGED
@@ -25,7 +25,8 @@ User request
25
25
  v
26
26
  user_prompt_submit.py (UserPromptSubmit hook)
27
27
  | Inject orchestrator identity via ops_identity.py
28
- | Skills loaded on-demand: project-dispatch, agent-response
28
+ | Inject surface routing recommendation (deterministic)
29
+ | Skills loaded on-demand: agent-response
29
30
  v
30
31
  Orchestrator dispatches to agent
31
32
  | Routes by surface classification
@@ -49,7 +50,7 @@ subagent_stop.py (SubagentStop hook)
49
50
  v
50
51
  Orchestrator processes json:contract (via agent-response skill)
51
52
  | COMPLETE -> summarize to user
52
- | AWAITING_APPROVAL -> get approval -> resume via SendMessage
53
+ | REVIEW (with approval_id) -> get approval -> resume via SendMessage
53
54
  | NEEDS_INPUT -> ask user -> resume via SendMessage
54
55
  | BLOCKED -> report blocker
55
56
  ```
@@ -170,7 +171,7 @@ Nonce-based T3 approval lifecycle:
170
171
  3. BashValidator generates 128-bit nonce via generate_nonce()
171
172
  4. write_pending_approval() saves pending-{nonce}.json to .claude/cache/approvals/
172
173
  5. Hook returns corrective deny (exit 0) with NONCE:{hex} in message
173
- 6. Agent includes NONCE:{hex} in PENDING_APPROVAL status to orchestrator
174
+ 6. Agent includes NONCE:{hex} in REVIEW status to orchestrator
174
175
  7. Orchestrator presents plan to user, asks for approval
175
176
  8. User approves -> orchestrator resumes agent with "APPROVE:{nonce}"
176
177
  9. pre_tool_use.py detects APPROVE: prefix, calls activate_pending_approval()
@@ -182,7 +183,7 @@ Nonce-based T3 approval lifecycle:
182
183
 
183
184
  Every agent response must end with a `json:contract` block containing `agent_status`. The contract validator (`hooks/modules/agents/contract_validator.py`) enforces:
184
185
 
185
- - **AGENT_STATUS**: PLAN_STATUS (from 6 valid states: COMPLETE, NEEDS_INPUT, REVIEW, AWAITING_APPROVAL, BLOCKED, IN_PROGRESS), PENDING_STEPS, NEXT_ACTION, AGENT_ID
186
+ - **AGENT_STATUS**: PLAN_STATUS (from 5 valid states: COMPLETE, NEEDS_INPUT, REVIEW, BLOCKED, IN_PROGRESS), PENDING_STEPS, NEXT_ACTION, AGENT_ID
186
187
  - **EVIDENCE_REPORT**: required for all valid states. Seven fields: PATTERNS_CHECKED, FILES_CHECKED, COMMANDS_RUN, KEY_OUTPUTS, VERBATIM_OUTPUTS, CROSS_LAYER_IMPACTS, OPEN_GAPS
187
188
  - **CONSOLIDATION_REPORT**: required when multi-surface or cross-check. Fields: OWNERSHIP_ASSESSMENT (enum), CONFIRMED_FINDINGS, SUSPECTED_FINDINGS, CONFLICTS, OPEN_GAPS, NEXT_BEST_AGENT
188
189
 
@@ -256,12 +257,12 @@ The adapter layer connects Claude Code's hook protocol to gaia-ops business logi
256
257
  | **Adapter methods called** | `ClaudeCodeAdapter.format_validation_response()` |
257
258
  | **Business logic modules** | None (pure formatting bridge) |
258
259
 
259
- ### CP-5: `templates/settings.template.json` / `hooks/hooks.json` -- Hook Configuration
260
+ ### CP-5: `hooks/hooks.json` -- Hook Configuration
260
261
 
261
262
  | Attribute | Value |
262
263
  |-----------|-------|
263
- | **File (npm channel)** | `templates/settings.template.json` -- paths use `.claude/hooks/` prefix |
264
264
  | **File (plugin channel)** | `hooks/hooks.json` -- paths use `${CLAUDE_PLUGIN_ROOT}/hooks/` prefix |
265
+ | **File (npm channel)** | `hooks/hooks.json` (symlinked into `.claude/hooks/`) |
265
266
  | **What it does** | Maps Claude Code hook events to handler scripts. Defines which events fire which entry points, the tool matchers (Bash, Task, Agent, `*`), and permissions (allow/deny lists). |
266
267
  | **Events configured** | PreToolUse (Bash, Task, Agent, SendMessage), PostToolUse, SubagentStop, SessionStart, Stop, TaskCompleted, SubagentStart, UserPromptSubmit (identity injection) |
267
268
 
@@ -292,7 +293,7 @@ To add support for a new Claude Code hook event (e.g., a future `PreCompact` eve
292
293
  2. **Add adapter method** to `ClaudeCodeAdapter` in `hooks/adapters/claude_code.py` -- implement `adapt_<event_name>(raw: dict) -> <ResultType>` and the corresponding `format_<result>_response()` if a new result type is needed.
293
294
  3. **Add extract/format methods** for the event type -- the extract method pulls typed data from the raw payload, the format method builds the CLI response JSON.
294
295
  4. **Create hook script entry point** -- a new `hooks/<event_name>.py` file that reads stdin, calls `adapter.parse_event()`, delegates to business logic, and writes the response to stdout.
295
- 5. **Add entry to `hooks/hooks.json`** (plugin channel) and `templates/settings.template.json` (npm channel) mapping the event name to the new script.
296
+ 5. **Add entry to `hooks/hooks.json`** mapping the event name to the new script.
296
297
 
297
298
  **Zero changes to business logic modules required.** The adapter is the only layer that touches CLI-specific JSON.
298
299
 
@@ -311,7 +312,7 @@ To support a CLI other than Claude Code (e.g., a hypothetical Cursor or Windsurf
311
312
  | File | Purpose |
312
313
  |------|---------|
313
314
  | `hooks/modules/identity/ops_identity.py` | Orchestrator identity (injected by UserPromptSubmit) |
314
- | `skills/project-dispatch/SKILL.md` | Agent routing table and dispatch rules (on-demand) |
315
+ | `config/surface-routing.json` | Surface routing config (agent table, signals, dispatch) |
315
316
  | `skills/agent-response/SKILL.md` | Contract status handling protocol (on-demand) |
316
317
  | `hooks/pre_tool_use.py` | PreToolUse hook entry point |
317
318
  | `hooks/subagent_stop.py` | SubagentStop hook entry point |
package/CHANGELOG.md CHANGED
@@ -5,6 +5,40 @@ All notable changes to the gaia-ops orchestration system are documented in this
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [4.5.0] - 2026-03-24
9
+
10
+ ### Settings Architecture Redesign + Multi-Cloud Security
11
+
12
+ Unified approach for permissions across NPM and plugin installation modes. Permissions now live in `settings.local.json` (union merge, preserves user config). `settings.json` contains only hooks.
13
+
14
+ #### Added
15
+ - **Azure deny rules** — 39 rules covering resource groups, networking, AKS, Key Vault, CosmosDB, Service Bus, and more
16
+ - **Generic wildcard deny rules** — 20 rules that catch all present and future cloud services (`aws * delete-*`, `az * delete`, `gcloud * delete`, etc.)
17
+ - **Indirect execution detection** — Catches `bash -c`, `eval`, `python3 -c`, `node -e`, `ruby -e`, `perl -e` wrappers that bypass regex patterns
18
+ - **Managed settings template** — `templates/managed-settings.template.json` for enterprise deployment via Claude.ai Admin Console
19
+ - **`updateLocalPermissions()`** in `gaia-update.js` — NPM postinstall now merges permissions into `settings.local.json` (same approach as plugin SessionStart)
20
+ - **Plugin mode detection via `plugin.json`** — `plugin_setup.py` and `plugin_mode.py` now read `.claude-plugin/plugin.json` for reliable name/version/mode detection with `--plugin-dir`
21
+ - **First-run welcome message** — `user_prompt_submit.py` detects first run and injects a welcome explaining that restart is needed to activate permissions
22
+
23
+ #### Changed
24
+ - **`settings.template.json`** — Removed permissions block; template now contains only hooks + environment
25
+ - **`_DENY_RULES` centralized in Python** — Single source of truth in `plugin_setup.py`, shared by both OPS and SECURITY modes
26
+ - **T3 approval flow** — All T3 mutative operations now use native `ask` dialog (both ops and security mode). Nonce workflow removed from direct conversation; kept for subagent use via skills.
27
+ - **`approval_messages.py`** — Simplified T3 block message to minimal data (tier + nonce). Workflow instructions live in skills, not hook messages.
28
+ - **`pre_tool_use.py`** — Simplified: passes through `block_response` from `bash_validator` directly, no more mode-specific branching
29
+ - **`bash_validator.py`** — T3 mutative returns `ask` response directly (no nonce generation, no pending files)
30
+ - **`session_start.py`** — Uses `mark_done=False` so `user_prompt_submit.py` can detect first-run and show welcome before marking initialized
31
+ - **`gaia-update.js` registry path** — Fixed to write `plugin-registry.json` in `.claude/` (same path Python hooks expect)
32
+ - **`gaia-doctor.js`** — Now checks permissions in `settings.local.json` (not just `settings.json`). Updated agent and config file lists.
33
+ - **`gaia-update.js` health check** — Updated config files (`surface-routing.json`) and agent list (`gaia-system.md`, `speckit-planner.md`)
34
+
35
+ #### Fixed
36
+ - **Registry path mismatch** — `gaia-update.js` wrote to `.claude/project-context/`, Python read from `.claude/`. Now both use `.claude/`.
37
+ - **Orphaned nonce files** — `bash_validator` no longer writes pending approval files for `ask` responses
38
+ - **Plugin mode detection** — `--plugin-dir` now correctly detects `gaia-ops` vs `gaia-security` via `plugin.json` instead of path parsing
39
+ - **First-run welcome race condition** — `SessionStart` no longer marks initialized; `UserPromptSubmit` marks after showing welcome
40
+ - **`_build_welcome()` framing** — Rewritten to explain WHY the user needs to restart (permissions not active yet), making Claude naturally relay the message
41
+
8
42
  ## [4.4.0-rc.5] - 2026-03-19
9
43
 
10
44
  ### Identity Redesign
package/README.md CHANGED
@@ -14,14 +14,17 @@ Multi-agent DevOps system that classifies every operation by risk, routes work t
14
14
 
15
15
  ### Features
16
16
 
17
- - **Multi-cloud support** - GCP, AWS
18
- - **6 agents** - terraform-architect, gitops-operator, cloud-troubleshooter, devops-developer, speckit-planner, gaia (meta-agent)
17
+ - **Multi-cloud support** - GCP, AWS, Azure
18
+ - **6 agents** - terraform-architect, gitops-operator, cloud-troubleshooter, devops-developer, speckit-planner, gaia-system (meta-agent)
19
19
  - **Contracts as SSOT** - Cloud-agnostic base contracts with per-cloud extensions (GCP, AWS)
20
20
  - **Dynamic identity** - Orchestrator identity injected by UserPromptSubmit hook; skills loaded on-demand
21
- - **Approval gates** for T3 operations via nonce-based workflow
21
+ - **Dual-barrier security** - Settings deny rules (Claude Code native) + hook-level blocking (inalterable via symlink)
22
+ - **Indirect execution detection** - Catches `bash -c`, `eval`, `python -c` wrappers that bypass regex patterns
23
+ - **Approval gates** for T3 operations via native `ask` dialog
22
24
  - **Git commit validation** with Conventional Commits
23
- - **20 skills** - Injected procedural knowledge modules for agents
25
+ - **21 skills** - Injected procedural knowledge modules for agents
24
26
  - **Plugin + npm** - Distributable as Claude Code native plugin or npm package
27
+ - **Enterprise ready** - Managed settings template for organization-wide deployment
25
28
 
26
29
  ## Installation
27
30
 
@@ -56,12 +59,24 @@ gaia-scan
56
59
 
57
60
  This will:
58
61
  1. Auto-detect your project structure (GitOps, Terraform, AppServices)
59
- 2. Install Claude Code if not present
60
- 3. Create `.claude/` directory with symlinks to this package
61
- 4. Generate `project-context.json` and `settings.json`
62
+ 2. Create `.claude/` directory with symlinks to this package
63
+ 3. Generate `project-context.json`
64
+ 4. Create `settings.json` with hooks only (no permissions in settings.json)
65
+ 5. Merge deny rules + allow permissions into `settings.local.json` (preserves existing user config)
62
66
 
63
67
  No `CLAUDE.md` is generated -- orchestrator identity is injected dynamically by the UserPromptSubmit hook.
64
68
 
69
+ ### Settings Architecture
70
+
71
+ Gaia-Ops separates hooks from permissions:
72
+
73
+ | File | Content | Strategy |
74
+ |------|---------|----------|
75
+ | `settings.json` | Hooks only (9 hook types) | Overwritten from template on each update |
76
+ | `settings.local.json` | Permissions (allow + deny rules) | Union merge — never removes user config |
77
+
78
+ This ensures your personal customizations (MCP servers, extra permissions) survive updates.
79
+
65
80
  ### Manual Installation
66
81
 
67
82
  ```bash
@@ -100,17 +115,34 @@ npx gaia-skills-diagnose
100
115
  npx gaia-skills-diagnose --run-tests
101
116
  ```
102
117
 
118
+ ## Security
119
+
120
+ Gaia-Ops enforces a 6-layer security pipeline:
121
+
122
+ | Layer | Mechanism | Bypassable? |
123
+ |-------|-----------|-------------|
124
+ | Indirect execution detection | `bash -c`, `eval`, `python -c` wrappers | No (hook-level) |
125
+ | Blocked commands (regex) | 85+ regex patterns | No (symlink to npm package) |
126
+ | Blocked commands (semantic) | 70+ ordered-token rules | No (symlink to npm package) |
127
+ | Cloud pipe validator | Credential piping detection | No (hook-level) |
128
+ | Mutative verb detection | `ask` dialog for state-changing ops | User approves via native dialog |
129
+ | Settings deny rules | 147 deny rules in `settings.local.json` | Self-healing (restored each session) |
130
+
131
+ ### Enterprise Deployment
132
+
133
+ For organization-wide enforcement, deploy `templates/managed-settings.template.json` as a managed settings policy via Claude.ai Admin Console. Managed settings have the highest precedence and cannot be overridden.
134
+
103
135
  ## Project Structure
104
136
 
105
137
  ```
106
138
  node_modules/@jaguilar87/gaia-ops/
107
139
  ├── agents/ # Agent definitions (6 agents)
108
- ├── skills/ # Skill modules (20 skills)
140
+ ├── skills/ # Skill modules (21 skills)
109
141
  ├── tools/ # Orchestration tools
110
142
  ├── hooks/ # Claude Code hooks (modular architecture)
111
143
  ├── commands/ # Slash commands (5 speckit + scan-project)
112
144
  ├── config/ # Configuration (contracts, git standards, rules)
113
- ├── templates/ # Installation templates (settings, governance)
145
+ ├── templates/ # Installation templates (settings, governance, managed-settings)
114
146
  ├── speckit/ # Spec-Kit framework (templates)
115
147
  ├── bin/ # CLI utilities (11 scripts)
116
148
  └── tests/ # Test suite
@@ -133,7 +165,7 @@ This package follows [Semantic Versioning](https://semver.org/):
133
165
  - **MINOR:** New features
134
166
  - **PATCH:** Bug fixes
135
167
 
136
- Current version: **4.4.0-rc.5**
168
+ Current version: **4.5.0**
137
169
 
138
170
  See [CHANGELOG.md](./CHANGELOG.md) for version history.
139
171
 
@@ -169,7 +201,7 @@ git clone git@bitbucket.org:yourorg/your-project-context.git project-context
169
201
 
170
202
  - **Issues:** [GitHub Issues](https://github.com/metraton/gaia-ops/issues)
171
203
  - **Repository:** [github.com/metraton/gaia-ops](https://github.com/metraton/gaia-ops)
172
- - **Author:** Jorge Aguilar <jaguilar1897@gmail.com>
204
+ - **Author:** Jorge Aguilar <jorge.aguilar88@gmail.com>
173
205
 
174
206
  ## License
175
207
 
@@ -19,7 +19,7 @@ skills:
19
19
 
20
20
  1. **Triage first**: When checking infrastructure state, run the fast-queries Terraform or cloud triage script before running plan/apply.
21
21
  2. **Deep analysis**: When investigating drift or complex module dependencies, follow the investigation phases.
22
- 3. **Before T3 operations**: When `terragrunt apply` is needed, present a REVIEW plan first. If a hook blocks it, follow the AWAITING_APPROVAL flow.
22
+ 3. **Before T3 operations**: When `terragrunt apply` is needed, present a REVIEW plan first. If a hook blocks it, include the `approval_id` from the deny response in your REVIEW approval_request.
23
23
  4. **Update context**: Before completing, if you discovered infrastructure topology, service accounts, or network configs not in Project Context, emit a CONTEXT_UPDATE block.
24
24
 
25
25
  ## Identity
package/bin/README.md CHANGED
@@ -27,7 +27,7 @@ Configure symlinks Remove files
27
27
  | Script | Description |
28
28
  |--------|-------------|
29
29
  | `gaia-scan` | Project scanner and installer (Python) |
30
- | `gaia-update.js` | Configuration updater (postinstall hook) |
30
+ | `gaia-update.js` | Configuration updater (postinstall hook) — updates hooks template, merges permissions into settings.local.json, ensures plugin-registry |
31
31
 
32
32
  ### Diagnostics and Monitoring
33
33
 
@@ -146,4 +146,4 @@ npx gaia-scan --non-interactive
146
146
 
147
147
  ---
148
148
 
149
- **Version:** 4.4.0-rc.5 | **Updated:** 2026-03-19 | **Scripts:** 11
149
+ **Version:** 4.5.0 | **Updated:** 2026-03-24 | **Scripts:** 11
@@ -102,17 +102,30 @@ async function checkSettingsJson() {
102
102
  if (!hookTypes.includes('PostToolUse')) issues.push('Missing PostToolUse hook');
103
103
  }
104
104
 
105
- // Check permissions exist
106
- if (!data.permissions) {
107
- issues.push('No permissions configured');
105
+ // Check permissions — now live in settings.local.json (not settings.json)
106
+ const localPath = join(CWD, '.claude', 'settings.local.json');
107
+ let permCount = 0;
108
+ if (existsSync(localPath)) {
109
+ try {
110
+ const localData = JSON.parse(await fs.readFile(localPath, 'utf-8'));
111
+ if (localData.permissions) {
112
+ permCount = Object.values(localData.permissions).flat().length;
113
+ }
114
+ } catch { /* ignore parse errors */ }
115
+ }
116
+ // Also count permissions in settings.json (legacy installs)
117
+ if (data.permissions) {
118
+ permCount += Object.values(data.permissions).flat().length;
119
+ }
120
+ if (permCount === 0) {
121
+ issues.push('No permissions configured (check settings.local.json)');
108
122
  }
109
123
 
110
124
  if (issues.length > 0) {
111
- return { name: 'settings.json', ok: false, detail: issues.join('; '), fix: 'Run gaia-scan' };
125
+ return { name: 'settings.json', ok: false, detail: issues.join('; '), fix: 'Run gaia-scan or npx gaia-update' };
112
126
  }
113
127
 
114
128
  const hookCount = data.hooks ? Object.keys(data.hooks).length : 0;
115
- const permCount = data.permissions ? Object.values(data.permissions).flat().length : 0;
116
129
  return { name: 'settings.json', ok: true, detail: `${hookCount} hook types, ${permCount} rules` };
117
130
  } catch {
118
131
  return { name: 'settings.json', ok: false, detail: 'Invalid JSON', fix: 'Delete and run gaia-scan' };
@@ -125,7 +125,6 @@ function colorStatus(status) {
125
125
  if (s === 'NEEDS_INPUT') return chalk.yellow(s.padEnd(8));
126
126
  if (s === 'IN_PROGRESS') return chalk.cyan(s.padEnd(8));
127
127
  if (s === 'REVIEW') return chalk.magenta(s.padEnd(8));
128
- if (s === 'AWAITING_APPROVAL') return chalk.yellow(s.padEnd(8));
129
128
  return chalk.gray(s.padEnd(8));
130
129
  }
131
130
 
@@ -450,7 +450,7 @@ function calculateAgentInvocations(workflowMetrics) {
450
450
 
451
451
  /**
452
452
  * Agent outcome distribution from plan_status field.
453
- * Counts COMPLETE, BLOCKED, NEEDS_INPUT, IN_PROGRESS, REVIEW, AWAITING_APPROVAL, and others.
453
+ * Counts COMPLETE, BLOCKED, NEEDS_INPUT, IN_PROGRESS, REVIEW, and others.
454
454
  * Returns null if no entries have the plan_status field (older data).
455
455
  */
456
456
  function calculateAgentOutcomes(workflowMetrics) {
@@ -874,7 +874,7 @@ function displayMetrics(
874
874
  // ── Agent Outcomes ───────────────────────────────────
875
875
  if (agentOutcomes) {
876
876
  console.log(chalk.bold(`\n📋 Agent Outcomes (${agentOutcomes.total} sessions with status)`));
877
- const outcomeColor = { COMPLETE: chalk.green, BLOCKED: chalk.red, NEEDS_INPUT: chalk.yellow, IN_PROGRESS: chalk.cyan, REVIEW: chalk.magenta, AWAITING_APPROVAL: chalk.yellow };
877
+ const outcomeColor = { COMPLETE: chalk.green, BLOCKED: chalk.red, NEEDS_INPUT: chalk.yellow, IN_PROGRESS: chalk.cyan, REVIEW: chalk.magenta };
878
878
  for (const { status, count, percentage } of agentOutcomes.distribution) {
879
879
  const bar = makeBar(percentage, 10);
880
880
  const pct = percentage.toFixed(1).padStart(5);
package/bin/gaia-scan.py CHANGED
@@ -205,6 +205,7 @@ def _mode_fresh(project_root: Path, scan_config: ScanConfig, args) -> int:
205
205
  generate_governance,
206
206
  generate_project_context,
207
207
  install_git_hooks,
208
+ merge_hooks_to_settings_local,
208
209
  )
209
210
  from tools.scan.ui import (
210
211
  RailUI,
@@ -238,11 +239,15 @@ def _mode_fresh(project_root: Path, scan_config: ScanConfig, args) -> int:
238
239
 
239
240
  # Step 4: INSTALL (automatic, no prompts)
240
241
  skip_claude = getattr(args, "skip_claude_install", False)
242
+ npm_postinstall = getattr(args, "npm_postinstall", False)
241
243
  ensure_claude_code(skip_install=skip_claude)
242
- ensure_gaia_ops_package(project_root)
244
+ if not npm_postinstall:
245
+ # Skip when called from npm postinstall to avoid re-entrance
246
+ ensure_gaia_ops_package(project_root)
243
247
  create_claude_directory(project_root)
244
248
  copy_claude_md(project_root)
245
249
  copy_settings_json(project_root)
250
+ merge_hooks_to_settings_local(project_root)
246
251
  install_git_hooks(project_root)
247
252
  generate_project_context(project_root, config, scan_context=output.context)
248
253
  generate_governance(project_root, config)
@@ -284,6 +289,7 @@ def _mode_existing(project_root: Path, scan_config: ScanConfig, args) -> int:
284
289
  copy_settings_json,
285
290
  create_claude_directory,
286
291
  install_git_hooks,
292
+ merge_hooks_to_settings_local,
287
293
  )
288
294
  from tools.scan.ui import (
289
295
  RailUI,
@@ -314,6 +320,7 @@ def _mode_existing(project_root: Path, scan_config: ScanConfig, args) -> int:
314
320
  # Step 4: SYNC
315
321
  copy_claude_md(project_root)
316
322
  copy_settings_json(project_root)
323
+ merge_hooks_to_settings_local(project_root)
317
324
  create_claude_directory(project_root)
318
325
  install_git_hooks(project_root)
319
326
 
@@ -496,6 +503,13 @@ def main(argv: list = None) -> int:
496
503
  dest="skip_claude_install",
497
504
  help="Skip Claude Code CLI installation",
498
505
  )
506
+ parser.add_argument(
507
+ "--npm-postinstall",
508
+ action="store_true",
509
+ default=False,
510
+ dest="npm_postinstall",
511
+ help="Called from npm postinstall: skip Claude Code install and npm package install to avoid re-entrance",
512
+ )
499
513
 
500
514
  args = parser.parse_args(argv)
501
515
 
@@ -544,11 +558,19 @@ def main(argv: list = None) -> int:
544
558
  print(json.dumps(result), file=sys.stdout)
545
559
  return 0
546
560
 
561
+ # --npm-postinstall implies --skip-claude-install and skips ensure_gaia_ops_package
562
+ if args.npm_postinstall:
563
+ args.skip_claude_install = True
564
+
547
565
  # Mode selection
548
566
  # --json or --scan-only: scan-only mode
549
567
  if args.json or args.scan_only:
550
568
  return _mode_scan_only(project_root, scan_config, args)
551
569
 
570
+ # --npm-postinstall: fresh install mode with re-entrance protection
571
+ if args.npm_postinstall:
572
+ return _mode_fresh(project_root, scan_config, args)
573
+
552
574
  # Detect mode based on .claude/ existence
553
575
  claude_dir = project_root / ".claude"
554
576
  if claude_dir.is_dir():