@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
package/bin/gaia ADDED
@@ -0,0 +1,112 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ gaia -- Unified Gaia-Ops CLI
4
+
5
+ Entry point that discovers subcommand plugins from bin/cli/ and dispatches
6
+ to the matching handler. Zero external dependencies (stdlib only).
7
+
8
+ Usage:
9
+ python bin/gaia <subcommand> [options]
10
+ python bin/gaia --help
11
+ python bin/gaia status [--json]
12
+ python bin/gaia doctor [--json] [--fix]
13
+ """
14
+
15
+ import argparse
16
+ import importlib
17
+ import importlib.util
18
+ import sys
19
+ from pathlib import Path
20
+
21
+ # Ensure the package root is on sys.path so submodules resolve correctly.
22
+ _SCRIPT_DIR = Path(__file__).resolve().parent
23
+ _PACKAGE_ROOT = _SCRIPT_DIR.parent
24
+ if str(_PACKAGE_ROOT) not in sys.path:
25
+ sys.path.insert(0, str(_PACKAGE_ROOT))
26
+ # Also ensure bin/ is on the path so bin/cli/ resolves as a package.
27
+ if str(_SCRIPT_DIR) not in sys.path:
28
+ sys.path.insert(0, str(_SCRIPT_DIR))
29
+
30
+ _CLI_DIR = _SCRIPT_DIR / "cli"
31
+
32
+
33
+ def _discover_plugins():
34
+ """Return a sorted list of (module_name, module) for all bin/cli/*.py plugins."""
35
+ plugins = []
36
+ if not _CLI_DIR.is_dir():
37
+ return plugins
38
+
39
+ for path in sorted(_CLI_DIR.glob("*.py")):
40
+ if path.stem == "__init__":
41
+ continue
42
+ spec = importlib.util.spec_from_file_location(f"cli.{path.stem}", path)
43
+ if spec is None:
44
+ continue
45
+ try:
46
+ mod = importlib.util.module_from_spec(spec)
47
+ spec.loader.exec_module(mod)
48
+ plugins.append((path.stem, mod))
49
+ except Exception as exc: # noqa: BLE001
50
+ print(f"Warning: could not load plugin {path.name}: {exc}", file=sys.stderr)
51
+
52
+ return plugins
53
+
54
+
55
+ def main(argv=None):
56
+ """CLI entry point. Returns exit code."""
57
+ parser = argparse.ArgumentParser(
58
+ prog="gaia",
59
+ description="Gaia-Ops unified CLI -- manage and inspect your Gaia installation.",
60
+ formatter_class=argparse.RawDescriptionHelpFormatter,
61
+ )
62
+ parser.add_argument(
63
+ "--json",
64
+ action="store_true",
65
+ default=False,
66
+ help="Output results as JSON (machine-readable)",
67
+ )
68
+ parser.add_argument(
69
+ "--version",
70
+ action="store_true",
71
+ default=False,
72
+ help="Print version and exit",
73
+ )
74
+
75
+ subparsers = parser.add_subparsers(dest="subcommand", metavar="<subcommand>")
76
+
77
+ # Discover and register plugins
78
+ plugins = _discover_plugins()
79
+ for _name, mod in plugins:
80
+ if hasattr(mod, "register"):
81
+ mod.register(subparsers)
82
+
83
+ args = parser.parse_args(argv)
84
+
85
+ if args.version:
86
+ # Print version from package.json
87
+ try:
88
+ import json
89
+ pkg = _PACKAGE_ROOT / "package.json"
90
+ version = json.loads(pkg.read_text())["version"]
91
+ print(f"gaia {version}")
92
+ except Exception:
93
+ print("gaia (version unknown)")
94
+ return 0
95
+
96
+ if args.subcommand is None:
97
+ parser.print_help()
98
+ return 0
99
+
100
+ # Dispatch to the matching plugin handler
101
+ for name, mod in plugins:
102
+ if name == args.subcommand and hasattr(mod, f"cmd_{name}"):
103
+ handler = getattr(mod, f"cmd_{name}")
104
+ return handler(args) or 0
105
+
106
+ # Subcommand registered but handler not found -- should not happen
107
+ print(f"gaia: unknown subcommand '{args.subcommand}'", file=sys.stderr)
108
+ return 1
109
+
110
+
111
+ if __name__ == "__main__":
112
+ sys.exit(main())
@@ -0,0 +1,531 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * @jaguilar87/gaia - Cleanup script
5
+ *
6
+ * Purpose:
7
+ * - Remove CLAUDE.md
8
+ * - Remove settings.json
9
+ * - Remove all symlinks (agents, tools, hooks, commands, config, templates, CHANGELOG.md)
10
+ * - Preserve project-specific data (logs, tests, project-context, session, metrics)
11
+ *
12
+ * Usage:
13
+ * Manual: npx gaia-cleanup
14
+ * Automatic: Runs via preuninstall hook when uninstalling from npm registry
15
+ *
16
+ * IMPORTANT FOR LOCAL DEVELOPMENT:
17
+ * When testing with local installs (npm install ./gaia-ops), the preuninstall hook
18
+ * will NOT execute automatically due to npm's file: protocol behavior.
19
+ * You must run 'npx gaia-cleanup' manually before uninstalling:
20
+ *
21
+ * npx gaia-cleanup && npm uninstall @jaguilar87/gaia
22
+ *
23
+ * When installed from npm registry, cleanup happens automatically on uninstall.
24
+ */
25
+
26
+ import { join, dirname, resolve } from 'path';
27
+ import fs from 'fs/promises';
28
+ import { existsSync, lstatSync, statSync, readdirSync } from 'fs';
29
+ import chalk from 'chalk';
30
+ import ora from 'ora';
31
+
32
+ /**
33
+ * Find the project root directory by looking for .claude/ directory
34
+ * Searches upward from the current working directory
35
+ */
36
+ function findProjectRoot() {
37
+ // First try INIT_CWD (available during npm install/uninstall)
38
+ if (process.env.INIT_CWD) {
39
+ const claudeDir = join(process.env.INIT_CWD, '.claude');
40
+ if (existsSync(claudeDir)) {
41
+ return process.env.INIT_CWD;
42
+ }
43
+ }
44
+
45
+ // Search upward from current directory
46
+ let currentDir = process.cwd();
47
+ const root = resolve('/');
48
+
49
+ while (currentDir !== root) {
50
+ const claudeDir = join(currentDir, '.claude');
51
+ if (existsSync(claudeDir)) {
52
+ return currentDir;
53
+ }
54
+ currentDir = dirname(currentDir);
55
+ }
56
+
57
+ // Fallback to current directory
58
+ return process.env.INIT_CWD || process.cwd();
59
+ }
60
+
61
+ const CWD = findProjectRoot();
62
+
63
+ /**
64
+ * Remove legacy CLAUDE.md if it exists (identity now injected by hook).
65
+ */
66
+ async function removeClaudeMd() {
67
+ const spinner = ora('Removing CLAUDE.md...').start();
68
+
69
+ try {
70
+ const claudeMdPath = join(CWD, 'CLAUDE.md');
71
+
72
+ if (!existsSync(claudeMdPath)) {
73
+ spinner.info('CLAUDE.md not found, skipping');
74
+ return false;
75
+ }
76
+
77
+ await fs.unlink(claudeMdPath);
78
+ spinner.succeed('CLAUDE.md removed');
79
+ return true;
80
+ } catch (error) {
81
+ spinner.fail(`Failed to remove CLAUDE.md: ${error.message}`);
82
+ return false;
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Remove settings.json if it exists
88
+ */
89
+ async function removeSettingsJson() {
90
+ const spinner = ora('Removing settings.json...').start();
91
+
92
+ try {
93
+ const settingsPath = join(CWD, '.claude', 'settings.json');
94
+
95
+ if (!existsSync(settingsPath)) {
96
+ spinner.info('settings.json not found, skipping');
97
+ return false;
98
+ }
99
+
100
+ await fs.unlink(settingsPath);
101
+ spinner.succeed('settings.json removed');
102
+ return true;
103
+ } catch (error) {
104
+ spinner.fail(`Failed to remove settings.json: ${error.message}`);
105
+ return false;
106
+ }
107
+ }
108
+
109
+ /**
110
+ * Remove all symlinks in .claude/ directory
111
+ */
112
+ async function removeSymlinks() {
113
+ const spinner = ora('Removing symlinks...').start();
114
+
115
+ try {
116
+ const claudeDir = join(CWD, '.claude');
117
+
118
+ if (!existsSync(claudeDir)) {
119
+ spinner.info('.claude/ directory not found, skipping');
120
+ return false;
121
+ }
122
+
123
+ // Define all symlinks that should be removed
124
+ const symlinks = [
125
+ join(claudeDir, 'agents'),
126
+ join(claudeDir, 'tools'),
127
+ join(claudeDir, 'hooks'),
128
+ join(claudeDir, 'commands'),
129
+ join(claudeDir, 'templates'),
130
+ join(claudeDir, 'config'),
131
+ join(claudeDir, 'CHANGELOG.md'),
132
+ join(claudeDir, 'README.en.md'),
133
+ join(claudeDir, 'README.md')
134
+ ];
135
+
136
+ // Also remove AGENTS.md at project root
137
+ const agentsMdPath = join(CWD, 'AGENTS.md');
138
+
139
+ let removed = 0;
140
+
141
+ // Remove known symlinks in .claude/
142
+ for (const symlinkPath of symlinks) {
143
+ try {
144
+ // Use lstat to check if path exists as a symlink (works for broken symlinks too)
145
+ const stats = lstatSync(symlinkPath);
146
+ if (stats.isSymbolicLink() || stats.isFile()) {
147
+ await fs.unlink(symlinkPath);
148
+ removed++;
149
+ }
150
+ } catch (error) {
151
+ // Path doesn't exist or other error, skip
152
+ }
153
+ }
154
+
155
+ // Remove AGENTS.md at project root (it's a symlink)
156
+ try {
157
+ const stats = lstatSync(agentsMdPath);
158
+ if (stats.isSymbolicLink() || stats.isFile()) {
159
+ await fs.unlink(agentsMdPath);
160
+ removed++;
161
+ }
162
+ } catch (error) {
163
+ // Path doesn't exist, skip
164
+ }
165
+
166
+ // Scan for ANY other broken symlinks in .claude/ directory
167
+ try {
168
+ const entries = await fs.readdir(claudeDir);
169
+ for (const entry of entries) {
170
+ const fullPath = join(claudeDir, entry);
171
+ try {
172
+ const stats = lstatSync(fullPath);
173
+ // Check if it's a symlink
174
+ if (stats.isSymbolicLink()) {
175
+ // Try to access the target to see if it's broken
176
+ try {
177
+ await fs.access(fullPath);
178
+ // Symlink is valid, skip
179
+ } catch {
180
+ // Symlink is broken, remove it
181
+ await fs.unlink(fullPath);
182
+ removed++;
183
+ }
184
+ }
185
+ } catch {
186
+ // Skip if can't check
187
+ }
188
+ }
189
+ } catch (error) {
190
+ // Can't read directory, skip scan
191
+ }
192
+
193
+ if (removed > 0) {
194
+ spinner.succeed(`Removed ${removed} symlink(s)`);
195
+ return true;
196
+ } else {
197
+ spinner.info('No symlinks found to remove');
198
+ return false;
199
+ }
200
+ } catch (error) {
201
+ spinner.fail(`Failed to remove symlinks: ${error.message}`);
202
+ return false;
203
+ }
204
+ }
205
+
206
+ /**
207
+ * Data retention policy configuration
208
+ * Defines max age in days for each data category
209
+ */
210
+ const RETENTION_POLICY = {
211
+ auditLogs: { pattern: 'audit-*.jsonl', dir: '.claude/logs', maxDays: 30, label: 'Audit logs' },
212
+ hookLogs: { pattern: 'hooks-*.log', dir: '.claude/logs', maxDays: 14, label: 'Hook logs' },
213
+ monthlyMetrics: { pattern: 'metrics-*.jsonl', dir: '.claude/metrics', maxDays: 90, label: 'Monthly metrics' },
214
+ responseContract: { type: 'dirs', dir: '.claude/session/active/response-contract', maxDays: 7, label: 'Response contract sessions' },
215
+ episodicEpisodes: { pattern: '*.json', dir: '.claude/project-context/episodic-memory/episodes', maxDays: 90, label: 'Episodic memory episodes' },
216
+ workflowMetrics: { type: 'truncate-jsonl', file: '.claude/project-context/workflow-episodic-memory/metrics.jsonl', maxDays: 90, label: 'Workflow metrics' },
217
+ anomalies: { type: 'truncate-jsonl', file: '.claude/project-context/workflow-episodic-memory/anomalies.jsonl', maxDays: 90, label: 'Anomalies' },
218
+ legacyLogs: { type: 'legacy', dir: '.claude/logs', patterns: ['pre_tool_use_v2-*.log', 'post_tool_use_v2-*.log', 'subagent_stop-*.log'], label: 'Legacy logs' },
219
+ anomalyFlag: { type: 'flag-ttl', file: '.claude/project-context/workflow-episodic-memory/signals/needs_analysis.flag', maxHours: 1, label: 'Anomaly signal flag' },
220
+ };
221
+
222
+ /**
223
+ * Check if a filename matches a glob-like pattern (supports * wildcard)
224
+ */
225
+ function matchesPattern(filename, pattern) {
226
+ const escaped = pattern.replace(/[.+^${}()|[\]\\]/g, '\\$&').replace(/\*/g, '.*');
227
+ return new RegExp(`^${escaped}$`).test(filename);
228
+ }
229
+
230
+ /**
231
+ * Delete files matching a pattern that are older than maxDays
232
+ */
233
+ async function pruneOldFiles(dirPath, pattern, maxDays, label) {
234
+ const fullDir = join(CWD, dirPath);
235
+ if (!existsSync(fullDir)) return 0;
236
+
237
+ const cutoff = Date.now() - maxDays * 24 * 60 * 60 * 1000;
238
+ let removed = 0;
239
+
240
+ try {
241
+ const entries = readdirSync(fullDir);
242
+ for (const entry of entries) {
243
+ if (!matchesPattern(entry, pattern)) continue;
244
+ const fullPath = join(fullDir, entry);
245
+ try {
246
+ const stats = statSync(fullPath);
247
+ if (stats.isFile() && stats.mtimeMs < cutoff) {
248
+ await fs.unlink(fullPath);
249
+ console.log(chalk.gray(` Pruned: ${dirPath}/${entry} (${label})`));
250
+ removed++;
251
+ }
252
+ } catch { /* skip unreadable files */ }
253
+ }
254
+ } catch { /* directory not readable */ }
255
+
256
+ return removed;
257
+ }
258
+
259
+ /**
260
+ * Delete directories older than maxDays (by modification time)
261
+ */
262
+ async function pruneOldDirs(dirPath, maxDays, label) {
263
+ const fullDir = join(CWD, dirPath);
264
+ if (!existsSync(fullDir)) return 0;
265
+
266
+ const cutoff = Date.now() - maxDays * 24 * 60 * 60 * 1000;
267
+ let removed = 0;
268
+
269
+ try {
270
+ const entries = readdirSync(fullDir);
271
+ for (const entry of entries) {
272
+ const fullPath = join(fullDir, entry);
273
+ try {
274
+ const stats = statSync(fullPath);
275
+ if (stats.isDirectory() && stats.mtimeMs < cutoff) {
276
+ await fs.rm(fullPath, { recursive: true, force: true });
277
+ console.log(chalk.gray(` Pruned dir: ${dirPath}/${entry} (${label})`));
278
+ removed++;
279
+ }
280
+ } catch { /* skip */ }
281
+ }
282
+ } catch { /* directory not readable */ }
283
+
284
+ return removed;
285
+ }
286
+
287
+ /**
288
+ * Truncate a JSONL file, keeping only entries newer than maxDays
289
+ * Entries must have a "timestamp" field (ISO 8601)
290
+ */
291
+ async function truncateJsonl(filePath, maxDays, label) {
292
+ const fullPath = join(CWD, filePath);
293
+ if (!existsSync(fullPath)) return 0;
294
+
295
+ const cutoff = Date.now() - maxDays * 24 * 60 * 60 * 1000;
296
+ let removedCount = 0;
297
+
298
+ try {
299
+ const content = await fs.readFile(fullPath, 'utf-8');
300
+ const lines = content.trim().split('\n').filter(l => l.trim());
301
+ const kept = [];
302
+
303
+ for (const line of lines) {
304
+ try {
305
+ const entry = JSON.parse(line);
306
+ const ts = entry.timestamp ? new Date(entry.timestamp).getTime() : Date.now();
307
+ if (ts >= cutoff) {
308
+ kept.push(line);
309
+ } else {
310
+ removedCount++;
311
+ }
312
+ } catch {
313
+ // Unparseable line - keep it to be safe
314
+ kept.push(line);
315
+ }
316
+ }
317
+
318
+ if (removedCount > 0) {
319
+ await fs.writeFile(fullPath, kept.join('\n') + (kept.length ? '\n' : ''));
320
+ console.log(chalk.gray(` Truncated: ${filePath} - removed ${removedCount} old entries (${label})`));
321
+ }
322
+ } catch { /* file not readable */ }
323
+
324
+ return removedCount;
325
+ }
326
+
327
+ /**
328
+ * Delete legacy log files that should no longer exist
329
+ */
330
+ async function pruneLegacyLogs(dirPath, patterns, label) {
331
+ const fullDir = join(CWD, dirPath);
332
+ if (!existsSync(fullDir)) return 0;
333
+
334
+ let removed = 0;
335
+
336
+ try {
337
+ const entries = readdirSync(fullDir);
338
+ for (const entry of entries) {
339
+ const matches = patterns.some(p => matchesPattern(entry, p));
340
+ if (!matches) continue;
341
+ const fullPath = join(fullDir, entry);
342
+ try {
343
+ const stats = statSync(fullPath);
344
+ if (stats.isFile()) {
345
+ await fs.unlink(fullPath);
346
+ console.log(chalk.gray(` Deleted legacy: ${dirPath}/${entry} (${label})`));
347
+ removed++;
348
+ }
349
+ } catch { /* skip */ }
350
+ }
351
+ } catch { /* directory not readable */ }
352
+
353
+ return removed;
354
+ }
355
+
356
+ /**
357
+ * Delete a flag file if it is older than maxHours
358
+ */
359
+ async function pruneFlagByTtl(filePath, maxHours, label) {
360
+ const fullPath = join(CWD, filePath);
361
+ if (!existsSync(fullPath)) return 0;
362
+
363
+ const cutoff = Date.now() - maxHours * 60 * 60 * 1000;
364
+
365
+ try {
366
+ const stats = statSync(fullPath);
367
+ if (stats.mtimeMs < cutoff) {
368
+ await fs.unlink(fullPath);
369
+ console.log(chalk.gray(` Expired flag: ${filePath} (${label})`));
370
+ return 1;
371
+ }
372
+
373
+ // Also check created_at timestamp inside the JSON
374
+ try {
375
+ const content = await fs.readFile(fullPath, 'utf-8');
376
+ const data = JSON.parse(content);
377
+ const createdAt = data.created_at || data.timestamp;
378
+ if (createdAt) {
379
+ const createdMs = new Date(createdAt).getTime();
380
+ if (createdMs < cutoff) {
381
+ await fs.unlink(fullPath);
382
+ console.log(chalk.gray(` Expired flag (by created_at): ${filePath} (${label})`));
383
+ return 1;
384
+ }
385
+ }
386
+ } catch { /* not valid JSON, use mtime check above */ }
387
+ } catch { /* file not accessible */ }
388
+
389
+ return 0;
390
+ }
391
+
392
+ /**
393
+ * Rebuild episodic memory index after pruning episodes
394
+ */
395
+ async function rebuildEpisodicIndex() {
396
+ const episodesDir = join(CWD, '.claude/project-context/episodic-memory/episodes');
397
+ const indexPath = join(CWD, '.claude/project-context/episodic-memory/index.json');
398
+
399
+ if (!existsSync(episodesDir)) return;
400
+
401
+ try {
402
+ const entries = readdirSync(episodesDir).filter(e => e.endsWith('.json')).sort();
403
+ const index = [];
404
+
405
+ for (const entry of entries) {
406
+ try {
407
+ const content = await fs.readFile(join(episodesDir, entry), 'utf-8');
408
+ const episode = JSON.parse(content);
409
+ index.push({
410
+ id: episode.id || entry.replace('.json', ''),
411
+ timestamp: episode.timestamp || '',
412
+ prompt_summary: (episode.prompt || '').slice(0, 100),
413
+ outcome: episode.outcome || 'unknown',
414
+ tags: episode.tags || [],
415
+ });
416
+ } catch { /* skip unparseable */ }
417
+ }
418
+
419
+ await fs.writeFile(indexPath, JSON.stringify({ episodes: index, rebuilt_at: new Date().toISOString() }, null, 2));
420
+ console.log(chalk.gray(` Rebuilt episodic index: ${index.length} episodes`));
421
+ } catch (error) {
422
+ console.log(chalk.yellow(` Warning: could not rebuild episodic index: ${error.message}`));
423
+ }
424
+ }
425
+
426
+ /**
427
+ * Apply data retention policy - prune old data across all categories
428
+ */
429
+ async function applyRetentionPolicy() {
430
+ const spinner = ora('Applying data retention policy...').start();
431
+
432
+ let totalPruned = 0;
433
+
434
+ try {
435
+ for (const [_key, policy] of Object.entries(RETENTION_POLICY)) {
436
+ if (policy.type === 'dirs') {
437
+ totalPruned += await pruneOldDirs(policy.dir, policy.maxDays, policy.label);
438
+ } else if (policy.type === 'truncate-jsonl') {
439
+ totalPruned += await truncateJsonl(policy.file, policy.maxDays, policy.label);
440
+ } else if (policy.type === 'legacy') {
441
+ totalPruned += await pruneLegacyLogs(policy.dir, policy.patterns, policy.label);
442
+ } else if (policy.type === 'flag-ttl') {
443
+ totalPruned += await pruneFlagByTtl(policy.file, policy.maxHours, policy.label);
444
+ } else if (policy.pattern) {
445
+ totalPruned += await pruneOldFiles(policy.dir, policy.pattern, policy.maxDays, policy.label);
446
+ }
447
+ }
448
+
449
+ // Rebuild episodic index if any episodes were pruned
450
+ if (totalPruned > 0) {
451
+ await rebuildEpisodicIndex();
452
+ }
453
+
454
+ if (totalPruned > 0) {
455
+ spinner.succeed(`Data retention applied: ${totalPruned} item(s) pruned`);
456
+ } else {
457
+ spinner.info('Data retention: nothing to prune');
458
+ }
459
+
460
+ return totalPruned > 0;
461
+ } catch (error) {
462
+ spinner.fail(`Data retention failed: ${error.message}`);
463
+ return false;
464
+ }
465
+ }
466
+
467
+ /**
468
+ * Main function
469
+ */
470
+ async function main() {
471
+ process.stderr.write('[DEPRECATED] gaia-cleanup.js is deprecated. Use: python3 bin/gaia cleanup\n[DEPRECATED] Migration guide: see CHANGELOG.md\n');
472
+
473
+ const args = process.argv.slice(2);
474
+ const pruneOnly = args.includes('--prune') || args.includes('--retain');
475
+
476
+ if (pruneOnly) {
477
+ console.log(chalk.cyan('\n🧹 @jaguilar87/gaia data retention\n'));
478
+ console.log(chalk.gray('Retention policy:'));
479
+ console.log(chalk.gray(' Audit logs: 30 days'));
480
+ console.log(chalk.gray(' Hook logs: 14 days'));
481
+ console.log(chalk.gray(' Monthly metrics: 90 days'));
482
+ console.log(chalk.gray(' Response contracts: 7 days'));
483
+ console.log(chalk.gray(' Episodic episodes: 90 days'));
484
+ console.log(chalk.gray(' Workflow metrics: 90 days'));
485
+ console.log(chalk.gray(' Anomalies: 90 days'));
486
+ console.log(chalk.gray(' Legacy logs: all removed'));
487
+ console.log(chalk.gray(' Anomaly flag: 1 hour TTL\n'));
488
+
489
+ try {
490
+ const pruned = await applyRetentionPolicy();
491
+ if (pruned) {
492
+ console.log(chalk.green('\n✅ Data retention completed\n'));
493
+ } else {
494
+ console.log(chalk.gray('\n✓ All data within retention limits\n'));
495
+ }
496
+ } catch (error) {
497
+ console.error(chalk.red(`\n❌ Data retention failed: ${error.message}\n`));
498
+ process.exit(1);
499
+ }
500
+ return;
501
+ }
502
+
503
+ console.log(chalk.cyan('\n🧹 @jaguilar87/gaia cleanup\n'));
504
+
505
+ try {
506
+ const claudeRemoved = await removeClaudeMd();
507
+ const settingsRemoved = await removeSettingsJson();
508
+ const symlinksRemoved = await removeSymlinks();
509
+
510
+ // Always apply data retention as part of cleanup
511
+ const retentionApplied = await applyRetentionPolicy();
512
+
513
+ if (claudeRemoved || settingsRemoved || symlinksRemoved || retentionApplied) {
514
+ console.log(chalk.green('\n✅ Cleanup completed\n'));
515
+ console.log(chalk.gray('Preserved data:'));
516
+ console.log(chalk.gray(' • .claude/logs/'));
517
+ console.log(chalk.gray(' • .claude/tests/'));
518
+ console.log(chalk.gray(' • .claude/project-context/'));
519
+ console.log(chalk.gray(' • .claude/session/'));
520
+ console.log(chalk.gray(' • .claude/metrics/\n'));
521
+ } else {
522
+ console.log(chalk.gray('\n✓ Nothing to clean up\n'));
523
+ }
524
+ } catch (error) {
525
+ console.error(chalk.red(`\n❌ Cleanup failed: ${error.message}\n`));
526
+ // Don't fail npm uninstall, just warn
527
+ process.exit(0);
528
+ }
529
+ }
530
+
531
+ main();