@jaguilar87/gaia 5.0.0-rc.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 (621) hide show
  1. package/.claude-plugin/marketplace.json +33 -0
  2. package/.claude-plugin/plugin.json +26 -0
  3. package/ARCHITECTURE.md +335 -0
  4. package/CHANGELOG.md +1298 -0
  5. package/CODE_OF_CONDUCT.md +11 -0
  6. package/CONTRIBUTING.md +146 -0
  7. package/INSTALL.md +436 -0
  8. package/LICENSE +21 -0
  9. package/README.md +222 -0
  10. package/SECURITY.md +47 -0
  11. package/agents/README.md +78 -0
  12. package/agents/cloud-troubleshooter.md +73 -0
  13. package/agents/developer.md +65 -0
  14. package/agents/gaia-operator.md +64 -0
  15. package/agents/gaia-orchestrator.md +111 -0
  16. package/agents/gaia-planner.md +53 -0
  17. package/agents/gaia-system.md +71 -0
  18. package/agents/gitops-operator.md +61 -0
  19. package/agents/terraform-architect.md +63 -0
  20. package/bin/README.md +106 -0
  21. package/bin/cli/__init__.py +1 -0
  22. package/bin/cli/approvals.py +740 -0
  23. package/bin/cli/cleanup.py +562 -0
  24. package/bin/cli/context.py +283 -0
  25. package/bin/cli/doctor.py +651 -0
  26. package/bin/cli/history.py +305 -0
  27. package/bin/cli/memory.py +483 -0
  28. package/bin/cli/metrics.py +1068 -0
  29. package/bin/cli/plans.py +515 -0
  30. package/bin/cli/status.py +302 -0
  31. package/bin/cli/update.py +382 -0
  32. package/bin/gaia +112 -0
  33. package/bin/gaia-cleanup.js +531 -0
  34. package/bin/gaia-doctor.js +635 -0
  35. package/bin/gaia-evidence +126 -0
  36. package/bin/gaia-history.js +251 -0
  37. package/bin/gaia-metrics.js +1278 -0
  38. package/bin/gaia-review.js +269 -0
  39. package/bin/gaia-scan +44 -0
  40. package/bin/gaia-scan.py +589 -0
  41. package/bin/gaia-skills-diagnose.js +929 -0
  42. package/bin/gaia-status.js +278 -0
  43. package/bin/gaia-uninstall.js +111 -0
  44. package/bin/gaia-update.js +919 -0
  45. package/bin/pre-publish-validate.js +610 -0
  46. package/bin/python-detect.js +60 -0
  47. package/bin/validate-sandbox.sh +601 -0
  48. package/commands/README.md +64 -0
  49. package/commands/gaia.md +37 -0
  50. package/commands/scan-project.md +67 -0
  51. package/config/README.md +71 -0
  52. package/config/cloud/aws.json +134 -0
  53. package/config/cloud/gcp.json +139 -0
  54. package/config/context-contracts.json +158 -0
  55. package/config/crons-schema.md +81 -0
  56. package/config/git_standards.json +72 -0
  57. package/config/surface-routing.json +417 -0
  58. package/config/universal-rules.json +102 -0
  59. package/dist/gaia-ops/.claude-plugin/plugin.json +24 -0
  60. package/dist/gaia-ops/README.md +80 -0
  61. package/dist/gaia-ops/agents/cloud-troubleshooter.md +73 -0
  62. package/dist/gaia-ops/agents/developer.md +65 -0
  63. package/dist/gaia-ops/agents/gaia-operator.md +64 -0
  64. package/dist/gaia-ops/agents/gaia-orchestrator.md +111 -0
  65. package/dist/gaia-ops/agents/gaia-planner.md +53 -0
  66. package/dist/gaia-ops/agents/gaia-system.md +71 -0
  67. package/dist/gaia-ops/agents/gitops-operator.md +61 -0
  68. package/dist/gaia-ops/agents/terraform-architect.md +63 -0
  69. package/dist/gaia-ops/commands/gaia.md +37 -0
  70. package/dist/gaia-ops/config/README.md +71 -0
  71. package/dist/gaia-ops/config/cloud/aws.json +134 -0
  72. package/dist/gaia-ops/config/cloud/gcp.json +139 -0
  73. package/dist/gaia-ops/config/context-contracts.json +158 -0
  74. package/dist/gaia-ops/config/crons-schema.md +81 -0
  75. package/dist/gaia-ops/config/git_standards.json +72 -0
  76. package/dist/gaia-ops/config/surface-routing.json +417 -0
  77. package/dist/gaia-ops/config/universal-rules.json +102 -0
  78. package/dist/gaia-ops/hooks/adapters/__init__.py +52 -0
  79. package/dist/gaia-ops/hooks/adapters/base.py +219 -0
  80. package/dist/gaia-ops/hooks/adapters/channel.py +17 -0
  81. package/dist/gaia-ops/hooks/adapters/claude_code.py +1890 -0
  82. package/dist/gaia-ops/hooks/adapters/types.py +194 -0
  83. package/dist/gaia-ops/hooks/adapters/utils.py +25 -0
  84. package/dist/gaia-ops/hooks/hooks.json +192 -0
  85. package/dist/gaia-ops/hooks/modules/__init__.py +15 -0
  86. package/dist/gaia-ops/hooks/modules/agents/__init__.py +29 -0
  87. package/dist/gaia-ops/hooks/modules/agents/contract_validator.py +647 -0
  88. package/dist/gaia-ops/hooks/modules/agents/response_contract.py +496 -0
  89. package/dist/gaia-ops/hooks/modules/agents/skill_injection_verifier.py +120 -0
  90. package/dist/gaia-ops/hooks/modules/agents/state_tracker.py +267 -0
  91. package/dist/gaia-ops/hooks/modules/agents/task_info_builder.py +74 -0
  92. package/dist/gaia-ops/hooks/modules/agents/transcript_analyzer.py +458 -0
  93. package/dist/gaia-ops/hooks/modules/agents/transcript_reader.py +152 -0
  94. package/dist/gaia-ops/hooks/modules/audit/__init__.py +28 -0
  95. package/dist/gaia-ops/hooks/modules/audit/event_detector.py +168 -0
  96. package/dist/gaia-ops/hooks/modules/audit/logger.py +131 -0
  97. package/dist/gaia-ops/hooks/modules/audit/metrics.py +134 -0
  98. package/dist/gaia-ops/hooks/modules/audit/workflow_auditor.py +611 -0
  99. package/dist/gaia-ops/hooks/modules/audit/workflow_recorder.py +296 -0
  100. package/dist/gaia-ops/hooks/modules/context/__init__.py +11 -0
  101. package/dist/gaia-ops/hooks/modules/context/agentic_loop_detector.py +165 -0
  102. package/dist/gaia-ops/hooks/modules/context/anchor_tracker.py +317 -0
  103. package/dist/gaia-ops/hooks/modules/context/compact_context_builder.py +218 -0
  104. package/dist/gaia-ops/hooks/modules/context/context_freshness.py +145 -0
  105. package/dist/gaia-ops/hooks/modules/context/context_injector.py +558 -0
  106. package/dist/gaia-ops/hooks/modules/context/context_writer.py +530 -0
  107. package/dist/gaia-ops/hooks/modules/context/contracts_loader.py +161 -0
  108. package/dist/gaia-ops/hooks/modules/core/__init__.py +40 -0
  109. package/dist/gaia-ops/hooks/modules/core/hook_entry.py +78 -0
  110. package/dist/gaia-ops/hooks/modules/core/paths.py +160 -0
  111. package/dist/gaia-ops/hooks/modules/core/plugin_mode.py +149 -0
  112. package/dist/gaia-ops/hooks/modules/core/plugin_setup.py +577 -0
  113. package/dist/gaia-ops/hooks/modules/core/state.py +179 -0
  114. package/dist/gaia-ops/hooks/modules/core/stdin.py +24 -0
  115. package/dist/gaia-ops/hooks/modules/events/__init__.py +1 -0
  116. package/dist/gaia-ops/hooks/modules/events/event_writer.py +210 -0
  117. package/dist/gaia-ops/hooks/modules/memory/__init__.py +8 -0
  118. package/dist/gaia-ops/hooks/modules/memory/episode_writer.py +216 -0
  119. package/dist/gaia-ops/hooks/modules/orchestrator/__init__.py +1 -0
  120. package/dist/gaia-ops/hooks/modules/orchestrator/delegate_mode.py +122 -0
  121. package/dist/gaia-ops/hooks/modules/scanning/__init__.py +8 -0
  122. package/dist/gaia-ops/hooks/modules/scanning/scan_trigger.py +84 -0
  123. package/dist/gaia-ops/hooks/modules/security/__init__.py +120 -0
  124. package/dist/gaia-ops/hooks/modules/security/approval_cleanup.py +87 -0
  125. package/dist/gaia-ops/hooks/modules/security/approval_constants.py +23 -0
  126. package/dist/gaia-ops/hooks/modules/security/approval_grants.py +1638 -0
  127. package/dist/gaia-ops/hooks/modules/security/approval_messages.py +71 -0
  128. package/dist/gaia-ops/hooks/modules/security/approval_scopes.py +222 -0
  129. package/dist/gaia-ops/hooks/modules/security/blocked_commands.py +595 -0
  130. package/dist/gaia-ops/hooks/modules/security/blocked_message_formatter.py +87 -0
  131. package/dist/gaia-ops/hooks/modules/security/command_semantics.py +181 -0
  132. package/dist/gaia-ops/hooks/modules/security/composition_rules.py +547 -0
  133. package/dist/gaia-ops/hooks/modules/security/flag_classifiers.py +873 -0
  134. package/dist/gaia-ops/hooks/modules/security/gitops_validator.py +179 -0
  135. package/dist/gaia-ops/hooks/modules/security/mutative_verbs.py +1131 -0
  136. package/dist/gaia-ops/hooks/modules/security/network_hosts.py +481 -0
  137. package/dist/gaia-ops/hooks/modules/security/prompt_validator.py +40 -0
  138. package/dist/gaia-ops/hooks/modules/security/shell_unwrapper.py +165 -0
  139. package/dist/gaia-ops/hooks/modules/security/tiers.py +196 -0
  140. package/dist/gaia-ops/hooks/modules/session/__init__.py +10 -0
  141. package/dist/gaia-ops/hooks/modules/session/pending_scanner.py +174 -0
  142. package/dist/gaia-ops/hooks/modules/session/session_context_writer.py +100 -0
  143. package/dist/gaia-ops/hooks/modules/session/session_event_injector.py +160 -0
  144. package/dist/gaia-ops/hooks/modules/session/session_manager.py +31 -0
  145. package/dist/gaia-ops/hooks/modules/session/session_registry.py +333 -0
  146. package/dist/gaia-ops/hooks/modules/tools/__init__.py +29 -0
  147. package/dist/gaia-ops/hooks/modules/tools/bash_validator.py +1008 -0
  148. package/dist/gaia-ops/hooks/modules/tools/cloud_pipe_validator.py +231 -0
  149. package/dist/gaia-ops/hooks/modules/tools/hook_response.py +55 -0
  150. package/dist/gaia-ops/hooks/modules/tools/shell_parser.py +227 -0
  151. package/dist/gaia-ops/hooks/modules/tools/stage_decomposer.py +315 -0
  152. package/dist/gaia-ops/hooks/modules/tools/task_validator.py +294 -0
  153. package/dist/gaia-ops/hooks/modules/validation/__init__.py +23 -0
  154. package/dist/gaia-ops/hooks/modules/validation/commit_validator.py +380 -0
  155. package/dist/gaia-ops/hooks/post_compact.py +43 -0
  156. package/dist/gaia-ops/hooks/post_tool_use.py +54 -0
  157. package/dist/gaia-ops/hooks/pre_compact.py +60 -0
  158. package/dist/gaia-ops/hooks/pre_tool_use.py +413 -0
  159. package/dist/gaia-ops/hooks/session_end_hook.py +77 -0
  160. package/dist/gaia-ops/hooks/session_start.py +81 -0
  161. package/dist/gaia-ops/hooks/stop_hook.py +70 -0
  162. package/dist/gaia-ops/hooks/subagent_start.py +71 -0
  163. package/dist/gaia-ops/hooks/subagent_stop.py +295 -0
  164. package/dist/gaia-ops/hooks/task_completed.py +70 -0
  165. package/dist/gaia-ops/hooks/user_prompt_submit.py +246 -0
  166. package/dist/gaia-ops/settings.json +72 -0
  167. package/dist/gaia-ops/skills/README.md +158 -0
  168. package/dist/gaia-ops/skills/agent-creation/SKILL.md +87 -0
  169. package/dist/gaia-ops/skills/agent-creation/examples.md +170 -0
  170. package/dist/gaia-ops/skills/agent-creation/reference.md +191 -0
  171. package/dist/gaia-ops/skills/agent-protocol/SKILL.md +93 -0
  172. package/dist/gaia-ops/skills/agent-protocol/examples.md +223 -0
  173. package/dist/gaia-ops/skills/agent-response/SKILL.md +69 -0
  174. package/dist/gaia-ops/skills/agentic-loop/SKILL.md +80 -0
  175. package/dist/gaia-ops/skills/agentic-loop/reference.md +378 -0
  176. package/dist/gaia-ops/skills/blog-writing/SKILL.md +98 -0
  177. package/dist/gaia-ops/skills/blog-writing/reference.md +130 -0
  178. package/dist/gaia-ops/skills/brief-spec/SKILL.md +185 -0
  179. package/dist/gaia-ops/skills/command-execution/SKILL.md +64 -0
  180. package/dist/gaia-ops/skills/command-execution/reference.md +83 -0
  181. package/dist/gaia-ops/skills/context-updater/SKILL.md +87 -0
  182. package/dist/gaia-ops/skills/context-updater/examples.md +71 -0
  183. package/dist/gaia-ops/skills/developer-patterns/SKILL.md +50 -0
  184. package/dist/gaia-ops/skills/developer-patterns/reference.md +112 -0
  185. package/dist/gaia-ops/skills/execution/SKILL.md +99 -0
  186. package/dist/gaia-ops/skills/fast-queries/SKILL.md +43 -0
  187. package/dist/gaia-ops/skills/gaia-compact/SKILL.md +74 -0
  188. package/dist/gaia-ops/skills/gaia-patterns/SKILL.md +108 -0
  189. package/dist/gaia-ops/skills/gaia-patterns/reference.md +395 -0
  190. package/dist/gaia-ops/skills/gaia-planner/SKILL.md +37 -0
  191. package/dist/gaia-ops/skills/gaia-planner/reference.md +107 -0
  192. package/dist/gaia-ops/skills/gaia-release/SKILL.md +85 -0
  193. package/dist/gaia-ops/skills/gaia-release/reference.md +92 -0
  194. package/dist/gaia-ops/skills/gaia-self-check/SKILL.md +114 -0
  195. package/dist/gaia-ops/skills/gaia-self-check/reference.md +453 -0
  196. package/dist/gaia-ops/skills/gaia-verify/SKILL.md +77 -0
  197. package/dist/gaia-ops/skills/gaia-verify/reference.md +80 -0
  198. package/dist/gaia-ops/skills/git-conventions/SKILL.md +47 -0
  199. package/dist/gaia-ops/skills/gitops-patterns/SKILL.md +60 -0
  200. package/dist/gaia-ops/skills/gitops-patterns/reference.md +183 -0
  201. package/dist/gaia-ops/skills/gmail-policy/SKILL.md +200 -0
  202. package/dist/gaia-ops/skills/gmail-policy/reference.md +150 -0
  203. package/dist/gaia-ops/skills/gmail-triage/SKILL.md +100 -0
  204. package/dist/gaia-ops/skills/gws-setup/SKILL.md +99 -0
  205. package/dist/gaia-ops/skills/gws-setup/reference.md +73 -0
  206. package/dist/gaia-ops/skills/investigation/SKILL.md +100 -0
  207. package/dist/gaia-ops/skills/memory-curation/SKILL.md +83 -0
  208. package/dist/gaia-ops/skills/memory-search/SKILL.md +88 -0
  209. package/dist/gaia-ops/skills/orchestrator-approval/SKILL.md +160 -0
  210. package/dist/gaia-ops/skills/orchestrator-approval/reference.md +174 -0
  211. package/dist/gaia-ops/skills/pending-approvals/SKILL.md +72 -0
  212. package/dist/gaia-ops/skills/pending-approvals/reference.md +214 -0
  213. package/dist/gaia-ops/skills/readme-writing/SKILL.md +71 -0
  214. package/dist/gaia-ops/skills/readme-writing/reference.md +188 -0
  215. package/dist/gaia-ops/skills/reference.md +135 -0
  216. package/dist/gaia-ops/skills/request-approval/SKILL.md +140 -0
  217. package/dist/gaia-ops/skills/request-approval/examples.md +140 -0
  218. package/dist/gaia-ops/skills/request-approval/reference.md +57 -0
  219. package/dist/gaia-ops/skills/schedule-task/SKILL.md +64 -0
  220. package/dist/gaia-ops/skills/schedule-task/reference.md +233 -0
  221. package/dist/gaia-ops/skills/security-tiers/SKILL.md +141 -0
  222. package/dist/gaia-ops/skills/security-tiers/destructive-commands-reference.md +623 -0
  223. package/dist/gaia-ops/skills/security-tiers/reference.md +39 -0
  224. package/dist/gaia-ops/skills/session-reflection/SKILL.md +69 -0
  225. package/dist/gaia-ops/skills/skill-creation/SKILL.md +92 -0
  226. package/dist/gaia-ops/skills/skill-creation/reference.md +29 -0
  227. package/dist/gaia-ops/skills/terraform-patterns/SKILL.md +89 -0
  228. package/dist/gaia-ops/skills/terraform-patterns/reference.md +93 -0
  229. package/dist/gaia-ops/tools/__init__.py +9 -0
  230. package/dist/gaia-ops/tools/agentic-loop/decide-status.py +210 -0
  231. package/dist/gaia-ops/tools/agentic-loop/parse-metric.py +106 -0
  232. package/dist/gaia-ops/tools/agentic-loop/record-iteration.py +221 -0
  233. package/dist/gaia-ops/tools/context/README.md +132 -0
  234. package/dist/gaia-ops/tools/context/__init__.py +42 -0
  235. package/dist/gaia-ops/tools/context/_paths.py +20 -0
  236. package/dist/gaia-ops/tools/context/context_provider.py +721 -0
  237. package/dist/gaia-ops/tools/context/context_section_reader.py +342 -0
  238. package/dist/gaia-ops/tools/context/deep_merge.py +159 -0
  239. package/dist/gaia-ops/tools/context/pending_updates.py +760 -0
  240. package/dist/gaia-ops/tools/context/surface_router.py +278 -0
  241. package/dist/gaia-ops/tools/fast-queries/README.md +65 -0
  242. package/dist/gaia-ops/tools/fast-queries/__init__.py +30 -0
  243. package/dist/gaia-ops/tools/fast-queries/appservices/quicktriage_devops_developer.sh +75 -0
  244. package/dist/gaia-ops/tools/fast-queries/cloud/aws/quicktriage_aws_troubleshooter.sh +32 -0
  245. package/dist/gaia-ops/tools/fast-queries/cloud/gcp/quicktriage_gcp_troubleshooter.sh +88 -0
  246. package/dist/gaia-ops/tools/fast-queries/gitops/quicktriage_gitops_operator.sh +48 -0
  247. package/dist/gaia-ops/tools/fast-queries/run_triage.sh +59 -0
  248. package/dist/gaia-ops/tools/fast-queries/terraform/quicktriage_terraform_architect.sh +80 -0
  249. package/dist/gaia-ops/tools/gaia_simulator/__init__.py +33 -0
  250. package/dist/gaia-ops/tools/gaia_simulator/cli.py +354 -0
  251. package/dist/gaia-ops/tools/gaia_simulator/extractor.py +457 -0
  252. package/dist/gaia-ops/tools/gaia_simulator/reporter.py +258 -0
  253. package/dist/gaia-ops/tools/gaia_simulator/routing_simulator.py +334 -0
  254. package/dist/gaia-ops/tools/gaia_simulator/runner.py +539 -0
  255. package/dist/gaia-ops/tools/gaia_simulator/skills_mapper.py +264 -0
  256. package/dist/gaia-ops/tools/memory/README.md +0 -0
  257. package/dist/gaia-ops/tools/memory/__init__.py +20 -0
  258. package/dist/gaia-ops/tools/memory/backfill_fts5.py +107 -0
  259. package/dist/gaia-ops/tools/memory/conflict_detector.py +295 -0
  260. package/dist/gaia-ops/tools/memory/episodic.py +1210 -0
  261. package/dist/gaia-ops/tools/memory/git_invalidator.py +262 -0
  262. package/dist/gaia-ops/tools/memory/paths.py +102 -0
  263. package/dist/gaia-ops/tools/memory/scoring.py +193 -0
  264. package/dist/gaia-ops/tools/memory/search_store.py +375 -0
  265. package/dist/gaia-ops/tools/persist_transcript_analysis.py +85 -0
  266. package/dist/gaia-ops/tools/review/__init__.py +1 -0
  267. package/dist/gaia-ops/tools/review/review_engine.py +157 -0
  268. package/dist/gaia-ops/tools/scan/__init__.py +35 -0
  269. package/dist/gaia-ops/tools/scan/config.py +247 -0
  270. package/dist/gaia-ops/tools/scan/merge.py +212 -0
  271. package/dist/gaia-ops/tools/scan/orchestrator.py +549 -0
  272. package/dist/gaia-ops/tools/scan/registry.py +127 -0
  273. package/dist/gaia-ops/tools/scan/scanners/__init__.py +18 -0
  274. package/dist/gaia-ops/tools/scan/scanners/base.py +137 -0
  275. package/dist/gaia-ops/tools/scan/scanners/environment.py +349 -0
  276. package/dist/gaia-ops/tools/scan/scanners/git.py +570 -0
  277. package/dist/gaia-ops/tools/scan/scanners/infrastructure.py +875 -0
  278. package/dist/gaia-ops/tools/scan/scanners/orchestration.py +600 -0
  279. package/dist/gaia-ops/tools/scan/scanners/stack.py +1085 -0
  280. package/dist/gaia-ops/tools/scan/scanners/tools.py +260 -0
  281. package/dist/gaia-ops/tools/scan/setup.py +686 -0
  282. package/dist/gaia-ops/tools/scan/tests/__init__.py +1 -0
  283. package/dist/gaia-ops/tools/scan/tests/conftest.py +796 -0
  284. package/dist/gaia-ops/tools/scan/tests/test_environment.py +323 -0
  285. package/dist/gaia-ops/tools/scan/tests/test_git.py +419 -0
  286. package/dist/gaia-ops/tools/scan/tests/test_infrastructure.py +382 -0
  287. package/dist/gaia-ops/tools/scan/tests/test_integration.py +920 -0
  288. package/dist/gaia-ops/tools/scan/tests/test_merge.py +269 -0
  289. package/dist/gaia-ops/tools/scan/tests/test_orchestration.py +304 -0
  290. package/dist/gaia-ops/tools/scan/tests/test_stack.py +604 -0
  291. package/dist/gaia-ops/tools/scan/tests/test_tools.py +349 -0
  292. package/dist/gaia-ops/tools/scan/ui.py +624 -0
  293. package/dist/gaia-ops/tools/scan/verify.py +270 -0
  294. package/dist/gaia-ops/tools/scan/walk.py +118 -0
  295. package/dist/gaia-ops/tools/scan/workspace.py +85 -0
  296. package/dist/gaia-ops/tools/validation/README.md +244 -0
  297. package/dist/gaia-ops/tools/validation/__init__.py +17 -0
  298. package/dist/gaia-ops/tools/validation/approval_gate.py +321 -0
  299. package/dist/gaia-ops/tools/validation/validate_skills.py +189 -0
  300. package/dist/gaia-security/.claude-plugin/plugin.json +24 -0
  301. package/dist/gaia-security/README.md +90 -0
  302. package/dist/gaia-security/config/universal-rules.json +102 -0
  303. package/dist/gaia-security/hooks/adapters/__init__.py +52 -0
  304. package/dist/gaia-security/hooks/adapters/base.py +219 -0
  305. package/dist/gaia-security/hooks/adapters/channel.py +17 -0
  306. package/dist/gaia-security/hooks/adapters/claude_code.py +1890 -0
  307. package/dist/gaia-security/hooks/adapters/types.py +194 -0
  308. package/dist/gaia-security/hooks/adapters/utils.py +25 -0
  309. package/dist/gaia-security/hooks/hooks.json +113 -0
  310. package/dist/gaia-security/hooks/modules/__init__.py +15 -0
  311. package/dist/gaia-security/hooks/modules/agents/__init__.py +29 -0
  312. package/dist/gaia-security/hooks/modules/agents/contract_validator.py +647 -0
  313. package/dist/gaia-security/hooks/modules/agents/response_contract.py +496 -0
  314. package/dist/gaia-security/hooks/modules/agents/skill_injection_verifier.py +120 -0
  315. package/dist/gaia-security/hooks/modules/agents/state_tracker.py +267 -0
  316. package/dist/gaia-security/hooks/modules/agents/task_info_builder.py +74 -0
  317. package/dist/gaia-security/hooks/modules/agents/transcript_analyzer.py +458 -0
  318. package/dist/gaia-security/hooks/modules/agents/transcript_reader.py +152 -0
  319. package/dist/gaia-security/hooks/modules/audit/__init__.py +28 -0
  320. package/dist/gaia-security/hooks/modules/audit/event_detector.py +168 -0
  321. package/dist/gaia-security/hooks/modules/audit/logger.py +131 -0
  322. package/dist/gaia-security/hooks/modules/audit/metrics.py +134 -0
  323. package/dist/gaia-security/hooks/modules/audit/workflow_auditor.py +611 -0
  324. package/dist/gaia-security/hooks/modules/audit/workflow_recorder.py +296 -0
  325. package/dist/gaia-security/hooks/modules/context/__init__.py +11 -0
  326. package/dist/gaia-security/hooks/modules/context/agentic_loop_detector.py +165 -0
  327. package/dist/gaia-security/hooks/modules/context/anchor_tracker.py +317 -0
  328. package/dist/gaia-security/hooks/modules/context/compact_context_builder.py +218 -0
  329. package/dist/gaia-security/hooks/modules/context/context_freshness.py +145 -0
  330. package/dist/gaia-security/hooks/modules/context/context_injector.py +558 -0
  331. package/dist/gaia-security/hooks/modules/context/context_writer.py +530 -0
  332. package/dist/gaia-security/hooks/modules/context/contracts_loader.py +161 -0
  333. package/dist/gaia-security/hooks/modules/core/__init__.py +40 -0
  334. package/dist/gaia-security/hooks/modules/core/hook_entry.py +78 -0
  335. package/dist/gaia-security/hooks/modules/core/paths.py +160 -0
  336. package/dist/gaia-security/hooks/modules/core/plugin_mode.py +149 -0
  337. package/dist/gaia-security/hooks/modules/core/plugin_setup.py +577 -0
  338. package/dist/gaia-security/hooks/modules/core/state.py +179 -0
  339. package/dist/gaia-security/hooks/modules/core/stdin.py +24 -0
  340. package/dist/gaia-security/hooks/modules/events/__init__.py +1 -0
  341. package/dist/gaia-security/hooks/modules/events/event_writer.py +210 -0
  342. package/dist/gaia-security/hooks/modules/memory/__init__.py +8 -0
  343. package/dist/gaia-security/hooks/modules/memory/episode_writer.py +216 -0
  344. package/dist/gaia-security/hooks/modules/orchestrator/__init__.py +1 -0
  345. package/dist/gaia-security/hooks/modules/orchestrator/delegate_mode.py +122 -0
  346. package/dist/gaia-security/hooks/modules/scanning/__init__.py +8 -0
  347. package/dist/gaia-security/hooks/modules/scanning/scan_trigger.py +84 -0
  348. package/dist/gaia-security/hooks/modules/security/__init__.py +120 -0
  349. package/dist/gaia-security/hooks/modules/security/approval_cleanup.py +87 -0
  350. package/dist/gaia-security/hooks/modules/security/approval_constants.py +23 -0
  351. package/dist/gaia-security/hooks/modules/security/approval_grants.py +1638 -0
  352. package/dist/gaia-security/hooks/modules/security/approval_messages.py +71 -0
  353. package/dist/gaia-security/hooks/modules/security/approval_scopes.py +222 -0
  354. package/dist/gaia-security/hooks/modules/security/blocked_commands.py +595 -0
  355. package/dist/gaia-security/hooks/modules/security/blocked_message_formatter.py +87 -0
  356. package/dist/gaia-security/hooks/modules/security/command_semantics.py +181 -0
  357. package/dist/gaia-security/hooks/modules/security/composition_rules.py +547 -0
  358. package/dist/gaia-security/hooks/modules/security/flag_classifiers.py +873 -0
  359. package/dist/gaia-security/hooks/modules/security/gitops_validator.py +179 -0
  360. package/dist/gaia-security/hooks/modules/security/mutative_verbs.py +1131 -0
  361. package/dist/gaia-security/hooks/modules/security/network_hosts.py +481 -0
  362. package/dist/gaia-security/hooks/modules/security/prompt_validator.py +40 -0
  363. package/dist/gaia-security/hooks/modules/security/shell_unwrapper.py +165 -0
  364. package/dist/gaia-security/hooks/modules/security/tiers.py +196 -0
  365. package/dist/gaia-security/hooks/modules/session/__init__.py +10 -0
  366. package/dist/gaia-security/hooks/modules/session/pending_scanner.py +174 -0
  367. package/dist/gaia-security/hooks/modules/session/session_context_writer.py +100 -0
  368. package/dist/gaia-security/hooks/modules/session/session_event_injector.py +160 -0
  369. package/dist/gaia-security/hooks/modules/session/session_manager.py +31 -0
  370. package/dist/gaia-security/hooks/modules/session/session_registry.py +333 -0
  371. package/dist/gaia-security/hooks/modules/tools/__init__.py +29 -0
  372. package/dist/gaia-security/hooks/modules/tools/bash_validator.py +1008 -0
  373. package/dist/gaia-security/hooks/modules/tools/cloud_pipe_validator.py +231 -0
  374. package/dist/gaia-security/hooks/modules/tools/hook_response.py +55 -0
  375. package/dist/gaia-security/hooks/modules/tools/shell_parser.py +227 -0
  376. package/dist/gaia-security/hooks/modules/tools/stage_decomposer.py +315 -0
  377. package/dist/gaia-security/hooks/modules/tools/task_validator.py +294 -0
  378. package/dist/gaia-security/hooks/modules/validation/__init__.py +23 -0
  379. package/dist/gaia-security/hooks/modules/validation/commit_validator.py +380 -0
  380. package/dist/gaia-security/hooks/post_tool_use.py +54 -0
  381. package/dist/gaia-security/hooks/pre_tool_use.py +413 -0
  382. package/dist/gaia-security/hooks/session_end_hook.py +77 -0
  383. package/dist/gaia-security/hooks/session_start.py +81 -0
  384. package/dist/gaia-security/hooks/stop_hook.py +70 -0
  385. package/dist/gaia-security/hooks/user_prompt_submit.py +246 -0
  386. package/dist/gaia-security/settings.json +58 -0
  387. package/git-hooks/commit-msg +41 -0
  388. package/hooks/README.md +100 -0
  389. package/hooks/adapters/__init__.py +52 -0
  390. package/hooks/adapters/base.py +219 -0
  391. package/hooks/adapters/channel.py +17 -0
  392. package/hooks/adapters/claude_code.py +1890 -0
  393. package/hooks/adapters/types.py +194 -0
  394. package/hooks/adapters/utils.py +25 -0
  395. package/hooks/elicitation_result.py +179 -0
  396. package/hooks/hooks.json +84 -0
  397. package/hooks/modules/README.md +189 -0
  398. package/hooks/modules/__init__.py +15 -0
  399. package/hooks/modules/agents/__init__.py +29 -0
  400. package/hooks/modules/agents/contract_validator.py +647 -0
  401. package/hooks/modules/agents/response_contract.py +496 -0
  402. package/hooks/modules/agents/skill_injection_verifier.py +120 -0
  403. package/hooks/modules/agents/state_tracker.py +267 -0
  404. package/hooks/modules/agents/task_info_builder.py +74 -0
  405. package/hooks/modules/agents/transcript_analyzer.py +458 -0
  406. package/hooks/modules/agents/transcript_reader.py +152 -0
  407. package/hooks/modules/audit/__init__.py +28 -0
  408. package/hooks/modules/audit/event_detector.py +168 -0
  409. package/hooks/modules/audit/logger.py +131 -0
  410. package/hooks/modules/audit/metrics.py +134 -0
  411. package/hooks/modules/audit/workflow_auditor.py +611 -0
  412. package/hooks/modules/audit/workflow_recorder.py +296 -0
  413. package/hooks/modules/context/__init__.py +11 -0
  414. package/hooks/modules/context/agentic_loop_detector.py +165 -0
  415. package/hooks/modules/context/anchor_tracker.py +317 -0
  416. package/hooks/modules/context/compact_context_builder.py +218 -0
  417. package/hooks/modules/context/context_freshness.py +145 -0
  418. package/hooks/modules/context/context_injector.py +558 -0
  419. package/hooks/modules/context/context_writer.py +530 -0
  420. package/hooks/modules/context/contracts_loader.py +161 -0
  421. package/hooks/modules/core/__init__.py +40 -0
  422. package/hooks/modules/core/hook_entry.py +78 -0
  423. package/hooks/modules/core/paths.py +160 -0
  424. package/hooks/modules/core/plugin_mode.py +149 -0
  425. package/hooks/modules/core/plugin_setup.py +577 -0
  426. package/hooks/modules/core/state.py +179 -0
  427. package/hooks/modules/core/stdin.py +24 -0
  428. package/hooks/modules/events/__init__.py +1 -0
  429. package/hooks/modules/events/event_writer.py +210 -0
  430. package/hooks/modules/evidence/__init__.py +34 -0
  431. package/hooks/modules/evidence/assertions.py +137 -0
  432. package/hooks/modules/evidence/index_writer.py +57 -0
  433. package/hooks/modules/evidence/loader.py +126 -0
  434. package/hooks/modules/evidence/runner.py +241 -0
  435. package/hooks/modules/memory/__init__.py +8 -0
  436. package/hooks/modules/memory/episode_writer.py +216 -0
  437. package/hooks/modules/orchestrator/__init__.py +1 -0
  438. package/hooks/modules/orchestrator/delegate_mode.py +122 -0
  439. package/hooks/modules/scanning/__init__.py +8 -0
  440. package/hooks/modules/scanning/scan_trigger.py +84 -0
  441. package/hooks/modules/security/__init__.py +120 -0
  442. package/hooks/modules/security/approval_cleanup.py +87 -0
  443. package/hooks/modules/security/approval_constants.py +23 -0
  444. package/hooks/modules/security/approval_grants.py +1638 -0
  445. package/hooks/modules/security/approval_messages.py +71 -0
  446. package/hooks/modules/security/approval_scopes.py +222 -0
  447. package/hooks/modules/security/blocked_commands.py +595 -0
  448. package/hooks/modules/security/blocked_message_formatter.py +87 -0
  449. package/hooks/modules/security/command_semantics.py +181 -0
  450. package/hooks/modules/security/composition_rules.py +547 -0
  451. package/hooks/modules/security/flag_classifiers.py +873 -0
  452. package/hooks/modules/security/gitops_validator.py +179 -0
  453. package/hooks/modules/security/mutative_verbs.py +1131 -0
  454. package/hooks/modules/security/network_hosts.py +481 -0
  455. package/hooks/modules/security/prompt_validator.py +40 -0
  456. package/hooks/modules/security/shell_unwrapper.py +165 -0
  457. package/hooks/modules/security/tiers.py +196 -0
  458. package/hooks/modules/session/__init__.py +10 -0
  459. package/hooks/modules/session/pending_scanner.py +174 -0
  460. package/hooks/modules/session/session_context_writer.py +100 -0
  461. package/hooks/modules/session/session_event_injector.py +160 -0
  462. package/hooks/modules/session/session_manager.py +31 -0
  463. package/hooks/modules/session/session_registry.py +333 -0
  464. package/hooks/modules/tools/__init__.py +29 -0
  465. package/hooks/modules/tools/bash_validator.py +1008 -0
  466. package/hooks/modules/tools/cloud_pipe_validator.py +231 -0
  467. package/hooks/modules/tools/hook_response.py +55 -0
  468. package/hooks/modules/tools/shell_parser.py +227 -0
  469. package/hooks/modules/tools/stage_decomposer.py +315 -0
  470. package/hooks/modules/tools/task_validator.py +294 -0
  471. package/hooks/modules/validation/__init__.py +23 -0
  472. package/hooks/modules/validation/commit_validator.py +380 -0
  473. package/hooks/post_compact.py +43 -0
  474. package/hooks/post_tool_use.py +54 -0
  475. package/hooks/pre_compact.py +60 -0
  476. package/hooks/pre_tool_use.py +413 -0
  477. package/hooks/session_end_hook.py +77 -0
  478. package/hooks/session_start.py +81 -0
  479. package/hooks/stop_hook.py +70 -0
  480. package/hooks/subagent_start.py +71 -0
  481. package/hooks/subagent_stop.py +295 -0
  482. package/hooks/task_completed.py +70 -0
  483. package/hooks/user_prompt_submit.py +246 -0
  484. package/index.js +83 -0
  485. package/package.json +103 -0
  486. package/pyproject.toml +32 -0
  487. package/skills/README.md +158 -0
  488. package/skills/agent-creation/SKILL.md +87 -0
  489. package/skills/agent-creation/examples.md +170 -0
  490. package/skills/agent-creation/reference.md +191 -0
  491. package/skills/agent-protocol/SKILL.md +93 -0
  492. package/skills/agent-protocol/examples.md +223 -0
  493. package/skills/agent-response/SKILL.md +69 -0
  494. package/skills/agentic-loop/SKILL.md +80 -0
  495. package/skills/agentic-loop/reference.md +378 -0
  496. package/skills/blog-writing/SKILL.md +98 -0
  497. package/skills/blog-writing/reference.md +130 -0
  498. package/skills/brief-spec/SKILL.md +185 -0
  499. package/skills/command-execution/SKILL.md +64 -0
  500. package/skills/command-execution/reference.md +83 -0
  501. package/skills/context-updater/SKILL.md +87 -0
  502. package/skills/context-updater/examples.md +71 -0
  503. package/skills/developer-patterns/SKILL.md +50 -0
  504. package/skills/developer-patterns/reference.md +112 -0
  505. package/skills/execution/SKILL.md +99 -0
  506. package/skills/fast-queries/SKILL.md +43 -0
  507. package/skills/gaia-compact/SKILL.md +74 -0
  508. package/skills/gaia-patterns/SKILL.md +108 -0
  509. package/skills/gaia-patterns/reference.md +395 -0
  510. package/skills/gaia-planner/SKILL.md +37 -0
  511. package/skills/gaia-planner/reference.md +107 -0
  512. package/skills/gaia-release/SKILL.md +85 -0
  513. package/skills/gaia-release/reference.md +92 -0
  514. package/skills/gaia-self-check/SKILL.md +114 -0
  515. package/skills/gaia-self-check/reference.md +453 -0
  516. package/skills/gaia-verify/SKILL.md +77 -0
  517. package/skills/gaia-verify/reference.md +80 -0
  518. package/skills/git-conventions/SKILL.md +47 -0
  519. package/skills/gitops-patterns/SKILL.md +60 -0
  520. package/skills/gitops-patterns/reference.md +183 -0
  521. package/skills/gmail-policy/SKILL.md +200 -0
  522. package/skills/gmail-policy/reference.md +150 -0
  523. package/skills/gmail-triage/SKILL.md +100 -0
  524. package/skills/gws-setup/SKILL.md +99 -0
  525. package/skills/gws-setup/reference.md +73 -0
  526. package/skills/investigation/SKILL.md +100 -0
  527. package/skills/memory-curation/SKILL.md +83 -0
  528. package/skills/memory-search/SKILL.md +88 -0
  529. package/skills/orchestrator-approval/SKILL.md +160 -0
  530. package/skills/orchestrator-approval/reference.md +174 -0
  531. package/skills/pending-approvals/SKILL.md +72 -0
  532. package/skills/pending-approvals/reference.md +214 -0
  533. package/skills/readme-writing/SKILL.md +71 -0
  534. package/skills/readme-writing/reference.md +188 -0
  535. package/skills/reference.md +135 -0
  536. package/skills/request-approval/SKILL.md +140 -0
  537. package/skills/request-approval/examples.md +140 -0
  538. package/skills/request-approval/reference.md +57 -0
  539. package/skills/schedule-task/SKILL.md +64 -0
  540. package/skills/schedule-task/reference.md +233 -0
  541. package/skills/security-tiers/SKILL.md +141 -0
  542. package/skills/security-tiers/destructive-commands-reference.md +623 -0
  543. package/skills/security-tiers/reference.md +39 -0
  544. package/skills/session-reflection/SKILL.md +69 -0
  545. package/skills/skill-creation/SKILL.md +92 -0
  546. package/skills/skill-creation/reference.md +29 -0
  547. package/skills/terraform-patterns/SKILL.md +89 -0
  548. package/skills/terraform-patterns/reference.md +93 -0
  549. package/templates/README.md +69 -0
  550. package/templates/managed-settings.template.json +43 -0
  551. package/tools/__init__.py +9 -0
  552. package/tools/agentic-loop/decide-status.py +210 -0
  553. package/tools/agentic-loop/parse-metric.py +106 -0
  554. package/tools/agentic-loop/record-iteration.py +221 -0
  555. package/tools/context/README.md +132 -0
  556. package/tools/context/__init__.py +42 -0
  557. package/tools/context/_paths.py +20 -0
  558. package/tools/context/context_provider.py +721 -0
  559. package/tools/context/context_section_reader.py +342 -0
  560. package/tools/context/deep_merge.py +159 -0
  561. package/tools/context/pending_updates.py +760 -0
  562. package/tools/context/surface_router.py +278 -0
  563. package/tools/fast-queries/README.md +65 -0
  564. package/tools/fast-queries/__init__.py +30 -0
  565. package/tools/fast-queries/appservices/quicktriage_devops_developer.sh +75 -0
  566. package/tools/fast-queries/cloud/aws/quicktriage_aws_troubleshooter.sh +32 -0
  567. package/tools/fast-queries/cloud/gcp/quicktriage_gcp_troubleshooter.sh +88 -0
  568. package/tools/fast-queries/gitops/quicktriage_gitops_operator.sh +48 -0
  569. package/tools/fast-queries/run_triage.sh +59 -0
  570. package/tools/fast-queries/terraform/quicktriage_terraform_architect.sh +80 -0
  571. package/tools/gaia_simulator/__init__.py +33 -0
  572. package/tools/gaia_simulator/cli.py +354 -0
  573. package/tools/gaia_simulator/extractor.py +457 -0
  574. package/tools/gaia_simulator/reporter.py +258 -0
  575. package/tools/gaia_simulator/routing_simulator.py +334 -0
  576. package/tools/gaia_simulator/runner.py +539 -0
  577. package/tools/gaia_simulator/skills_mapper.py +264 -0
  578. package/tools/memory/README.md +0 -0
  579. package/tools/memory/__init__.py +20 -0
  580. package/tools/memory/backfill_fts5.py +107 -0
  581. package/tools/memory/conflict_detector.py +295 -0
  582. package/tools/memory/episodic.py +1210 -0
  583. package/tools/memory/git_invalidator.py +262 -0
  584. package/tools/memory/paths.py +102 -0
  585. package/tools/memory/scoring.py +193 -0
  586. package/tools/memory/search_store.py +375 -0
  587. package/tools/persist_transcript_analysis.py +85 -0
  588. package/tools/review/__init__.py +1 -0
  589. package/tools/review/review_engine.py +157 -0
  590. package/tools/scan/__init__.py +35 -0
  591. package/tools/scan/config.py +247 -0
  592. package/tools/scan/merge.py +212 -0
  593. package/tools/scan/orchestrator.py +549 -0
  594. package/tools/scan/registry.py +127 -0
  595. package/tools/scan/scanners/__init__.py +18 -0
  596. package/tools/scan/scanners/base.py +137 -0
  597. package/tools/scan/scanners/environment.py +349 -0
  598. package/tools/scan/scanners/git.py +570 -0
  599. package/tools/scan/scanners/infrastructure.py +875 -0
  600. package/tools/scan/scanners/orchestration.py +600 -0
  601. package/tools/scan/scanners/stack.py +1085 -0
  602. package/tools/scan/scanners/tools.py +260 -0
  603. package/tools/scan/setup.py +686 -0
  604. package/tools/scan/tests/__init__.py +1 -0
  605. package/tools/scan/tests/conftest.py +796 -0
  606. package/tools/scan/tests/test_environment.py +323 -0
  607. package/tools/scan/tests/test_git.py +419 -0
  608. package/tools/scan/tests/test_infrastructure.py +382 -0
  609. package/tools/scan/tests/test_integration.py +920 -0
  610. package/tools/scan/tests/test_merge.py +269 -0
  611. package/tools/scan/tests/test_orchestration.py +304 -0
  612. package/tools/scan/tests/test_stack.py +604 -0
  613. package/tools/scan/tests/test_tools.py +349 -0
  614. package/tools/scan/ui.py +624 -0
  615. package/tools/scan/verify.py +270 -0
  616. package/tools/scan/walk.py +118 -0
  617. package/tools/scan/workspace.py +85 -0
  618. package/tools/validation/README.md +244 -0
  619. package/tools/validation/__init__.py +17 -0
  620. package/tools/validation/approval_gate.py +321 -0
  621. package/tools/validation/validate_skills.py +189 -0
