@jaguilar87/gaia 5.0.0-rc1

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 (609) 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 +1212 -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 +237 -0
  16. package/agents/gaia-planner.md +53 -0
  17. package/agents/gaia-system.md +70 -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 +628 -0
  26. package/bin/cli/history.py +305 -0
  27. package/bin/cli/memory.py +464 -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 +816 -0
  45. package/bin/pre-publish-validate.js +610 -0
  46. package/bin/python-detect.js +60 -0
  47. package/commands/README.md +64 -0
  48. package/commands/gaia.md +37 -0
  49. package/commands/scan-project.md +67 -0
  50. package/config/README.md +71 -0
  51. package/config/cloud/aws.json +134 -0
  52. package/config/cloud/gcp.json +139 -0
  53. package/config/context-contracts.json +158 -0
  54. package/config/crons-schema.md +81 -0
  55. package/config/git_standards.json +72 -0
  56. package/config/surface-routing.json +421 -0
  57. package/config/universal-rules.json +102 -0
  58. package/dist/gaia-ops/.claude-plugin/plugin.json +24 -0
  59. package/dist/gaia-ops/README.md +80 -0
  60. package/dist/gaia-ops/agents/cloud-troubleshooter.md +73 -0
  61. package/dist/gaia-ops/agents/developer.md +65 -0
  62. package/dist/gaia-ops/agents/gaia-operator.md +64 -0
  63. package/dist/gaia-ops/agents/gaia-orchestrator.md +237 -0
  64. package/dist/gaia-ops/agents/gaia-planner.md +53 -0
  65. package/dist/gaia-ops/agents/gaia-system.md +70 -0
  66. package/dist/gaia-ops/agents/gitops-operator.md +61 -0
  67. package/dist/gaia-ops/agents/terraform-architect.md +63 -0
  68. package/dist/gaia-ops/commands/gaia.md +37 -0
  69. package/dist/gaia-ops/config/README.md +71 -0
  70. package/dist/gaia-ops/config/cloud/aws.json +134 -0
  71. package/dist/gaia-ops/config/cloud/gcp.json +139 -0
  72. package/dist/gaia-ops/config/context-contracts.json +158 -0
  73. package/dist/gaia-ops/config/crons-schema.md +81 -0
  74. package/dist/gaia-ops/config/git_standards.json +72 -0
  75. package/dist/gaia-ops/config/surface-routing.json +421 -0
  76. package/dist/gaia-ops/config/universal-rules.json +102 -0
  77. package/dist/gaia-ops/hooks/adapters/__init__.py +52 -0
  78. package/dist/gaia-ops/hooks/adapters/base.py +219 -0
  79. package/dist/gaia-ops/hooks/adapters/channel.py +17 -0
  80. package/dist/gaia-ops/hooks/adapters/claude_code.py +1890 -0
  81. package/dist/gaia-ops/hooks/adapters/types.py +194 -0
  82. package/dist/gaia-ops/hooks/adapters/utils.py +25 -0
  83. package/dist/gaia-ops/hooks/hooks.json +163 -0
  84. package/dist/gaia-ops/hooks/modules/__init__.py +15 -0
  85. package/dist/gaia-ops/hooks/modules/agents/__init__.py +29 -0
  86. package/dist/gaia-ops/hooks/modules/agents/contract_validator.py +647 -0
  87. package/dist/gaia-ops/hooks/modules/agents/response_contract.py +496 -0
  88. package/dist/gaia-ops/hooks/modules/agents/skill_injection_verifier.py +120 -0
  89. package/dist/gaia-ops/hooks/modules/agents/state_tracker.py +267 -0
  90. package/dist/gaia-ops/hooks/modules/agents/task_info_builder.py +74 -0
  91. package/dist/gaia-ops/hooks/modules/agents/transcript_analyzer.py +458 -0
  92. package/dist/gaia-ops/hooks/modules/agents/transcript_reader.py +152 -0
  93. package/dist/gaia-ops/hooks/modules/audit/__init__.py +28 -0
  94. package/dist/gaia-ops/hooks/modules/audit/event_detector.py +168 -0
  95. package/dist/gaia-ops/hooks/modules/audit/logger.py +131 -0
  96. package/dist/gaia-ops/hooks/modules/audit/metrics.py +134 -0
  97. package/dist/gaia-ops/hooks/modules/audit/workflow_auditor.py +611 -0
  98. package/dist/gaia-ops/hooks/modules/audit/workflow_recorder.py +296 -0
  99. package/dist/gaia-ops/hooks/modules/context/__init__.py +11 -0
  100. package/dist/gaia-ops/hooks/modules/context/agentic_loop_detector.py +165 -0
  101. package/dist/gaia-ops/hooks/modules/context/anchor_tracker.py +317 -0
  102. package/dist/gaia-ops/hooks/modules/context/compact_context_builder.py +218 -0
  103. package/dist/gaia-ops/hooks/modules/context/context_freshness.py +145 -0
  104. package/dist/gaia-ops/hooks/modules/context/context_injector.py +558 -0
  105. package/dist/gaia-ops/hooks/modules/context/context_writer.py +530 -0
  106. package/dist/gaia-ops/hooks/modules/context/contracts_loader.py +161 -0
  107. package/dist/gaia-ops/hooks/modules/core/__init__.py +40 -0
  108. package/dist/gaia-ops/hooks/modules/core/hook_entry.py +78 -0
  109. package/dist/gaia-ops/hooks/modules/core/paths.py +160 -0
  110. package/dist/gaia-ops/hooks/modules/core/plugin_mode.py +149 -0
  111. package/dist/gaia-ops/hooks/modules/core/plugin_setup.py +577 -0
  112. package/dist/gaia-ops/hooks/modules/core/state.py +179 -0
  113. package/dist/gaia-ops/hooks/modules/core/stdin.py +24 -0
  114. package/dist/gaia-ops/hooks/modules/events/__init__.py +1 -0
  115. package/dist/gaia-ops/hooks/modules/events/event_writer.py +210 -0
  116. package/dist/gaia-ops/hooks/modules/memory/__init__.py +8 -0
  117. package/dist/gaia-ops/hooks/modules/memory/episode_writer.py +216 -0
  118. package/dist/gaia-ops/hooks/modules/orchestrator/__init__.py +1 -0
  119. package/dist/gaia-ops/hooks/modules/orchestrator/delegate_mode.py +122 -0
  120. package/dist/gaia-ops/hooks/modules/scanning/__init__.py +8 -0
  121. package/dist/gaia-ops/hooks/modules/scanning/scan_trigger.py +84 -0
  122. package/dist/gaia-ops/hooks/modules/security/__init__.py +120 -0
  123. package/dist/gaia-ops/hooks/modules/security/approval_cleanup.py +87 -0
  124. package/dist/gaia-ops/hooks/modules/security/approval_constants.py +23 -0
  125. package/dist/gaia-ops/hooks/modules/security/approval_grants.py +1638 -0
  126. package/dist/gaia-ops/hooks/modules/security/approval_messages.py +71 -0
  127. package/dist/gaia-ops/hooks/modules/security/approval_scopes.py +222 -0
  128. package/dist/gaia-ops/hooks/modules/security/blocked_commands.py +595 -0
  129. package/dist/gaia-ops/hooks/modules/security/blocked_message_formatter.py +87 -0
  130. package/dist/gaia-ops/hooks/modules/security/command_semantics.py +181 -0
  131. package/dist/gaia-ops/hooks/modules/security/composition_rules.py +547 -0
  132. package/dist/gaia-ops/hooks/modules/security/flag_classifiers.py +873 -0
  133. package/dist/gaia-ops/hooks/modules/security/gitops_validator.py +179 -0
  134. package/dist/gaia-ops/hooks/modules/security/mutative_verbs.py +1131 -0
  135. package/dist/gaia-ops/hooks/modules/security/network_hosts.py +481 -0
  136. package/dist/gaia-ops/hooks/modules/security/prompt_validator.py +40 -0
  137. package/dist/gaia-ops/hooks/modules/security/shell_unwrapper.py +165 -0
  138. package/dist/gaia-ops/hooks/modules/security/tiers.py +196 -0
  139. package/dist/gaia-ops/hooks/modules/session/__init__.py +10 -0
  140. package/dist/gaia-ops/hooks/modules/session/pending_scanner.py +174 -0
  141. package/dist/gaia-ops/hooks/modules/session/session_context_writer.py +100 -0
  142. package/dist/gaia-ops/hooks/modules/session/session_event_injector.py +160 -0
  143. package/dist/gaia-ops/hooks/modules/session/session_manager.py +31 -0
  144. package/dist/gaia-ops/hooks/modules/session/session_registry.py +232 -0
  145. package/dist/gaia-ops/hooks/modules/tools/__init__.py +29 -0
  146. package/dist/gaia-ops/hooks/modules/tools/bash_validator.py +1008 -0
  147. package/dist/gaia-ops/hooks/modules/tools/cloud_pipe_validator.py +231 -0
  148. package/dist/gaia-ops/hooks/modules/tools/hook_response.py +55 -0
  149. package/dist/gaia-ops/hooks/modules/tools/shell_parser.py +227 -0
  150. package/dist/gaia-ops/hooks/modules/tools/stage_decomposer.py +315 -0
  151. package/dist/gaia-ops/hooks/modules/tools/task_validator.py +294 -0
  152. package/dist/gaia-ops/hooks/modules/validation/__init__.py +23 -0
  153. package/dist/gaia-ops/hooks/modules/validation/commit_validator.py +380 -0
  154. package/dist/gaia-ops/hooks/post_compact.py +43 -0
  155. package/dist/gaia-ops/hooks/post_tool_use.py +54 -0
  156. package/dist/gaia-ops/hooks/pre_compact.py +60 -0
  157. package/dist/gaia-ops/hooks/pre_tool_use.py +413 -0
  158. package/dist/gaia-ops/hooks/session_start.py +81 -0
  159. package/dist/gaia-ops/hooks/stop_hook.py +82 -0
  160. package/dist/gaia-ops/hooks/subagent_start.py +71 -0
  161. package/dist/gaia-ops/hooks/subagent_stop.py +295 -0
  162. package/dist/gaia-ops/hooks/task_completed.py +70 -0
  163. package/dist/gaia-ops/hooks/user_prompt_submit.py +246 -0
  164. package/dist/gaia-ops/settings.json +72 -0
  165. package/dist/gaia-ops/skills/README.md +154 -0
  166. package/dist/gaia-ops/skills/agent-protocol/SKILL.md +93 -0
  167. package/dist/gaia-ops/skills/agent-protocol/examples.md +223 -0
  168. package/dist/gaia-ops/skills/agent-response/SKILL.md +69 -0
  169. package/dist/gaia-ops/skills/agentic-loop/SKILL.md +80 -0
  170. package/dist/gaia-ops/skills/agentic-loop/reference.md +378 -0
  171. package/dist/gaia-ops/skills/blog-writing/SKILL.md +98 -0
  172. package/dist/gaia-ops/skills/blog-writing/reference.md +130 -0
  173. package/dist/gaia-ops/skills/brief-spec/SKILL.md +182 -0
  174. package/dist/gaia-ops/skills/command-execution/SKILL.md +64 -0
  175. package/dist/gaia-ops/skills/command-execution/reference.md +83 -0
  176. package/dist/gaia-ops/skills/context-updater/SKILL.md +87 -0
  177. package/dist/gaia-ops/skills/context-updater/examples.md +71 -0
  178. package/dist/gaia-ops/skills/developer-patterns/SKILL.md +50 -0
  179. package/dist/gaia-ops/skills/developer-patterns/reference.md +112 -0
  180. package/dist/gaia-ops/skills/execution/SKILL.md +99 -0
  181. package/dist/gaia-ops/skills/fast-queries/SKILL.md +43 -0
  182. package/dist/gaia-ops/skills/gaia-compact/SKILL.md +74 -0
  183. package/dist/gaia-ops/skills/gaia-patterns/SKILL.md +108 -0
  184. package/dist/gaia-ops/skills/gaia-patterns/reference.md +395 -0
  185. package/dist/gaia-ops/skills/gaia-planner/SKILL.md +37 -0
  186. package/dist/gaia-ops/skills/gaia-planner/reference.md +107 -0
  187. package/dist/gaia-ops/skills/gaia-release/SKILL.md +82 -0
  188. package/dist/gaia-ops/skills/gaia-release/reference.md +102 -0
  189. package/dist/gaia-ops/skills/gaia-self-check/SKILL.md +114 -0
  190. package/dist/gaia-ops/skills/gaia-self-check/reference.md +453 -0
  191. package/dist/gaia-ops/skills/gaia-verify/SKILL.md +77 -0
  192. package/dist/gaia-ops/skills/gaia-verify/reference.md +80 -0
  193. package/dist/gaia-ops/skills/git-conventions/SKILL.md +47 -0
  194. package/dist/gaia-ops/skills/gitops-patterns/SKILL.md +60 -0
  195. package/dist/gaia-ops/skills/gitops-patterns/reference.md +183 -0
  196. package/dist/gaia-ops/skills/gmail-policy/SKILL.md +200 -0
  197. package/dist/gaia-ops/skills/gmail-policy/reference.md +150 -0
  198. package/dist/gaia-ops/skills/gmail-triage/SKILL.md +100 -0
  199. package/dist/gaia-ops/skills/gws-setup/SKILL.md +99 -0
  200. package/dist/gaia-ops/skills/gws-setup/reference.md +73 -0
  201. package/dist/gaia-ops/skills/investigation/SKILL.md +100 -0
  202. package/dist/gaia-ops/skills/memory-curation/SKILL.md +83 -0
  203. package/dist/gaia-ops/skills/memory-search/SKILL.md +88 -0
  204. package/dist/gaia-ops/skills/orchestrator-approval/SKILL.md +160 -0
  205. package/dist/gaia-ops/skills/orchestrator-approval/reference.md +174 -0
  206. package/dist/gaia-ops/skills/pending-approvals/SKILL.md +72 -0
  207. package/dist/gaia-ops/skills/pending-approvals/reference.md +214 -0
  208. package/dist/gaia-ops/skills/readme-writing/SKILL.md +71 -0
  209. package/dist/gaia-ops/skills/readme-writing/reference.md +188 -0
  210. package/dist/gaia-ops/skills/reference.md +135 -0
  211. package/dist/gaia-ops/skills/request-approval/SKILL.md +140 -0
  212. package/dist/gaia-ops/skills/request-approval/examples.md +140 -0
  213. package/dist/gaia-ops/skills/request-approval/reference.md +57 -0
  214. package/dist/gaia-ops/skills/schedule-task/SKILL.md +64 -0
  215. package/dist/gaia-ops/skills/schedule-task/reference.md +233 -0
  216. package/dist/gaia-ops/skills/security-tiers/SKILL.md +141 -0
  217. package/dist/gaia-ops/skills/security-tiers/destructive-commands-reference.md +623 -0
  218. package/dist/gaia-ops/skills/security-tiers/reference.md +39 -0
  219. package/dist/gaia-ops/skills/skill-creation/SKILL.md +92 -0
  220. package/dist/gaia-ops/skills/skill-creation/reference.md +29 -0
  221. package/dist/gaia-ops/skills/terraform-patterns/SKILL.md +89 -0
  222. package/dist/gaia-ops/skills/terraform-patterns/reference.md +93 -0
  223. package/dist/gaia-ops/tools/__init__.py +9 -0
  224. package/dist/gaia-ops/tools/agentic-loop/decide-status.py +210 -0
  225. package/dist/gaia-ops/tools/agentic-loop/parse-metric.py +106 -0
  226. package/dist/gaia-ops/tools/agentic-loop/record-iteration.py +221 -0
  227. package/dist/gaia-ops/tools/context/README.md +132 -0
  228. package/dist/gaia-ops/tools/context/__init__.py +42 -0
  229. package/dist/gaia-ops/tools/context/_paths.py +20 -0
  230. package/dist/gaia-ops/tools/context/context_provider.py +721 -0
  231. package/dist/gaia-ops/tools/context/context_section_reader.py +342 -0
  232. package/dist/gaia-ops/tools/context/deep_merge.py +159 -0
  233. package/dist/gaia-ops/tools/context/pending_updates.py +760 -0
  234. package/dist/gaia-ops/tools/context/surface_router.py +278 -0
  235. package/dist/gaia-ops/tools/fast-queries/README.md +65 -0
  236. package/dist/gaia-ops/tools/fast-queries/__init__.py +30 -0
  237. package/dist/gaia-ops/tools/fast-queries/appservices/quicktriage_devops_developer.sh +75 -0
  238. package/dist/gaia-ops/tools/fast-queries/cloud/aws/quicktriage_aws_troubleshooter.sh +32 -0
  239. package/dist/gaia-ops/tools/fast-queries/cloud/gcp/quicktriage_gcp_troubleshooter.sh +88 -0
  240. package/dist/gaia-ops/tools/fast-queries/gitops/quicktriage_gitops_operator.sh +48 -0
  241. package/dist/gaia-ops/tools/fast-queries/run_triage.sh +59 -0
  242. package/dist/gaia-ops/tools/fast-queries/terraform/quicktriage_terraform_architect.sh +80 -0
  243. package/dist/gaia-ops/tools/gaia_simulator/__init__.py +33 -0
  244. package/dist/gaia-ops/tools/gaia_simulator/cli.py +354 -0
  245. package/dist/gaia-ops/tools/gaia_simulator/extractor.py +457 -0
  246. package/dist/gaia-ops/tools/gaia_simulator/reporter.py +258 -0
  247. package/dist/gaia-ops/tools/gaia_simulator/routing_simulator.py +334 -0
  248. package/dist/gaia-ops/tools/gaia_simulator/runner.py +539 -0
  249. package/dist/gaia-ops/tools/gaia_simulator/skills_mapper.py +264 -0
  250. package/dist/gaia-ops/tools/memory/README.md +0 -0
  251. package/dist/gaia-ops/tools/memory/__init__.py +20 -0
  252. package/dist/gaia-ops/tools/memory/backfill_fts5.py +107 -0
  253. package/dist/gaia-ops/tools/memory/conflict_detector.py +295 -0
  254. package/dist/gaia-ops/tools/memory/episodic.py +1210 -0
  255. package/dist/gaia-ops/tools/memory/git_invalidator.py +262 -0
  256. package/dist/gaia-ops/tools/memory/paths.py +102 -0
  257. package/dist/gaia-ops/tools/memory/scoring.py +193 -0
  258. package/dist/gaia-ops/tools/memory/search_store.py +360 -0
  259. package/dist/gaia-ops/tools/persist_transcript_analysis.py +85 -0
  260. package/dist/gaia-ops/tools/review/__init__.py +1 -0
  261. package/dist/gaia-ops/tools/review/review_engine.py +157 -0
  262. package/dist/gaia-ops/tools/scan/__init__.py +35 -0
  263. package/dist/gaia-ops/tools/scan/config.py +247 -0
  264. package/dist/gaia-ops/tools/scan/merge.py +212 -0
  265. package/dist/gaia-ops/tools/scan/orchestrator.py +549 -0
  266. package/dist/gaia-ops/tools/scan/registry.py +127 -0
  267. package/dist/gaia-ops/tools/scan/scanners/__init__.py +18 -0
  268. package/dist/gaia-ops/tools/scan/scanners/base.py +137 -0
  269. package/dist/gaia-ops/tools/scan/scanners/environment.py +349 -0
  270. package/dist/gaia-ops/tools/scan/scanners/git.py +570 -0
  271. package/dist/gaia-ops/tools/scan/scanners/infrastructure.py +875 -0
  272. package/dist/gaia-ops/tools/scan/scanners/orchestration.py +600 -0
  273. package/dist/gaia-ops/tools/scan/scanners/stack.py +1085 -0
  274. package/dist/gaia-ops/tools/scan/scanners/tools.py +260 -0
  275. package/dist/gaia-ops/tools/scan/setup.py +686 -0
  276. package/dist/gaia-ops/tools/scan/tests/__init__.py +1 -0
  277. package/dist/gaia-ops/tools/scan/tests/conftest.py +796 -0
  278. package/dist/gaia-ops/tools/scan/tests/test_environment.py +323 -0
  279. package/dist/gaia-ops/tools/scan/tests/test_git.py +419 -0
  280. package/dist/gaia-ops/tools/scan/tests/test_infrastructure.py +382 -0
  281. package/dist/gaia-ops/tools/scan/tests/test_integration.py +920 -0
  282. package/dist/gaia-ops/tools/scan/tests/test_merge.py +269 -0
  283. package/dist/gaia-ops/tools/scan/tests/test_orchestration.py +304 -0
  284. package/dist/gaia-ops/tools/scan/tests/test_stack.py +604 -0
  285. package/dist/gaia-ops/tools/scan/tests/test_tools.py +349 -0
  286. package/dist/gaia-ops/tools/scan/ui.py +624 -0
  287. package/dist/gaia-ops/tools/scan/verify.py +270 -0
  288. package/dist/gaia-ops/tools/scan/walk.py +118 -0
  289. package/dist/gaia-ops/tools/scan/workspace.py +85 -0
  290. package/dist/gaia-ops/tools/validation/README.md +244 -0
  291. package/dist/gaia-ops/tools/validation/__init__.py +17 -0
  292. package/dist/gaia-ops/tools/validation/approval_gate.py +321 -0
  293. package/dist/gaia-ops/tools/validation/validate_skills.py +189 -0
  294. package/dist/gaia-security/.claude-plugin/plugin.json +24 -0
  295. package/dist/gaia-security/README.md +90 -0
  296. package/dist/gaia-security/config/universal-rules.json +102 -0
  297. package/dist/gaia-security/hooks/adapters/__init__.py +52 -0
  298. package/dist/gaia-security/hooks/adapters/base.py +219 -0
  299. package/dist/gaia-security/hooks/adapters/channel.py +17 -0
  300. package/dist/gaia-security/hooks/adapters/claude_code.py +1890 -0
  301. package/dist/gaia-security/hooks/adapters/types.py +194 -0
  302. package/dist/gaia-security/hooks/adapters/utils.py +25 -0
  303. package/dist/gaia-security/hooks/hooks.json +84 -0
  304. package/dist/gaia-security/hooks/modules/__init__.py +15 -0
  305. package/dist/gaia-security/hooks/modules/agents/__init__.py +29 -0
  306. package/dist/gaia-security/hooks/modules/agents/contract_validator.py +647 -0
  307. package/dist/gaia-security/hooks/modules/agents/response_contract.py +496 -0
  308. package/dist/gaia-security/hooks/modules/agents/skill_injection_verifier.py +120 -0
  309. package/dist/gaia-security/hooks/modules/agents/state_tracker.py +267 -0
  310. package/dist/gaia-security/hooks/modules/agents/task_info_builder.py +74 -0
  311. package/dist/gaia-security/hooks/modules/agents/transcript_analyzer.py +458 -0
  312. package/dist/gaia-security/hooks/modules/agents/transcript_reader.py +152 -0
  313. package/dist/gaia-security/hooks/modules/audit/__init__.py +28 -0
  314. package/dist/gaia-security/hooks/modules/audit/event_detector.py +168 -0
  315. package/dist/gaia-security/hooks/modules/audit/logger.py +131 -0
  316. package/dist/gaia-security/hooks/modules/audit/metrics.py +134 -0
  317. package/dist/gaia-security/hooks/modules/audit/workflow_auditor.py +611 -0
  318. package/dist/gaia-security/hooks/modules/audit/workflow_recorder.py +296 -0
  319. package/dist/gaia-security/hooks/modules/context/__init__.py +11 -0
  320. package/dist/gaia-security/hooks/modules/context/agentic_loop_detector.py +165 -0
  321. package/dist/gaia-security/hooks/modules/context/anchor_tracker.py +317 -0
  322. package/dist/gaia-security/hooks/modules/context/compact_context_builder.py +218 -0
  323. package/dist/gaia-security/hooks/modules/context/context_freshness.py +145 -0
  324. package/dist/gaia-security/hooks/modules/context/context_injector.py +558 -0
  325. package/dist/gaia-security/hooks/modules/context/context_writer.py +530 -0
  326. package/dist/gaia-security/hooks/modules/context/contracts_loader.py +161 -0
  327. package/dist/gaia-security/hooks/modules/core/__init__.py +40 -0
  328. package/dist/gaia-security/hooks/modules/core/hook_entry.py +78 -0
  329. package/dist/gaia-security/hooks/modules/core/paths.py +160 -0
  330. package/dist/gaia-security/hooks/modules/core/plugin_mode.py +149 -0
  331. package/dist/gaia-security/hooks/modules/core/plugin_setup.py +577 -0
  332. package/dist/gaia-security/hooks/modules/core/state.py +179 -0
  333. package/dist/gaia-security/hooks/modules/core/stdin.py +24 -0
  334. package/dist/gaia-security/hooks/modules/events/__init__.py +1 -0
  335. package/dist/gaia-security/hooks/modules/events/event_writer.py +210 -0
  336. package/dist/gaia-security/hooks/modules/memory/__init__.py +8 -0
  337. package/dist/gaia-security/hooks/modules/memory/episode_writer.py +216 -0
  338. package/dist/gaia-security/hooks/modules/orchestrator/__init__.py +1 -0
  339. package/dist/gaia-security/hooks/modules/orchestrator/delegate_mode.py +122 -0
  340. package/dist/gaia-security/hooks/modules/scanning/__init__.py +8 -0
  341. package/dist/gaia-security/hooks/modules/scanning/scan_trigger.py +84 -0
  342. package/dist/gaia-security/hooks/modules/security/__init__.py +120 -0
  343. package/dist/gaia-security/hooks/modules/security/approval_cleanup.py +87 -0
  344. package/dist/gaia-security/hooks/modules/security/approval_constants.py +23 -0
  345. package/dist/gaia-security/hooks/modules/security/approval_grants.py +1638 -0
  346. package/dist/gaia-security/hooks/modules/security/approval_messages.py +71 -0
  347. package/dist/gaia-security/hooks/modules/security/approval_scopes.py +222 -0
  348. package/dist/gaia-security/hooks/modules/security/blocked_commands.py +595 -0
  349. package/dist/gaia-security/hooks/modules/security/blocked_message_formatter.py +87 -0
  350. package/dist/gaia-security/hooks/modules/security/command_semantics.py +181 -0
  351. package/dist/gaia-security/hooks/modules/security/composition_rules.py +547 -0
  352. package/dist/gaia-security/hooks/modules/security/flag_classifiers.py +873 -0
  353. package/dist/gaia-security/hooks/modules/security/gitops_validator.py +179 -0
  354. package/dist/gaia-security/hooks/modules/security/mutative_verbs.py +1131 -0
  355. package/dist/gaia-security/hooks/modules/security/network_hosts.py +481 -0
  356. package/dist/gaia-security/hooks/modules/security/prompt_validator.py +40 -0
  357. package/dist/gaia-security/hooks/modules/security/shell_unwrapper.py +165 -0
  358. package/dist/gaia-security/hooks/modules/security/tiers.py +196 -0
  359. package/dist/gaia-security/hooks/modules/session/__init__.py +10 -0
  360. package/dist/gaia-security/hooks/modules/session/pending_scanner.py +174 -0
  361. package/dist/gaia-security/hooks/modules/session/session_context_writer.py +100 -0
  362. package/dist/gaia-security/hooks/modules/session/session_event_injector.py +160 -0
  363. package/dist/gaia-security/hooks/modules/session/session_manager.py +31 -0
  364. package/dist/gaia-security/hooks/modules/session/session_registry.py +232 -0
  365. package/dist/gaia-security/hooks/modules/tools/__init__.py +29 -0
  366. package/dist/gaia-security/hooks/modules/tools/bash_validator.py +1008 -0
  367. package/dist/gaia-security/hooks/modules/tools/cloud_pipe_validator.py +231 -0
  368. package/dist/gaia-security/hooks/modules/tools/hook_response.py +55 -0
  369. package/dist/gaia-security/hooks/modules/tools/shell_parser.py +227 -0
  370. package/dist/gaia-security/hooks/modules/tools/stage_decomposer.py +315 -0
  371. package/dist/gaia-security/hooks/modules/tools/task_validator.py +294 -0
  372. package/dist/gaia-security/hooks/modules/validation/__init__.py +23 -0
  373. package/dist/gaia-security/hooks/modules/validation/commit_validator.py +380 -0
  374. package/dist/gaia-security/hooks/post_tool_use.py +54 -0
  375. package/dist/gaia-security/hooks/pre_tool_use.py +413 -0
  376. package/dist/gaia-security/hooks/session_start.py +81 -0
  377. package/dist/gaia-security/hooks/stop_hook.py +82 -0
  378. package/dist/gaia-security/hooks/user_prompt_submit.py +246 -0
  379. package/dist/gaia-security/settings.json +58 -0
  380. package/git-hooks/commit-msg +41 -0
  381. package/hooks/README.md +100 -0
  382. package/hooks/adapters/__init__.py +52 -0
  383. package/hooks/adapters/base.py +219 -0
  384. package/hooks/adapters/channel.py +17 -0
  385. package/hooks/adapters/claude_code.py +1890 -0
  386. package/hooks/adapters/types.py +194 -0
  387. package/hooks/adapters/utils.py +25 -0
  388. package/hooks/elicitation_result.py +179 -0
  389. package/hooks/hooks.json +84 -0
  390. package/hooks/modules/README.md +189 -0
  391. package/hooks/modules/__init__.py +15 -0
  392. package/hooks/modules/agents/__init__.py +29 -0
  393. package/hooks/modules/agents/contract_validator.py +647 -0
  394. package/hooks/modules/agents/response_contract.py +496 -0
  395. package/hooks/modules/agents/skill_injection_verifier.py +120 -0
  396. package/hooks/modules/agents/state_tracker.py +267 -0
  397. package/hooks/modules/agents/task_info_builder.py +74 -0
  398. package/hooks/modules/agents/transcript_analyzer.py +458 -0
  399. package/hooks/modules/agents/transcript_reader.py +152 -0
  400. package/hooks/modules/audit/__init__.py +28 -0
  401. package/hooks/modules/audit/event_detector.py +168 -0
  402. package/hooks/modules/audit/logger.py +131 -0
  403. package/hooks/modules/audit/metrics.py +134 -0
  404. package/hooks/modules/audit/workflow_auditor.py +611 -0
  405. package/hooks/modules/audit/workflow_recorder.py +296 -0
  406. package/hooks/modules/context/__init__.py +11 -0
  407. package/hooks/modules/context/agentic_loop_detector.py +165 -0
  408. package/hooks/modules/context/anchor_tracker.py +317 -0
  409. package/hooks/modules/context/compact_context_builder.py +218 -0
  410. package/hooks/modules/context/context_freshness.py +145 -0
  411. package/hooks/modules/context/context_injector.py +558 -0
  412. package/hooks/modules/context/context_writer.py +530 -0
  413. package/hooks/modules/context/contracts_loader.py +161 -0
  414. package/hooks/modules/core/__init__.py +40 -0
  415. package/hooks/modules/core/hook_entry.py +78 -0
  416. package/hooks/modules/core/paths.py +160 -0
  417. package/hooks/modules/core/plugin_mode.py +149 -0
  418. package/hooks/modules/core/plugin_setup.py +577 -0
  419. package/hooks/modules/core/state.py +179 -0
  420. package/hooks/modules/core/stdin.py +24 -0
  421. package/hooks/modules/events/__init__.py +1 -0
  422. package/hooks/modules/events/event_writer.py +210 -0
  423. package/hooks/modules/evidence/__init__.py +34 -0
  424. package/hooks/modules/evidence/assertions.py +137 -0
  425. package/hooks/modules/evidence/index_writer.py +57 -0
  426. package/hooks/modules/evidence/loader.py +126 -0
  427. package/hooks/modules/evidence/runner.py +241 -0
  428. package/hooks/modules/memory/__init__.py +8 -0
  429. package/hooks/modules/memory/episode_writer.py +216 -0
  430. package/hooks/modules/orchestrator/__init__.py +1 -0
  431. package/hooks/modules/orchestrator/delegate_mode.py +122 -0
  432. package/hooks/modules/scanning/__init__.py +8 -0
  433. package/hooks/modules/scanning/scan_trigger.py +84 -0
  434. package/hooks/modules/security/__init__.py +120 -0
  435. package/hooks/modules/security/approval_cleanup.py +87 -0
  436. package/hooks/modules/security/approval_constants.py +23 -0
  437. package/hooks/modules/security/approval_grants.py +1638 -0
  438. package/hooks/modules/security/approval_messages.py +71 -0
  439. package/hooks/modules/security/approval_scopes.py +222 -0
  440. package/hooks/modules/security/blocked_commands.py +595 -0
  441. package/hooks/modules/security/blocked_message_formatter.py +87 -0
  442. package/hooks/modules/security/command_semantics.py +181 -0
  443. package/hooks/modules/security/composition_rules.py +547 -0
  444. package/hooks/modules/security/flag_classifiers.py +873 -0
  445. package/hooks/modules/security/gitops_validator.py +179 -0
  446. package/hooks/modules/security/mutative_verbs.py +1131 -0
  447. package/hooks/modules/security/network_hosts.py +481 -0
  448. package/hooks/modules/security/prompt_validator.py +40 -0
  449. package/hooks/modules/security/shell_unwrapper.py +165 -0
  450. package/hooks/modules/security/tiers.py +196 -0
  451. package/hooks/modules/session/__init__.py +10 -0
  452. package/hooks/modules/session/pending_scanner.py +174 -0
  453. package/hooks/modules/session/session_context_writer.py +100 -0
  454. package/hooks/modules/session/session_event_injector.py +160 -0
  455. package/hooks/modules/session/session_manager.py +31 -0
  456. package/hooks/modules/session/session_registry.py +232 -0
  457. package/hooks/modules/tools/__init__.py +29 -0
  458. package/hooks/modules/tools/bash_validator.py +1008 -0
  459. package/hooks/modules/tools/cloud_pipe_validator.py +231 -0
  460. package/hooks/modules/tools/hook_response.py +55 -0
  461. package/hooks/modules/tools/shell_parser.py +227 -0
  462. package/hooks/modules/tools/stage_decomposer.py +315 -0
  463. package/hooks/modules/tools/task_validator.py +294 -0
  464. package/hooks/modules/validation/__init__.py +23 -0
  465. package/hooks/modules/validation/commit_validator.py +380 -0
  466. package/hooks/post_compact.py +43 -0
  467. package/hooks/post_tool_use.py +54 -0
  468. package/hooks/pre_compact.py +60 -0
  469. package/hooks/pre_tool_use.py +413 -0
  470. package/hooks/session_start.py +81 -0
  471. package/hooks/stop_hook.py +82 -0
  472. package/hooks/subagent_start.py +71 -0
  473. package/hooks/subagent_stop.py +295 -0
  474. package/hooks/task_completed.py +70 -0
  475. package/hooks/user_prompt_submit.py +246 -0
  476. package/index.js +83 -0
  477. package/package.json +99 -0
  478. package/pyproject.toml +32 -0
  479. package/skills/README.md +154 -0
  480. package/skills/agent-protocol/SKILL.md +93 -0
  481. package/skills/agent-protocol/examples.md +223 -0
  482. package/skills/agent-response/SKILL.md +69 -0
  483. package/skills/agentic-loop/SKILL.md +80 -0
  484. package/skills/agentic-loop/reference.md +378 -0
  485. package/skills/blog-writing/SKILL.md +98 -0
  486. package/skills/blog-writing/reference.md +130 -0
  487. package/skills/brief-spec/SKILL.md +182 -0
  488. package/skills/command-execution/SKILL.md +64 -0
  489. package/skills/command-execution/reference.md +83 -0
  490. package/skills/context-updater/SKILL.md +87 -0
  491. package/skills/context-updater/examples.md +71 -0
  492. package/skills/developer-patterns/SKILL.md +50 -0
  493. package/skills/developer-patterns/reference.md +112 -0
  494. package/skills/execution/SKILL.md +99 -0
  495. package/skills/fast-queries/SKILL.md +43 -0
  496. package/skills/gaia-compact/SKILL.md +74 -0
  497. package/skills/gaia-patterns/SKILL.md +108 -0
  498. package/skills/gaia-patterns/reference.md +395 -0
  499. package/skills/gaia-planner/SKILL.md +37 -0
  500. package/skills/gaia-planner/reference.md +107 -0
  501. package/skills/gaia-release/SKILL.md +82 -0
  502. package/skills/gaia-release/reference.md +102 -0
  503. package/skills/gaia-self-check/SKILL.md +114 -0
  504. package/skills/gaia-self-check/reference.md +453 -0
  505. package/skills/gaia-verify/SKILL.md +77 -0
  506. package/skills/gaia-verify/reference.md +80 -0
  507. package/skills/git-conventions/SKILL.md +47 -0
  508. package/skills/gitops-patterns/SKILL.md +60 -0
  509. package/skills/gitops-patterns/reference.md +183 -0
  510. package/skills/gmail-policy/SKILL.md +200 -0
  511. package/skills/gmail-policy/reference.md +150 -0
  512. package/skills/gmail-triage/SKILL.md +100 -0
  513. package/skills/gws-setup/SKILL.md +99 -0
  514. package/skills/gws-setup/reference.md +73 -0
  515. package/skills/investigation/SKILL.md +100 -0
  516. package/skills/memory-curation/SKILL.md +83 -0
  517. package/skills/memory-search/SKILL.md +88 -0
  518. package/skills/orchestrator-approval/SKILL.md +160 -0
  519. package/skills/orchestrator-approval/reference.md +174 -0
  520. package/skills/pending-approvals/SKILL.md +72 -0
  521. package/skills/pending-approvals/reference.md +214 -0
  522. package/skills/readme-writing/SKILL.md +71 -0
  523. package/skills/readme-writing/reference.md +188 -0
  524. package/skills/reference.md +135 -0
  525. package/skills/request-approval/SKILL.md +140 -0
  526. package/skills/request-approval/examples.md +140 -0
  527. package/skills/request-approval/reference.md +57 -0
  528. package/skills/schedule-task/SKILL.md +64 -0
  529. package/skills/schedule-task/reference.md +233 -0
  530. package/skills/security-tiers/SKILL.md +141 -0
  531. package/skills/security-tiers/destructive-commands-reference.md +623 -0
  532. package/skills/security-tiers/reference.md +39 -0
  533. package/skills/skill-creation/SKILL.md +92 -0
  534. package/skills/skill-creation/reference.md +29 -0
  535. package/skills/terraform-patterns/SKILL.md +89 -0
  536. package/skills/terraform-patterns/reference.md +93 -0
  537. package/templates/README.md +69 -0
  538. package/templates/managed-settings.template.json +43 -0
  539. package/tools/__init__.py +9 -0
  540. package/tools/agentic-loop/decide-status.py +210 -0
  541. package/tools/agentic-loop/parse-metric.py +106 -0
  542. package/tools/agentic-loop/record-iteration.py +221 -0
  543. package/tools/context/README.md +132 -0
  544. package/tools/context/__init__.py +42 -0
  545. package/tools/context/_paths.py +20 -0
  546. package/tools/context/context_provider.py +721 -0
  547. package/tools/context/context_section_reader.py +342 -0
  548. package/tools/context/deep_merge.py +159 -0
  549. package/tools/context/pending_updates.py +760 -0
  550. package/tools/context/surface_router.py +278 -0
  551. package/tools/fast-queries/README.md +65 -0
  552. package/tools/fast-queries/__init__.py +30 -0
  553. package/tools/fast-queries/appservices/quicktriage_devops_developer.sh +75 -0
  554. package/tools/fast-queries/cloud/aws/quicktriage_aws_troubleshooter.sh +32 -0
  555. package/tools/fast-queries/cloud/gcp/quicktriage_gcp_troubleshooter.sh +88 -0
  556. package/tools/fast-queries/gitops/quicktriage_gitops_operator.sh +48 -0
  557. package/tools/fast-queries/run_triage.sh +59 -0
  558. package/tools/fast-queries/terraform/quicktriage_terraform_architect.sh +80 -0
  559. package/tools/gaia_simulator/__init__.py +33 -0
  560. package/tools/gaia_simulator/cli.py +354 -0
  561. package/tools/gaia_simulator/extractor.py +457 -0
  562. package/tools/gaia_simulator/reporter.py +258 -0
  563. package/tools/gaia_simulator/routing_simulator.py +334 -0
  564. package/tools/gaia_simulator/runner.py +539 -0
  565. package/tools/gaia_simulator/skills_mapper.py +264 -0
  566. package/tools/memory/README.md +0 -0
  567. package/tools/memory/__init__.py +20 -0
  568. package/tools/memory/backfill_fts5.py +107 -0
  569. package/tools/memory/conflict_detector.py +295 -0
  570. package/tools/memory/episodic.py +1210 -0
  571. package/tools/memory/git_invalidator.py +262 -0
  572. package/tools/memory/paths.py +102 -0
  573. package/tools/memory/scoring.py +193 -0
  574. package/tools/memory/search_store.py +360 -0
  575. package/tools/persist_transcript_analysis.py +85 -0
  576. package/tools/review/__init__.py +1 -0
  577. package/tools/review/review_engine.py +157 -0
  578. package/tools/scan/__init__.py +35 -0
  579. package/tools/scan/config.py +247 -0
  580. package/tools/scan/merge.py +212 -0
  581. package/tools/scan/orchestrator.py +549 -0
  582. package/tools/scan/registry.py +127 -0
  583. package/tools/scan/scanners/__init__.py +18 -0
  584. package/tools/scan/scanners/base.py +137 -0
  585. package/tools/scan/scanners/environment.py +349 -0
  586. package/tools/scan/scanners/git.py +570 -0
  587. package/tools/scan/scanners/infrastructure.py +875 -0
  588. package/tools/scan/scanners/orchestration.py +600 -0
  589. package/tools/scan/scanners/stack.py +1085 -0
  590. package/tools/scan/scanners/tools.py +260 -0
  591. package/tools/scan/setup.py +686 -0
  592. package/tools/scan/tests/__init__.py +1 -0
  593. package/tools/scan/tests/conftest.py +796 -0
  594. package/tools/scan/tests/test_environment.py +323 -0
  595. package/tools/scan/tests/test_git.py +419 -0
  596. package/tools/scan/tests/test_infrastructure.py +382 -0
  597. package/tools/scan/tests/test_integration.py +920 -0
  598. package/tools/scan/tests/test_merge.py +269 -0
  599. package/tools/scan/tests/test_orchestration.py +304 -0
  600. package/tools/scan/tests/test_stack.py +604 -0
  601. package/tools/scan/tests/test_tools.py +349 -0
  602. package/tools/scan/ui.py +624 -0
  603. package/tools/scan/verify.py +270 -0
  604. package/tools/scan/walk.py +118 -0
  605. package/tools/scan/workspace.py +85 -0
  606. package/tools/validation/README.md +244 -0
  607. package/tools/validation/__init__.py +17 -0
  608. package/tools/validation/approval_gate.py +321 -0
  609. package/tools/validation/validate_skills.py +189 -0
@@ -0,0 +1,179 @@
1
+ """
2
+ Hook state management - Share state between pre and post hooks.
3
+
4
+ Uses a temporary file to pass information from pre_tool_use to post_tool_use,
5
+ since they run in separate processes.
6
+ """
7
+
8
+ import os
9
+ import json
10
+ import logging
11
+ import time
12
+ from pathlib import Path
13
+ from datetime import datetime
14
+ from typing import Dict, Any, Optional
15
+ from dataclasses import dataclass, asdict, field
16
+
17
+ from .paths import find_claude_dir
18
+
19
+ logger = logging.getLogger(__name__)
20
+
21
+ # State file location
22
+ STATE_FILE_NAME = ".hooks_state.json"
23
+
24
+
25
+ def get_session_id() -> str:
26
+ """Return the current Claude session ID, defaulting to 'default'."""
27
+ return os.environ.get("CLAUDE_SESSION_ID", "default")
28
+
29
+
30
+ @dataclass
31
+ class HookState:
32
+ """
33
+ State passed from pre-hook to post-hook.
34
+
35
+ Attributes:
36
+ tool_name: Name of the tool being executed
37
+ command: Command being executed (for Bash)
38
+ tier: Security tier assigned by pre-hook
39
+ start_time: ISO timestamp when pre-hook ran
40
+ session_id: Current session identifier
41
+ pre_hook_result: Result from pre-hook validation
42
+ metadata: Additional context data
43
+ """
44
+ tool_name: str = ""
45
+ command: str = ""
46
+ tier: str = "unknown"
47
+ start_time: str = ""
48
+ start_time_epoch: float = 0.0
49
+ session_id: str = ""
50
+ pre_hook_result: str = "allowed"
51
+ metadata: Dict[str, Any] = field(default_factory=dict)
52
+
53
+ def to_dict(self) -> Dict[str, Any]:
54
+ """Convert to dictionary."""
55
+ return asdict(self)
56
+
57
+ @classmethod
58
+ def from_dict(cls, data: Dict[str, Any]) -> "HookState":
59
+ """Create from dictionary."""
60
+ return cls(
61
+ tool_name=data.get("tool_name", ""),
62
+ command=data.get("command", ""),
63
+ tier=data.get("tier", "unknown"),
64
+ start_time=data.get("start_time", ""),
65
+ start_time_epoch=float(data.get("start_time_epoch", 0.0)),
66
+ session_id=data.get("session_id", ""),
67
+ pre_hook_result=data.get("pre_hook_result", "allowed"),
68
+ metadata=data.get("metadata", {}),
69
+ )
70
+
71
+
72
+ def _get_state_file_path() -> Path:
73
+ """Get path to state file."""
74
+ claude_dir = find_claude_dir()
75
+ return claude_dir / STATE_FILE_NAME
76
+
77
+
78
+ def save_hook_state(state: HookState) -> bool:
79
+ """
80
+ Save hook state for post-hook to read.
81
+
82
+ Args:
83
+ state: HookState to save
84
+
85
+ Returns:
86
+ True if saved successfully
87
+ """
88
+ try:
89
+ state_file = _get_state_file_path()
90
+ state_file.parent.mkdir(parents=True, exist_ok=True)
91
+
92
+ with open(state_file, "w") as f:
93
+ json.dump(state.to_dict(), f)
94
+
95
+ logger.debug(f"Saved hook state: {state.tool_name} / {state.tier}")
96
+ return True
97
+
98
+ except Exception as e:
99
+ logger.warning(f"Could not save hook state: {e}")
100
+ return False
101
+
102
+
103
+ def get_hook_state() -> Optional[HookState]:
104
+ """
105
+ Get hook state saved by pre-hook.
106
+
107
+ Returns:
108
+ HookState if found, None otherwise
109
+ """
110
+ try:
111
+ state_file = _get_state_file_path()
112
+
113
+ if not state_file.exists():
114
+ logger.debug("No hook state file found")
115
+ return None
116
+
117
+ with open(state_file, "r") as f:
118
+ data = json.load(f)
119
+
120
+ return HookState.from_dict(data)
121
+
122
+ except Exception as e:
123
+ logger.warning(f"Could not read hook state: {e}")
124
+ return None
125
+
126
+
127
+ def clear_hook_state() -> bool:
128
+ """
129
+ Clear hook state after post-hook has processed it.
130
+
131
+ Returns:
132
+ True if cleared successfully
133
+ """
134
+ try:
135
+ state_file = _get_state_file_path()
136
+
137
+ if state_file.exists():
138
+ state_file.unlink()
139
+ logger.debug("Cleared hook state")
140
+
141
+ return True
142
+
143
+ except Exception as e:
144
+ logger.warning(f"Could not clear hook state: {e}")
145
+ return False
146
+
147
+
148
+ def create_pre_hook_state(
149
+ tool_name: str,
150
+ command: str = "",
151
+ tier: str = "unknown",
152
+ **metadata
153
+ ) -> HookState:
154
+ """
155
+ Create a new hook state for pre-hook.
156
+
157
+ Convenience function that sets common fields automatically.
158
+
159
+ Args:
160
+ tool_name: Name of the tool
161
+ command: Command being executed
162
+ tier: Security tier
163
+ **metadata: Additional metadata
164
+
165
+ Returns:
166
+ New HookState instance
167
+ """
168
+ session_id = get_session_id()
169
+
170
+ return HookState(
171
+ tool_name=tool_name,
172
+ command=command,
173
+ tier=tier,
174
+ start_time=datetime.now().isoformat(),
175
+ start_time_epoch=time.time(),
176
+ session_id=session_id,
177
+ pre_hook_result="allowed",
178
+ metadata=metadata,
179
+ )
@@ -0,0 +1,24 @@
1
+ """
2
+ Stdin availability check for hook entrypoints.
3
+
4
+ Provides a single ``has_stdin_data()`` helper that determines whether the
5
+ current process has data available on stdin. This replaces the duplicate
6
+ implementations that previously lived in ``adapters.utils``.
7
+ """
8
+
9
+ import logging
10
+ import select
11
+ import sys
12
+
13
+ logger = logging.getLogger(__name__)
14
+
15
+
16
+ def has_stdin_data() -> bool:
17
+ """Check if there is data available on stdin."""
18
+ if sys.stdin.isatty():
19
+ return False
20
+ try:
21
+ readable, _, _ = select.select([sys.stdin], [], [], 0)
22
+ return bool(readable)
23
+ except Exception:
24
+ return not sys.stdin.isatty()
@@ -0,0 +1 @@
1
+ """Event context system for cross-session operational event logging."""
@@ -0,0 +1,210 @@
1
+ """Event writer and reader for the GAIA Event Context system.
2
+
3
+ Provides:
4
+ - EventWriter: append-only JSONL writer with file locking
5
+ - read_events(): read events from last N hours with optional filtering
6
+ - cleanup_old_events(): remove events older than N days
7
+ - Event type constants
8
+ """
9
+
10
+ import fcntl
11
+ import json
12
+ import logging
13
+ import os
14
+ from datetime import datetime, timedelta, timezone
15
+ from pathlib import Path
16
+ from typing import Any, Dict, List, Optional
17
+
18
+ from ..core.paths import get_events_dir
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+ # ---------------------------------------------------------------------------
23
+ # Event type constants
24
+ # ---------------------------------------------------------------------------
25
+
26
+ AGENT_DISPATCH = "agent.dispatch"
27
+ AGENT_COMPLETE = "agent.complete"
28
+ COMMAND_EXECUTED = "command.executed"
29
+ SESSION_END = "session.end"
30
+ TRIGGER_SCHEDULED = "trigger.scheduled"
31
+ HEARTBEAT = "heartbeat"
32
+ USER_NOTE = "user.note"
33
+
34
+
35
+ class EventWriter:
36
+ """Append-only JSONL event writer with file locking.
37
+
38
+ All writes are wrapped in try/except -- events are non-critical and
39
+ must never block the hook pipeline.
40
+ """
41
+
42
+ def __init__(self, events_dir: Optional[Path] = None):
43
+ self.events_dir = events_dir or get_events_dir()
44
+ self.events_file = self.events_dir / "events.jsonl"
45
+ self.lock_file = self.events_dir / "events.jsonl.lock"
46
+
47
+ def write_event(
48
+ self,
49
+ event_type: str,
50
+ source: str,
51
+ agent: str,
52
+ result: str,
53
+ severity: str = "info",
54
+ meta: Optional[Dict[str, Any]] = None,
55
+ ) -> None:
56
+ """Append a single event to the JSONL log.
57
+
58
+ Thread-safe via exclusive file lock. Fails silently on any error
59
+ to avoid disrupting the hook pipeline.
60
+
61
+ Args:
62
+ event_type: Dotted event category (e.g. "agent.dispatch").
63
+ source: Who wrote the event (e.g. "hook").
64
+ agent: Agent involved, or empty string for non-agent events.
65
+ result: Outcome summary string.
66
+ severity: info | warning | error.
67
+ meta: Optional type-specific structured data.
68
+ """
69
+ try:
70
+ self.events_dir.mkdir(parents=True, exist_ok=True)
71
+
72
+ record: Dict[str, Any] = {
73
+ "ts": datetime.now(timezone.utc).isoformat(),
74
+ "type": event_type,
75
+ "source": source,
76
+ "agent": agent,
77
+ "result": result,
78
+ "severity": severity,
79
+ }
80
+ if meta:
81
+ record["meta"] = meta
82
+
83
+ with open(self.lock_file, "w") as lf:
84
+ fcntl.flock(lf.fileno(), fcntl.LOCK_EX)
85
+ try:
86
+ with open(self.events_file, "a") as f:
87
+ f.write(json.dumps(record, separators=(",", ":")) + "\n")
88
+ finally:
89
+ fcntl.flock(lf.fileno(), fcntl.LOCK_UN)
90
+
91
+ except Exception as exc:
92
+ logger.debug("Event write failed (non-fatal): %s", exc)
93
+
94
+
95
+ def read_events(
96
+ hours: int = 24,
97
+ event_type: Optional[str] = None,
98
+ limit: int = 50,
99
+ events_dir: Optional[Path] = None,
100
+ ) -> List[Dict[str, Any]]:
101
+ """Read recent events from the JSONL log.
102
+
103
+ Args:
104
+ hours: How far back to look (default 24h).
105
+ event_type: Optional filter by event type (exact match).
106
+ limit: Maximum number of events to return.
107
+ events_dir: Override events directory (for testing).
108
+
109
+ Returns:
110
+ List of event dicts, most recent last, capped at *limit*.
111
+ """
112
+ try:
113
+ edir = events_dir or get_events_dir()
114
+ events_file = edir / "events.jsonl"
115
+ if not events_file.exists():
116
+ return []
117
+
118
+ cutoff = datetime.now(timezone.utc) - timedelta(hours=hours)
119
+ results: List[Dict[str, Any]] = []
120
+
121
+ with open(events_file, "r") as f:
122
+ for line in f:
123
+ line = line.strip()
124
+ if not line:
125
+ continue
126
+ try:
127
+ evt = json.loads(line)
128
+ except json.JSONDecodeError:
129
+ continue
130
+
131
+ # Time filter
132
+ try:
133
+ ts = datetime.fromisoformat(evt.get("ts", ""))
134
+ if ts < cutoff:
135
+ continue
136
+ except (ValueError, TypeError):
137
+ continue
138
+
139
+ # Type filter
140
+ if event_type and evt.get("type") != event_type:
141
+ continue
142
+
143
+ results.append(evt)
144
+
145
+ # Return the most recent events, capped at limit
146
+ return results[-limit:]
147
+
148
+ except Exception as exc:
149
+ logger.debug("Event read failed (non-fatal): %s", exc)
150
+ return []
151
+
152
+
153
+ def cleanup_old_events(
154
+ days: int = 7,
155
+ events_dir: Optional[Path] = None,
156
+ ) -> int:
157
+ """Remove events older than *days* from the JSONL log.
158
+
159
+ Uses file locking to avoid conflicts with concurrent writers.
160
+ Retains lines that cannot be parsed (conservative).
161
+
162
+ Args:
163
+ days: Retention window in days (default 7).
164
+ events_dir: Override events directory (for testing).
165
+
166
+ Returns:
167
+ Number of events removed.
168
+ """
169
+ try:
170
+ edir = events_dir or get_events_dir()
171
+ events_file = edir / "events.jsonl"
172
+ lock_file = edir / "events.jsonl.lock"
173
+
174
+ if not events_file.exists():
175
+ return 0
176
+
177
+ retention_days = int(os.environ.get("GAIA_EVENT_RETENTION_DAYS", str(days)))
178
+ cutoff = datetime.now(timezone.utc) - timedelta(days=retention_days)
179
+ kept: List[str] = []
180
+ removed = 0
181
+
182
+ with open(lock_file, "w") as lf:
183
+ fcntl.flock(lf.fileno(), fcntl.LOCK_EX)
184
+ try:
185
+ with open(events_file, "r") as f:
186
+ for line in f:
187
+ line = line.strip()
188
+ if not line:
189
+ continue
190
+ try:
191
+ evt = json.loads(line)
192
+ ts = datetime.fromisoformat(evt["ts"])
193
+ if ts < cutoff:
194
+ removed += 1
195
+ continue
196
+ except (json.JSONDecodeError, KeyError, ValueError):
197
+ pass # Keep unparseable lines
198
+ kept.append(line)
199
+
200
+ with open(events_file, "w") as f:
201
+ for line in kept:
202
+ f.write(line + "\n")
203
+ finally:
204
+ fcntl.flock(lf.fileno(), fcntl.LOCK_UN)
205
+
206
+ return removed
207
+
208
+ except Exception as exc:
209
+ logger.debug("Event cleanup failed (non-fatal): %s", exc)
210
+ return 0
@@ -0,0 +1,8 @@
1
+ """
2
+ Memory module - Episodic memory capture for workflow episodes.
3
+
4
+ Provides:
5
+ - episode_writer: Workflow episode storage + session events (replaces episode_capture + session_state)
6
+ """
7
+
8
+ __all__ = []
@@ -0,0 +1,216 @@
1
+ """
2
+ Episodic memory capture for workflow episodes.
3
+
4
+ Renamed from episode_capture.py. Absorbs get_session_events() from
5
+ session_state.py directly into this module.
6
+
7
+ Provides:
8
+ - write(): Store workflow as episodic memory
9
+ - get_session_events(): Read context.json, categorize events
10
+ """
11
+
12
+ import json
13
+ import logging
14
+ from pathlib import Path
15
+ from typing import Any, Dict, List, Optional
16
+
17
+ logger = logging.getLogger(__name__)
18
+
19
+
20
+ # ============================================================================
21
+ # Session events (absorbed from session_state.py)
22
+ # ============================================================================
23
+
24
+ def get_session_events() -> Dict[str, Any]:
25
+ """
26
+ Get critical events from active session context.
27
+
28
+ Returns:
29
+ Dict with categorized session events (commits, pushes, file_mods)
30
+ """
31
+ context_path = Path(".claude/session/active/context.json")
32
+
33
+ if not context_path.exists():
34
+ logger.debug("No session context found")
35
+ return {}
36
+
37
+ try:
38
+ with open(context_path, "r") as f:
39
+ context = json.load(f)
40
+
41
+ critical_events = context.get("critical_events", [])
42
+
43
+ if not critical_events:
44
+ return {}
45
+
46
+ commits = [
47
+ {
48
+ "hash": e.get("commit_hash", ""),
49
+ "message": e.get("commit_message", ""),
50
+ "timestamp": e.get("timestamp", "")
51
+ }
52
+ for e in critical_events
53
+ if e.get("event_type") == "git_commit" and e.get("commit_hash")
54
+ ]
55
+
56
+ pushes = [
57
+ {
58
+ "branch": e.get("branch", ""),
59
+ "timestamp": e.get("timestamp", "")
60
+ }
61
+ for e in critical_events
62
+ if e.get("event_type") == "git_push" and e.get("branch")
63
+ ]
64
+
65
+ file_mods = [
66
+ {
67
+ "count": e.get("modification_count", 0),
68
+ "timestamp": e.get("timestamp", "")
69
+ }
70
+ for e in critical_events
71
+ if e.get("event_type") == "file_modifications"
72
+ ]
73
+
74
+ result = {}
75
+ if commits:
76
+ result["git_commits"] = commits
77
+ if pushes:
78
+ result["git_pushes"] = pushes
79
+ if file_mods:
80
+ result["file_modifications"] = file_mods
81
+
82
+ if result:
83
+ logger.info(f"Found {len(critical_events)} session events")
84
+
85
+ return result
86
+
87
+ except Exception as e:
88
+ logger.warning(f"Failed to read session events: {e}")
89
+ return {}
90
+
91
+
92
+ # ============================================================================
93
+ # Episodic memory capture
94
+ # ============================================================================
95
+
96
+ def write(
97
+ metrics: Dict[str, Any],
98
+ anomalies: Optional[List[Dict[str, str]]] = None,
99
+ commands_executed: Optional[List[str]] = None,
100
+ ) -> Optional[str]:
101
+ """
102
+ Capture workflow as episodic memory.
103
+
104
+ Args:
105
+ metrics: Subagent metrics from workflow (includes plan_status, tier, task description)
106
+ anomalies: Detected anomalies from audit(), stored in episode context
107
+ commands_executed: List of commands extracted from EVIDENCE_REPORT
108
+
109
+ Returns:
110
+ Episode ID if stored, None otherwise
111
+ """
112
+ try:
113
+ import importlib.util
114
+
115
+ candidates = [
116
+ Path(__file__).parent.parent.parent.parent / "tools" / "memory" / "episodic.py",
117
+ Path(".claude/tools/memory/episodic.py"),
118
+ ]
119
+
120
+ episodic_module = None
121
+ for path in candidates:
122
+ if path.exists():
123
+ try:
124
+ spec = importlib.util.spec_from_file_location("episodic", path)
125
+ if spec and spec.loader:
126
+ episodic_module = importlib.util.module_from_spec(spec)
127
+ spec.loader.exec_module(episodic_module)
128
+ logger.debug(f"Loaded episodic module from {path}")
129
+ break
130
+ except Exception as e:
131
+ logger.debug(f"Could not load episodic from {path}: {e}")
132
+ continue
133
+
134
+ if not episodic_module:
135
+ logger.debug("Episodic memory module not found - skipping episode capture")
136
+ return None
137
+
138
+ memory = episodic_module.EpisodicMemory()
139
+
140
+ # Use the real task description captured from the transcript.
141
+ # metrics["prompt"] now holds the first user message (task description)
142
+ # rather than the generic "SubagentStop for <agent>".
143
+ prompt = metrics.get("prompt", "")
144
+ if not prompt:
145
+ prompt = f"Task for {metrics.get('agent', 'unknown')}"
146
+
147
+ subagent_type = metrics.get("agent", "unknown")
148
+ duration_seconds = metrics.get("duration_ms", 0) / 1000.0 if metrics.get("duration_ms") else None
149
+
150
+ # Determine outcome: prefer plan_status string, fall back to exit_code
151
+ plan_status = metrics.get("plan_status", "")
152
+ exit_code = metrics.get("exit_code", 0)
153
+ if plan_status:
154
+ if "COMPLETE" in plan_status:
155
+ outcome = "success"
156
+ success = True
157
+ elif "BLOCKED" in plan_status or "ERROR" in plan_status:
158
+ outcome = "failed"
159
+ success = False
160
+ else:
161
+ # IN_PROGRESS, REVIEW, NEEDS_INPUT -> partial
162
+ outcome = "partial"
163
+ success = None
164
+ elif exit_code == 0:
165
+ outcome = "success"
166
+ success = True
167
+ else:
168
+ outcome = "failed"
169
+ success = False
170
+
171
+ # Tags from metrics -- filter empty strings defensively
172
+ tags = [t for t in metrics.get("tags", []) if t]
173
+ if not tags and subagent_type and subagent_type != "unknown":
174
+ tags = [subagent_type]
175
+
176
+ # Enrich with session events and anomalies
177
+ session_events = get_session_events()
178
+ context = {"metrics": metrics}
179
+ if session_events:
180
+ context["session_events"] = session_events
181
+ logger.info(f"Enriched episode with session events: {list(session_events.keys())}")
182
+ if anomalies:
183
+ context["anomalies"] = anomalies
184
+ logger.info(f"Episode has {len(anomalies)} anomaly/anomalies")
185
+
186
+ # Include context anchor hit tracking if available
187
+ anchor_hits = metrics.get("context_anchor_hits")
188
+ if anchor_hits:
189
+ context["context_anchor_hits"] = anchor_hits
190
+ logger.info(
191
+ "Episode anchor hits: %d/%d (%.0f%%)",
192
+ anchor_hits.get("hits", 0),
193
+ anchor_hits.get("total_checked", 0),
194
+ anchor_hits.get("hit_rate", 0) * 100,
195
+ )
196
+
197
+ # P3 CLI compatibility fields
198
+ episode_id = memory.store_episode(
199
+ prompt=prompt,
200
+ clarifications={},
201
+ enriched_prompt=prompt,
202
+ context=context,
203
+ tags=tags,
204
+ outcome=outcome,
205
+ success=success,
206
+ duration_seconds=duration_seconds,
207
+ commands_executed=commands_executed or [],
208
+ workflow_metrics=metrics,
209
+ )
210
+
211
+ logger.info(f"Captured episode: {episode_id} (outcome: {outcome}, plan_status: {plan_status})")
212
+ return episode_id
213
+
214
+ except Exception as e:
215
+ logger.debug(f"Failed to capture episodic memory: {e}")
216
+ return None
@@ -0,0 +1 @@
1
+ # Orchestrator enforcement modules.