@@ -0,0 +1,196 @@
1
+ """
2
+ Security tier definitions and classification.
3
+
4
+ Provides tier metadata for commands after bash_validator has already
5
+ enforced security decisions. The bash_validator is the primary gate;
6
+ this module's classify_command_tier() is used for logging and state
7
+ tracking.
8
+
9
+ Tiers:
10
+ - T0: Read-only operations (safe by elimination)
11
+ - T1: Validation operations (validate, lint, fmt, check) -- local only
12
+ - T2: Simulation operations (plan, diff, dry-run) -- may contact remote APIs
13
+ - T3: State-modifying operations (mutative_verbs.py detection,
14
+ nonce-based approval via approval_grants.py)
15
+ """
16
+ from __future__ import annotations
17
+
18
+ import re
19
+ import logging
20
+ from enum import Enum
21
+ from functools import lru_cache
22
+
23
+ logger = logging.getLogger(__name__)
24
+
25
+
26
+ class SecurityTier(str, Enum):
27
+ """Security tier classification for commands."""
28
+
29
+ T0_READ_ONLY = "T0" # describe, get, show, list operations
30
+ T1_VALIDATION = "T1" # validate, lint, fmt, check (local only)
31
+ T2_DRY_RUN = "T2" # plan, diff, dry-run, template (simulation)
32
+ T3_BLOCKED = "T3" # apply, reconcile, deploy operations (require approval)
33
+
34
+ def __str__(self) -> str:
35
+ return self.value
36
+
37
+ @property
38
+ def requires_approval(self) -> bool:
39
+ """Check if this tier requires user approval."""
40
+ return self == SecurityTier.T3_BLOCKED
41
+
42
+ @property
43
+ def description(self) -> str:
44
+ """Human-readable description of the tier."""
45
+ descriptions = {
46
+ SecurityTier.T0_READ_ONLY: "Read-only operation",
47
+ SecurityTier.T1_VALIDATION: "Validation operation",
48
+ SecurityTier.T2_DRY_RUN: "Dry-run operation",
49
+ SecurityTier.T3_BLOCKED: "State-modifying operation (requires approval)",
50
+ }
51
+ return descriptions.get(self, "Unknown tier")
52
+
53
+
54
+ # T1: Local validation (no remote API calls)
55
+ T1_PATTERNS = [
56
+ r"\bvalidate\b",
57
+ r"\blint\b",
58
+ r"\bcheck\b",
59
+ r"\bfmt\b",
60
+ ]
61
+
62
+ # T2: Simulation (may contact remote APIs, but no state changes)
63
+ T2_PATTERNS = [
64
+ r"\bplan\b",
65
+ r"\btemplate\b",
66
+ r"\bdiff\b",
67
+ ]
68
+
69
+ # Ultra-common commands that should fast-path to T0
70
+ # These are commands that appear in >80% of sessions
71
+ # NOTE: Only include commands that are ALWAYS read-only regardless of flags.
72
+ # "git branch" was removed because it has mutative variants (-D, -m, -M, etc.).
73
+ ULTRA_COMMON_T0_COMMANDS = frozenset({
74
+ "ls", "pwd", "cat", "echo", "git status", "git diff",
75
+ "git log", "kubectl get",
76
+ })
77
+
78
+
79
+ @lru_cache(maxsize=512)
80
+ def _classify_command_tier_cached(
81
+ command: str,
82
+ has_blocked_patterns: bool = False,
83
+ ) -> SecurityTier:
84
+ """
85
+ Classify command into security tier with LRU cache.
86
+
87
+ This is the internal cached implementation. Use classify_command_tier() instead.
88
+ """
89
+ if not command or not command.strip():
90
+ return SecurityTier.T3_BLOCKED
91
+
92
+ command = command.strip()
93
+
94
+ # Fast-path: Ultra-common T0 commands
95
+ words = command.split()
96
+ if len(words) >= 2:
97
+ prefix2 = f"{words[0]} {words[1]}"
98
+ if prefix2 in ULTRA_COMMON_T0_COMMANDS:
99
+ return SecurityTier.T0_READ_ONLY
100
+ if len(words) >= 1:
101
+ if words[0] in ULTRA_COMMON_T0_COMMANDS:
102
+ return SecurityTier.T0_READ_ONLY
103
+
104
+ # Blocked patterns already checked externally
105
+ if has_blocked_patterns:
106
+ return SecurityTier.T3_BLOCKED
107
+
108
+ # Check for dry-run operations (T2)
109
+ if "--dry-run" in command or "--plan-only" in command:
110
+ return SecurityTier.T2_DRY_RUN
111
+
112
+ # Check for simulation operations (T2: plan, diff, template)
113
+ for pattern in T2_PATTERNS:
114
+ if re.search(pattern, command, re.IGNORECASE):
115
+ return SecurityTier.T2_DRY_RUN
116
+
117
+ # Check for local validation operations (T1: validate, lint, fmt, check)
118
+ for pattern in T1_PATTERNS:
119
+ if re.search(pattern, command, re.IGNORECASE):
120
+ return SecurityTier.T1_VALIDATION
121
+
122
+ # Use the mutative verb detector for T3 classification
123
+ from .mutative_verbs import (
124
+ detect_mutative_command,
125
+ CATEGORY_MUTATIVE,
126
+ CATEGORY_READ_ONLY,
127
+ CATEGORY_SIMULATION,
128
+ )
129
+ result = detect_mutative_command(command)
130
+ if result.is_mutative:
131
+ return SecurityTier.T3_BLOCKED
132
+ if result.category == CATEGORY_SIMULATION:
133
+ return SecurityTier.T2_DRY_RUN
134
+ if result.category == CATEGORY_READ_ONLY:
135
+ return SecurityTier.T0_READ_ONLY
136
+
137
+ # Not blocked, not mutative -> safe by elimination (T0)
138
+ return SecurityTier.T0_READ_ONLY
139
+
140
+
141
+ def classify_command_tier(
142
+ command: str,
143
+ *,
144
+ pre_computed_tier: "SecurityTier | None" = None,
145
+ ) -> SecurityTier:
146
+ """
147
+ Classify command into security tier.
148
+
149
+ NOTE: This function is used for tier metadata AFTER the bash_validator has
150
+ already enforced security decisions. The bash_validator's own validation
151
+ order (blocked -> safe -> dangerous verbs -> GitOps -> tier) is the primary
152
+ security gate.
153
+
154
+ If *pre_computed_tier* is provided (e.g. from a ``BashValidationResult``
155
+ that already determined the tier during validation), it is returned
156
+ immediately without re-computing.
157
+
158
+ Classification order (when no pre-computed tier):
159
+ 1. Ultra-common T0 fast-path (ls, git status, etc.)
160
+ 2. Blocked patterns (T3) -- checked against pre-compiled patterns
161
+ 3. Dry-run/simulation (T2) -- --dry-run, plan, diff, template
162
+ 4. Local validation (T1) -- validate, lint, fmt, check
163
+ 5. Mutative verb detector (T3) -- MUTATIVE verbs
164
+ 6. Default T0 for everything else (safe by elimination)
165
+
166
+ Args:
167
+ command: Shell command to classify
168
+ pre_computed_tier: Optional tier already determined by an upstream
169
+ validator. When provided the function returns it directly.
170
+
171
+ Returns:
172
+ SecurityTier classification
173
+ """
174
+ # Fast path: caller already knows the tier (e.g. BashValidationResult).
175
+ if pre_computed_tier is not None:
176
+ return pre_computed_tier
177
+
178
+ if not command or not command.strip():
179
+ return SecurityTier.T3_BLOCKED
180
+
181
+ command = command.strip()
182
+
183
+ # Import here to avoid circular imports
184
+ from .blocked_commands import get_blocked_patterns
185
+ blocked_patterns = get_blocked_patterns()
186
+
187
+ # Check for blocked operations first (T3)
188
+ # This must be done before caching since blocked_patterns come from module state
189
+ has_blocked = False
190
+ for pattern in blocked_patterns:
191
+ if pattern.search(command):
192
+ has_blocked = True
193
+ break
194
+
195
+ # Use cached classification
196
+ return _classify_command_tier_cached(command, has_blocked)
@@ -0,0 +1,10 @@
1
+ """Session management module.
2
+
3
+ Provides:
4
+ - session_manager: Session ID generation and management
5
+ - session_event_injector: Filter and inject session events into agent prompts
6
+
7
+ Note: session_state.py has been absorbed into modules.memory.episode_writer.
8
+ """
9
+
10
+ __all__ = []
@@ -0,0 +1,174 @@
1
+ """Scan for deferred pending approvals and format a human-readable summary."""
2
+
3
+ import json
4
+ import logging
5
+ import os
6
+ import time
7
+ from pathlib import Path
8
+ from typing import List, Dict, Optional
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ def scan_pending_approvals(
14
+ approvals_dir: Path,
15
+ session_id: Optional[str] = None,
16
+ current_session_id: Optional[str] = None,
17
+ exclude_live_sessions: bool = False,
18
+ ) -> List[Dict]:
19
+ """Scan approvals directory for pending files.
20
+
21
+ Returns list of dicts with: nonce (short), command, verb, category,
22
+ age_human (e.g. "14 hours ago"), context (if enriched), timestamp,
23
+ cross_session (bool), pending_session_id.
24
+
25
+ If session_id provided, filter to that session. Otherwise return all.
26
+ current_session_id is used to annotate items from prior sessions
27
+ (cross_session=True when pending.session_id != current_session_id).
28
+
29
+ If exclude_live_sessions is True, pendings whose owning session_id
30
+ is currently registered as alive (per session_registry.get_live_sessions)
31
+ are filtered out. This is used by the [ACTIONABLE] injection path and
32
+ the `gaia approvals list --orphans-only` CLI flag to avoid showing
33
+ cross-session pendings that a parallel live session may still resolve.
34
+ On registry errors the function logs a warning and returns all pendings
35
+ unfiltered (conservative: better to show extras than lose real pendings).
36
+ """
37
+ results = []
38
+
39
+ if not approvals_dir.exists():
40
+ return results
41
+
42
+ for f in approvals_dir.glob("pending-*.json"):
43
+ if "index" in f.name:
44
+ continue
45
+ try:
46
+ data = json.loads(f.read_text())
47
+ # Clean up expired pendings (ttl > 0 and expired)
48
+ ttl = data.get("ttl_minutes", 0)
49
+ if ttl > 0:
50
+ elapsed = (time.time() - data.get("timestamp", 0)) / 60
51
+ if elapsed > ttl:
52
+ try:
53
+ os.unlink(str(f))
54
+ except OSError:
55
+ pass
56
+ continue
57
+ # Clean up rejected pendings
58
+ if data.get("status") == "rejected":
59
+ try:
60
+ os.unlink(str(f))
61
+ except OSError:
62
+ pass
63
+ continue
64
+ # Filter by session if requested
65
+ if session_id and data.get("session_id") != session_id:
66
+ continue
67
+ # Format age
68
+ age_seconds = time.time() - data.get("timestamp", 0)
69
+ age_human = _format_age(age_seconds)
70
+
71
+ # Detect cross-session pending approvals
72
+ pending_sid = data.get("session_id", "unknown")
73
+ cross_session = bool(
74
+ current_session_id and pending_sid != current_session_id
75
+ )
76
+
77
+ results.append({
78
+ "nonce_short": data["nonce"][:8],
79
+ "nonce_full": data["nonce"],
80
+ "command": data.get("command", data.get("file_path", "unknown")),
81
+ "verb": data.get("danger_verb", "unknown"),
82
+ "category": data.get("danger_category", "UNKNOWN"),
83
+ "age_human": age_human,
84
+ "timestamp": data.get("timestamp", 0),
85
+ "context": data.get("context", {}),
86
+ "scope_type": data.get("scope_type", "semantic_signature"),
87
+ "cross_session": cross_session,
88
+ "pending_session_id": pending_sid,
89
+ })
90
+ except Exception:
91
+ continue
92
+
93
+ # Optionally exclude pendings whose owning session is currently alive.
94
+ # Lazy import keeps the registry dependency out of modules that call
95
+ # scan_pending_approvals() without the flag.
96
+ if exclude_live_sessions:
97
+ try:
98
+ from modules.session.session_registry import get_live_sessions
99
+ live = get_live_sessions()
100
+ results = [r for r in results if r["pending_session_id"] not in live]
101
+ except Exception as exc: # noqa: BLE001 — deliberate broad catch
102
+ logger.warning(
103
+ "scan_pending_approvals: get_live_sessions() failed (%s) "
104
+ "— returning all pendings unfiltered",
105
+ exc,
106
+ )
107
+
108
+ # Sort by timestamp (oldest first)
109
+ results.sort(key=lambda x: x["timestamp"])
110
+ return results
111
+
112
+
113
+ def format_pending_summary(pendings: List[Dict]) -> str:
114
+ """Format pending approvals as a readable summary for injection."""
115
+ if not pendings:
116
+ return ""
117
+
118
+ lines = [f"## {len(pendings)} aprobaciones pendientes\n"]
119
+ for i, p in enumerate(pendings, 1):
120
+ ctx = p["context"]
121
+ source = ctx.get("source", "unknown")
122
+ desc = ctx.get("description", p["command"])
123
+ risk = ctx.get("risk", "unknown")
124
+
125
+ cross_tag = " [session anterior]" if p.get("cross_session") else ""
126
+ lines.append(f"**#{i} [P-{p['nonce_short']}]** `{p['command'][:60]}`{cross_tag}")
127
+ lines.append(f" Hace: {p['age_human']} | Source: {source} | Risk: {risk}")
128
+ if desc != p["command"]:
129
+ lines.append(f" {desc}")
130
+ lines.append("")
131
+
132
+ lines.append('Di "ver P-XXXX" para detalles o "aprobar P-XXXX" para ejecutar.')
133
+ return "\n".join(lines)
134
+
135
+
136
+ def format_pending_detail(pending: Dict) -> str:
137
+ """Format a single pending approval with full details."""
138
+ ctx = pending["context"]
139
+ lines = [
140
+ f"## Detalle P-{pending['nonce_short']}",
141
+ "",
142
+ f"**OPERACION:** {pending['verb']} ({pending['category']})",
143
+ f"**COMANDO:** `{pending['command']}`",
144
+ ]
145
+ if ctx.get("description"):
146
+ lines.append(f"**CONTEXTO:** {ctx['description']}")
147
+ if ctx.get("source"):
148
+ lines.append(f"**SOURCE:** {ctx['source']}")
149
+ if ctx.get("branch"):
150
+ lines.append(f"**BRANCH:** {ctx['branch']}")
151
+ if ctx.get("files_changed"):
152
+ lines.append(f"**ARCHIVOS:** {', '.join(ctx['files_changed'])}")
153
+ if ctx.get("risk"):
154
+ lines.append(f"**RIESGO:** {ctx['risk']}")
155
+ if ctx.get("rollback"):
156
+ lines.append(f"**ROLLBACK:** {ctx['rollback']}")
157
+ lines.append(f"**EDAD:** {pending['age_human']}")
158
+ lines.append("")
159
+ lines.append(f'"aprobar P-{pending["nonce_short"]}" o "rechazar P-{pending["nonce_short"]}"')
160
+ return "\n".join(lines)
161
+
162
+
163
+ def _format_age(seconds: float) -> str:
164
+ """Format seconds into human-readable age."""
165
+ if seconds < 60:
166
+ return f"{int(seconds)}s"
167
+ elif seconds < 3600:
168
+ return f"{int(seconds/60)} min"
169
+ elif seconds < 86400:
170
+ hours = int(seconds / 3600)
171
+ return f"{hours} hora{'s' if hours > 1 else ''}"
172
+ else:
173
+ days = int(seconds / 86400)
174
+ return f"{days} dia{'s' if days > 1 else ''}"
@@ -0,0 +1,100 @@
1
+ """
2
+ Session context writer for PostToolUse hook.
3
+
4
+ Manages the active session context file, appending critical events
5
+ (git commits, pushes, etc.) and applying a time-based retention policy.
6
+
7
+ Public API:
8
+ - SessionContextWriter (class with update_context method)
9
+ """
10
+
11
+ import fcntl
12
+ import json
13
+ import logging
14
+ import os
15
+ from datetime import datetime, timedelta
16
+ from pathlib import Path
17
+ from typing import Dict, Any
18
+
19
+ from ..core.paths import get_session_dir
20
+
21
+ logger = logging.getLogger(__name__)
22
+
23
+ # Default retention period for session events
24
+ DEFAULT_RETENTION_HOURS = 24
25
+
26
+
27
+ class SessionContextWriter:
28
+ """Update active session context for critical events.
29
+
30
+ Thread-safe via file locking. Applies a configurable retention
31
+ policy (default 24h, override via SESSION_RETENTION_HOURS env var).
32
+ """
33
+
34
+ def __init__(self, context_path: Path = None):
35
+ """Initialize with optional custom context path.
36
+
37
+ Args:
38
+ context_path: Override path. Defaults to session_dir/context.json.
39
+ """
40
+ self.context_path = context_path or (get_session_dir() / "context.json")
41
+
42
+ def update_context(self, event_data: Dict[str, Any]) -> None:
43
+ """Update active context with event data.
44
+
45
+ Appends the event to the critical_events list, applies retention
46
+ policy, and writes back atomically with file locking.
47
+
48
+ Args:
49
+ event_data: Event dict (must include at least event_type).
50
+ """
51
+ try:
52
+ self.context_path.parent.mkdir(parents=True, exist_ok=True)
53
+
54
+ # File lock to prevent race conditions from parallel tool calls
55
+ lock_path = self.context_path.with_suffix(".lock")
56
+ with open(lock_path, "w") as lock_file:
57
+ fcntl.flock(lock_file.fileno(), fcntl.LOCK_EX)
58
+ try:
59
+ context: Dict[str, Any] = {}
60
+ if self.context_path.exists():
61
+ with open(self.context_path, "r") as f:
62
+ context = json.load(f)
63
+
64
+ if "critical_events" not in context:
65
+ context["critical_events"] = []
66
+
67
+ event_data["timestamp"] = datetime.now().isoformat()
68
+
69
+ context["critical_events"].append(event_data)
70
+
71
+ # Keep only events within retention window
72
+ retention_hours = int(
73
+ os.environ.get(
74
+ "SESSION_RETENTION_HOURS",
75
+ str(DEFAULT_RETENTION_HOURS),
76
+ )
77
+ )
78
+ cutoff = datetime.now() - timedelta(hours=retention_hours)
79
+
80
+ context["critical_events"] = [
81
+ event
82
+ for event in context["critical_events"]
83
+ if event.get("timestamp")
84
+ and datetime.fromisoformat(event["timestamp"]) > cutoff
85
+ ]
86
+
87
+ context["last_modified"] = datetime.now().isoformat()
88
+
89
+ with open(self.context_path, "w") as f:
90
+ json.dump(context, f, indent=2)
91
+ finally:
92
+ fcntl.flock(lock_file.fileno(), fcntl.LOCK_UN)
93
+
94
+ logger.info(
95
+ "Updated context with event: %s",
96
+ event_data.get("event_type", "unknown"),
97
+ )
98
+
99
+ except Exception as e:
100
+ logger.error("Error updating active context: %s", e)
@@ -0,0 +1,160 @@
1
+ """Session event injection for agent context.
2
+
3
+ Subsystem 4 of the pre_tool_use Task/Agent path.
4
+
5
+ Filters events by agent domain and injects them into agent prompts.
6
+ Includes the hardcoded agent-to-event mapping.
7
+ """
8
+ from __future__ import annotations
9
+
10
+ import json
11
+ import logging
12
+ from pathlib import Path
13
+
14
+ logger = logging.getLogger(__name__)
15
+
16
+ # Agent-to-event-type mapping: which events each agent should see
17
+ AGENT_EVENT_FILTERS = {
18
+ "terraform-architect": ["git_commit", "infrastructure_change"],
19
+ "gitops-operator": ["git_commit", "git_push", "infrastructure_change"],
20
+ "developer": ["git_commit", "file_modifications"],
21
+ "cloud-troubleshooter": "*", # All events (needs full history for diagnosis)
22
+ "gaia-system": "*", # All events (workflow analysis)
23
+ "gaia-operator": ["git_commit", "file_modifications", "infrastructure_change"],
24
+ "gaia-planner": ["git_commit", "file_modifications"],
25
+ }
26
+
27
+
28
+ def filter_events_for_agent(events: list, agent: str) -> list:
29
+ """
30
+ Filter events relevant to agent domain.
31
+
32
+ Args:
33
+ events: List of critical events from session
34
+ agent: Agent type (e.g., "gitops-operator")
35
+
36
+ Returns:
37
+ Filtered list of events relevant to agent
38
+ """
39
+ agent_filter = AGENT_EVENT_FILTERS.get(agent, [])
40
+
41
+ # Return all events for wildcard agents
42
+ if agent_filter == "*":
43
+ return events[-10:] # Last 10 events
44
+
45
+ # Filter by event type and return max 10
46
+ filtered = [
47
+ e for e in events[-20:] # Search last 20
48
+ if e.get("event_type") in agent_filter
49
+ ]
50
+
51
+ return filtered[:10] # Return max 10
52
+
53
+
54
+ def format_events_summary(events: list) -> str:
55
+ """
56
+ Format events as readable summary for agent context.
57
+
58
+ Args:
59
+ events: List of filtered events
60
+
61
+ Returns:
62
+ Formatted markdown string
63
+ """
64
+ if not events:
65
+ return "No recent events"
66
+
67
+ lines = []
68
+
69
+ for event in events:
70
+ etype = event.get("event_type", "")
71
+ ts = event.get("timestamp", "")[:16] # YYYY-MM-DDTHH:MM
72
+
73
+ if etype == "git_commit":
74
+ msg = event.get("commit_message", "")
75
+ hash_val = event.get("commit_hash", "")[:7]
76
+ if hash_val and msg:
77
+ lines.append(f"- [{ts}] Commit {hash_val}: {msg}")
78
+
79
+ elif etype == "git_push":
80
+ branch = event.get("branch", "")
81
+ if branch:
82
+ lines.append(f"- [{ts}] Pushed to {branch}")
83
+
84
+ elif etype == "file_modifications":
85
+ count = event.get("modification_count", 0)
86
+ if count:
87
+ lines.append(f"- [{ts}] Modified {count} files")
88
+
89
+ elif etype == "infrastructure_change":
90
+ cmd = event.get("command", "")
91
+ if cmd:
92
+ lines.append(f"- [{ts}] Infrastructure: {cmd}")
93
+
94
+ return "\n".join(lines) if lines else "No recent events"
95
+
96
+
97
+ def build_session_events(
98
+ parameters: dict,
99
+ project_agents: list,
100
+ ) -> str | None:
101
+ """
102
+ Build session events string for agent context without mutating parameters.
103
+
104
+ Filters events by agent domain to avoid noise.
105
+ Returns the events string suitable for additionalContext injection,
106
+ or None if no events to inject.
107
+
108
+ Args:
109
+ parameters: Task tool parameters (read-only).
110
+ project_agents: List of valid project agent names.
111
+
112
+ Returns:
113
+ Session events string, or None if nothing to inject.
114
+ """
115
+ subagent_type = parameters.get("subagent_type", "")
116
+
117
+ # Only inject for project agents
118
+ if subagent_type not in project_agents:
119
+ logger.debug(f"Skipping session events for non-project agent: {subagent_type}")
120
+ return None
121
+
122
+ # Get session events
123
+ from ..core.paths import get_session_dir
124
+ context_path = get_session_dir() / "context.json"
125
+ if not context_path.exists():
126
+ logger.debug("No session context file found")
127
+ return None
128
+
129
+ try:
130
+ with open(context_path, 'r') as f:
131
+ context = json.load(f)
132
+
133
+ events = context.get("critical_events", [])
134
+ if not events:
135
+ logger.debug("No critical events in session")
136
+ return None
137
+
138
+ # Filter by agent domain
139
+ filtered = filter_events_for_agent(events, subagent_type)
140
+
141
+ if not filtered:
142
+ logger.debug(f"No relevant events for {subagent_type}")
143
+ return None
144
+
145
+ # Format events summary
146
+ events_summary = format_events_summary(filtered)
147
+
148
+ events_string = (
149
+ "# Recent Session Events (Auto-Injected, Last 24h)\n"
150
+ f"{events_summary}"
151
+ )
152
+ logger.info(f"Session events built for {subagent_type} ({len(filtered)} events)")
153
+
154
+ return events_string
155
+
156
+ except Exception as e:
157
+ logger.warning(f"Failed to build session events: {e}")
158
+ return None
159
+
160
+
@@ -0,0 +1,31 @@
1
+ """
2
+ Session ID generation and retrieval.
3
+
4
+ Provides:
5
+ - get_or_create_session_id(): Get existing session ID or create new one
6
+ """
7
+
8
+ import hashlib
9
+ import logging
10
+ import os
11
+ from datetime import datetime
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ def get_or_create_session_id() -> str:
17
+ """Get existing session ID or create new one.
18
+
19
+ Checks the CLAUDE_SESSION_ID env var first. If absent, generates a
20
+ new session ID from the current time and PID, stores it in the env var,
21
+ and returns it.
22
+ """
23
+ session_id = os.environ.get("CLAUDE_SESSION_ID")
24
+ if not session_id:
25
+ timestamp = datetime.now().strftime("%H%M%S")
26
+ hash_input = f"{timestamp}-{os.getpid()}"
27
+ session_hash = hashlib.sha256(hash_input.encode()).hexdigest()[:8]
28
+ session_id = f"session-{timestamp}-{session_hash}"
29
+ os.environ["CLAUDE_SESSION_ID"] = session_id
30
+ logger.debug(f"Generated new session_id: {session_id}")
31
+ return session_id