@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.
- package/.claude-plugin/marketplace.json +33 -0
- package/.claude-plugin/plugin.json +26 -0
- package/ARCHITECTURE.md +335 -0
- package/CHANGELOG.md +1212 -0
- package/CODE_OF_CONDUCT.md +11 -0
- package/CONTRIBUTING.md +146 -0
- package/INSTALL.md +436 -0
- package/LICENSE +21 -0
- package/README.md +222 -0
- package/SECURITY.md +47 -0
- package/agents/README.md +78 -0
- package/agents/cloud-troubleshooter.md +73 -0
- package/agents/developer.md +65 -0
- package/agents/gaia-operator.md +64 -0
- package/agents/gaia-orchestrator.md +237 -0
- package/agents/gaia-planner.md +53 -0
- package/agents/gaia-system.md +70 -0
- package/agents/gitops-operator.md +61 -0
- package/agents/terraform-architect.md +63 -0
- package/bin/README.md +106 -0
- package/bin/cli/__init__.py +1 -0
- package/bin/cli/approvals.py +740 -0
- package/bin/cli/cleanup.py +562 -0
- package/bin/cli/context.py +283 -0
- package/bin/cli/doctor.py +628 -0
- package/bin/cli/history.py +305 -0
- package/bin/cli/memory.py +464 -0
- package/bin/cli/metrics.py +1068 -0
- package/bin/cli/plans.py +515 -0
- package/bin/cli/status.py +302 -0
- package/bin/cli/update.py +382 -0
- package/bin/gaia +112 -0
- package/bin/gaia-cleanup.js +531 -0
- package/bin/gaia-doctor.js +635 -0
- package/bin/gaia-evidence +126 -0
- package/bin/gaia-history.js +251 -0
- package/bin/gaia-metrics.js +1278 -0
- package/bin/gaia-review.js +269 -0
- package/bin/gaia-scan +44 -0
- package/bin/gaia-scan.py +589 -0
- package/bin/gaia-skills-diagnose.js +929 -0
- package/bin/gaia-status.js +278 -0
- package/bin/gaia-uninstall.js +111 -0
- package/bin/gaia-update.js +816 -0
- package/bin/pre-publish-validate.js +610 -0
- package/bin/python-detect.js +60 -0
- package/commands/README.md +64 -0
- package/commands/gaia.md +37 -0
- package/commands/scan-project.md +67 -0
- package/config/README.md +71 -0
- package/config/cloud/aws.json +134 -0
- package/config/cloud/gcp.json +139 -0
- package/config/context-contracts.json +158 -0
- package/config/crons-schema.md +81 -0
- package/config/git_standards.json +72 -0
- package/config/surface-routing.json +421 -0
- package/config/universal-rules.json +102 -0
- package/dist/gaia-ops/.claude-plugin/plugin.json +24 -0
- package/dist/gaia-ops/README.md +80 -0
- package/dist/gaia-ops/agents/cloud-troubleshooter.md +73 -0
- package/dist/gaia-ops/agents/developer.md +65 -0
- package/dist/gaia-ops/agents/gaia-operator.md +64 -0
- package/dist/gaia-ops/agents/gaia-orchestrator.md +237 -0
- package/dist/gaia-ops/agents/gaia-planner.md +53 -0
- package/dist/gaia-ops/agents/gaia-system.md +70 -0
- package/dist/gaia-ops/agents/gitops-operator.md +61 -0
- package/dist/gaia-ops/agents/terraform-architect.md +63 -0
- package/dist/gaia-ops/commands/gaia.md +37 -0
- package/dist/gaia-ops/config/README.md +71 -0
- package/dist/gaia-ops/config/cloud/aws.json +134 -0
- package/dist/gaia-ops/config/cloud/gcp.json +139 -0
- package/dist/gaia-ops/config/context-contracts.json +158 -0
- package/dist/gaia-ops/config/crons-schema.md +81 -0
- package/dist/gaia-ops/config/git_standards.json +72 -0
- package/dist/gaia-ops/config/surface-routing.json +421 -0
- package/dist/gaia-ops/config/universal-rules.json +102 -0
- package/dist/gaia-ops/hooks/adapters/__init__.py +52 -0
- package/dist/gaia-ops/hooks/adapters/base.py +219 -0
- package/dist/gaia-ops/hooks/adapters/channel.py +17 -0
- package/dist/gaia-ops/hooks/adapters/claude_code.py +1890 -0
- package/dist/gaia-ops/hooks/adapters/types.py +194 -0
- package/dist/gaia-ops/hooks/adapters/utils.py +25 -0
- package/dist/gaia-ops/hooks/hooks.json +163 -0
- package/dist/gaia-ops/hooks/modules/__init__.py +15 -0
- package/dist/gaia-ops/hooks/modules/agents/__init__.py +29 -0
- package/dist/gaia-ops/hooks/modules/agents/contract_validator.py +647 -0
- package/dist/gaia-ops/hooks/modules/agents/response_contract.py +496 -0
- package/dist/gaia-ops/hooks/modules/agents/skill_injection_verifier.py +120 -0
- package/dist/gaia-ops/hooks/modules/agents/state_tracker.py +267 -0
- package/dist/gaia-ops/hooks/modules/agents/task_info_builder.py +74 -0
- package/dist/gaia-ops/hooks/modules/agents/transcript_analyzer.py +458 -0
- package/dist/gaia-ops/hooks/modules/agents/transcript_reader.py +152 -0
- package/dist/gaia-ops/hooks/modules/audit/__init__.py +28 -0
- package/dist/gaia-ops/hooks/modules/audit/event_detector.py +168 -0
- package/dist/gaia-ops/hooks/modules/audit/logger.py +131 -0
- package/dist/gaia-ops/hooks/modules/audit/metrics.py +134 -0
- package/dist/gaia-ops/hooks/modules/audit/workflow_auditor.py +611 -0
- package/dist/gaia-ops/hooks/modules/audit/workflow_recorder.py +296 -0
- package/dist/gaia-ops/hooks/modules/context/__init__.py +11 -0
- package/dist/gaia-ops/hooks/modules/context/agentic_loop_detector.py +165 -0
- package/dist/gaia-ops/hooks/modules/context/anchor_tracker.py +317 -0
- package/dist/gaia-ops/hooks/modules/context/compact_context_builder.py +218 -0
- package/dist/gaia-ops/hooks/modules/context/context_freshness.py +145 -0
- package/dist/gaia-ops/hooks/modules/context/context_injector.py +558 -0
- package/dist/gaia-ops/hooks/modules/context/context_writer.py +530 -0
- package/dist/gaia-ops/hooks/modules/context/contracts_loader.py +161 -0
- package/dist/gaia-ops/hooks/modules/core/__init__.py +40 -0
- package/dist/gaia-ops/hooks/modules/core/hook_entry.py +78 -0
- package/dist/gaia-ops/hooks/modules/core/paths.py +160 -0
- package/dist/gaia-ops/hooks/modules/core/plugin_mode.py +149 -0
- package/dist/gaia-ops/hooks/modules/core/plugin_setup.py +577 -0
- package/dist/gaia-ops/hooks/modules/core/state.py +179 -0
- package/dist/gaia-ops/hooks/modules/core/stdin.py +24 -0
- package/dist/gaia-ops/hooks/modules/events/__init__.py +1 -0
- package/dist/gaia-ops/hooks/modules/events/event_writer.py +210 -0
- package/dist/gaia-ops/hooks/modules/memory/__init__.py +8 -0
- package/dist/gaia-ops/hooks/modules/memory/episode_writer.py +216 -0
- package/dist/gaia-ops/hooks/modules/orchestrator/__init__.py +1 -0
- package/dist/gaia-ops/hooks/modules/orchestrator/delegate_mode.py +122 -0
- package/dist/gaia-ops/hooks/modules/scanning/__init__.py +8 -0
- package/dist/gaia-ops/hooks/modules/scanning/scan_trigger.py +84 -0
- package/dist/gaia-ops/hooks/modules/security/__init__.py +120 -0
- package/dist/gaia-ops/hooks/modules/security/approval_cleanup.py +87 -0
- package/dist/gaia-ops/hooks/modules/security/approval_constants.py +23 -0
- package/dist/gaia-ops/hooks/modules/security/approval_grants.py +1638 -0
- package/dist/gaia-ops/hooks/modules/security/approval_messages.py +71 -0
- package/dist/gaia-ops/hooks/modules/security/approval_scopes.py +222 -0
- package/dist/gaia-ops/hooks/modules/security/blocked_commands.py +595 -0
- package/dist/gaia-ops/hooks/modules/security/blocked_message_formatter.py +87 -0
- package/dist/gaia-ops/hooks/modules/security/command_semantics.py +181 -0
- package/dist/gaia-ops/hooks/modules/security/composition_rules.py +547 -0
- package/dist/gaia-ops/hooks/modules/security/flag_classifiers.py +873 -0
- package/dist/gaia-ops/hooks/modules/security/gitops_validator.py +179 -0
- package/dist/gaia-ops/hooks/modules/security/mutative_verbs.py +1131 -0
- package/dist/gaia-ops/hooks/modules/security/network_hosts.py +481 -0
- package/dist/gaia-ops/hooks/modules/security/prompt_validator.py +40 -0
- package/dist/gaia-ops/hooks/modules/security/shell_unwrapper.py +165 -0
- package/dist/gaia-ops/hooks/modules/security/tiers.py +196 -0
- package/dist/gaia-ops/hooks/modules/session/__init__.py +10 -0
- package/dist/gaia-ops/hooks/modules/session/pending_scanner.py +174 -0
- package/dist/gaia-ops/hooks/modules/session/session_context_writer.py +100 -0
- package/dist/gaia-ops/hooks/modules/session/session_event_injector.py +160 -0
- package/dist/gaia-ops/hooks/modules/session/session_manager.py +31 -0
- package/dist/gaia-ops/hooks/modules/session/session_registry.py +232 -0
- package/dist/gaia-ops/hooks/modules/tools/__init__.py +29 -0
- package/dist/gaia-ops/hooks/modules/tools/bash_validator.py +1008 -0
- package/dist/gaia-ops/hooks/modules/tools/cloud_pipe_validator.py +231 -0
- package/dist/gaia-ops/hooks/modules/tools/hook_response.py +55 -0
- package/dist/gaia-ops/hooks/modules/tools/shell_parser.py +227 -0
- package/dist/gaia-ops/hooks/modules/tools/stage_decomposer.py +315 -0
- package/dist/gaia-ops/hooks/modules/tools/task_validator.py +294 -0
- package/dist/gaia-ops/hooks/modules/validation/__init__.py +23 -0
- package/dist/gaia-ops/hooks/modules/validation/commit_validator.py +380 -0
- package/dist/gaia-ops/hooks/post_compact.py +43 -0
- package/dist/gaia-ops/hooks/post_tool_use.py +54 -0
- package/dist/gaia-ops/hooks/pre_compact.py +60 -0
- package/dist/gaia-ops/hooks/pre_tool_use.py +413 -0
- package/dist/gaia-ops/hooks/session_start.py +81 -0
- package/dist/gaia-ops/hooks/stop_hook.py +82 -0
- package/dist/gaia-ops/hooks/subagent_start.py +71 -0
- package/dist/gaia-ops/hooks/subagent_stop.py +295 -0
- package/dist/gaia-ops/hooks/task_completed.py +70 -0
- package/dist/gaia-ops/hooks/user_prompt_submit.py +246 -0
- package/dist/gaia-ops/settings.json +72 -0
- package/dist/gaia-ops/skills/README.md +154 -0
- package/dist/gaia-ops/skills/agent-protocol/SKILL.md +93 -0
- package/dist/gaia-ops/skills/agent-protocol/examples.md +223 -0
- package/dist/gaia-ops/skills/agent-response/SKILL.md +69 -0
- package/dist/gaia-ops/skills/agentic-loop/SKILL.md +80 -0
- package/dist/gaia-ops/skills/agentic-loop/reference.md +378 -0
- package/dist/gaia-ops/skills/blog-writing/SKILL.md +98 -0
- package/dist/gaia-ops/skills/blog-writing/reference.md +130 -0
- package/dist/gaia-ops/skills/brief-spec/SKILL.md +182 -0
- package/dist/gaia-ops/skills/command-execution/SKILL.md +64 -0
- package/dist/gaia-ops/skills/command-execution/reference.md +83 -0
- package/dist/gaia-ops/skills/context-updater/SKILL.md +87 -0
- package/dist/gaia-ops/skills/context-updater/examples.md +71 -0
- package/dist/gaia-ops/skills/developer-patterns/SKILL.md +50 -0
- package/dist/gaia-ops/skills/developer-patterns/reference.md +112 -0
- package/dist/gaia-ops/skills/execution/SKILL.md +99 -0
- package/dist/gaia-ops/skills/fast-queries/SKILL.md +43 -0
- package/dist/gaia-ops/skills/gaia-compact/SKILL.md +74 -0
- package/dist/gaia-ops/skills/gaia-patterns/SKILL.md +108 -0
- package/dist/gaia-ops/skills/gaia-patterns/reference.md +395 -0
- package/dist/gaia-ops/skills/gaia-planner/SKILL.md +37 -0
- package/dist/gaia-ops/skills/gaia-planner/reference.md +107 -0
- package/dist/gaia-ops/skills/gaia-release/SKILL.md +82 -0
- package/dist/gaia-ops/skills/gaia-release/reference.md +102 -0
- package/dist/gaia-ops/skills/gaia-self-check/SKILL.md +114 -0
- package/dist/gaia-ops/skills/gaia-self-check/reference.md +453 -0
- package/dist/gaia-ops/skills/gaia-verify/SKILL.md +77 -0
- package/dist/gaia-ops/skills/gaia-verify/reference.md +80 -0
- package/dist/gaia-ops/skills/git-conventions/SKILL.md +47 -0
- package/dist/gaia-ops/skills/gitops-patterns/SKILL.md +60 -0
- package/dist/gaia-ops/skills/gitops-patterns/reference.md +183 -0
- package/dist/gaia-ops/skills/gmail-policy/SKILL.md +200 -0
- package/dist/gaia-ops/skills/gmail-policy/reference.md +150 -0
- package/dist/gaia-ops/skills/gmail-triage/SKILL.md +100 -0
- package/dist/gaia-ops/skills/gws-setup/SKILL.md +99 -0
- package/dist/gaia-ops/skills/gws-setup/reference.md +73 -0
- package/dist/gaia-ops/skills/investigation/SKILL.md +100 -0
- package/dist/gaia-ops/skills/memory-curation/SKILL.md +83 -0
- package/dist/gaia-ops/skills/memory-search/SKILL.md +88 -0
- package/dist/gaia-ops/skills/orchestrator-approval/SKILL.md +160 -0
- package/dist/gaia-ops/skills/orchestrator-approval/reference.md +174 -0
- package/dist/gaia-ops/skills/pending-approvals/SKILL.md +72 -0
- package/dist/gaia-ops/skills/pending-approvals/reference.md +214 -0
- package/dist/gaia-ops/skills/readme-writing/SKILL.md +71 -0
- package/dist/gaia-ops/skills/readme-writing/reference.md +188 -0
- package/dist/gaia-ops/skills/reference.md +135 -0
- package/dist/gaia-ops/skills/request-approval/SKILL.md +140 -0
- package/dist/gaia-ops/skills/request-approval/examples.md +140 -0
- package/dist/gaia-ops/skills/request-approval/reference.md +57 -0
- package/dist/gaia-ops/skills/schedule-task/SKILL.md +64 -0
- package/dist/gaia-ops/skills/schedule-task/reference.md +233 -0
- package/dist/gaia-ops/skills/security-tiers/SKILL.md +141 -0
- package/dist/gaia-ops/skills/security-tiers/destructive-commands-reference.md +623 -0
- package/dist/gaia-ops/skills/security-tiers/reference.md +39 -0
- package/dist/gaia-ops/skills/skill-creation/SKILL.md +92 -0
- package/dist/gaia-ops/skills/skill-creation/reference.md +29 -0
- package/dist/gaia-ops/skills/terraform-patterns/SKILL.md +89 -0
- package/dist/gaia-ops/skills/terraform-patterns/reference.md +93 -0
- package/dist/gaia-ops/tools/__init__.py +9 -0
- package/dist/gaia-ops/tools/agentic-loop/decide-status.py +210 -0
- package/dist/gaia-ops/tools/agentic-loop/parse-metric.py +106 -0
- package/dist/gaia-ops/tools/agentic-loop/record-iteration.py +221 -0
- package/dist/gaia-ops/tools/context/README.md +132 -0
- package/dist/gaia-ops/tools/context/__init__.py +42 -0
- package/dist/gaia-ops/tools/context/_paths.py +20 -0
- package/dist/gaia-ops/tools/context/context_provider.py +721 -0
- package/dist/gaia-ops/tools/context/context_section_reader.py +342 -0
- package/dist/gaia-ops/tools/context/deep_merge.py +159 -0
- package/dist/gaia-ops/tools/context/pending_updates.py +760 -0
- package/dist/gaia-ops/tools/context/surface_router.py +278 -0
- package/dist/gaia-ops/tools/fast-queries/README.md +65 -0
- package/dist/gaia-ops/tools/fast-queries/__init__.py +30 -0
- package/dist/gaia-ops/tools/fast-queries/appservices/quicktriage_devops_developer.sh +75 -0
- package/dist/gaia-ops/tools/fast-queries/cloud/aws/quicktriage_aws_troubleshooter.sh +32 -0
- package/dist/gaia-ops/tools/fast-queries/cloud/gcp/quicktriage_gcp_troubleshooter.sh +88 -0
- package/dist/gaia-ops/tools/fast-queries/gitops/quicktriage_gitops_operator.sh +48 -0
- package/dist/gaia-ops/tools/fast-queries/run_triage.sh +59 -0
- package/dist/gaia-ops/tools/fast-queries/terraform/quicktriage_terraform_architect.sh +80 -0
- package/dist/gaia-ops/tools/gaia_simulator/__init__.py +33 -0
- package/dist/gaia-ops/tools/gaia_simulator/cli.py +354 -0
- package/dist/gaia-ops/tools/gaia_simulator/extractor.py +457 -0
- package/dist/gaia-ops/tools/gaia_simulator/reporter.py +258 -0
- package/dist/gaia-ops/tools/gaia_simulator/routing_simulator.py +334 -0
- package/dist/gaia-ops/tools/gaia_simulator/runner.py +539 -0
- package/dist/gaia-ops/tools/gaia_simulator/skills_mapper.py +264 -0
- package/dist/gaia-ops/tools/memory/README.md +0 -0
- package/dist/gaia-ops/tools/memory/__init__.py +20 -0
- package/dist/gaia-ops/tools/memory/backfill_fts5.py +107 -0
- package/dist/gaia-ops/tools/memory/conflict_detector.py +295 -0
- package/dist/gaia-ops/tools/memory/episodic.py +1210 -0
- package/dist/gaia-ops/tools/memory/git_invalidator.py +262 -0
- package/dist/gaia-ops/tools/memory/paths.py +102 -0
- package/dist/gaia-ops/tools/memory/scoring.py +193 -0
- package/dist/gaia-ops/tools/memory/search_store.py +360 -0
- package/dist/gaia-ops/tools/persist_transcript_analysis.py +85 -0
- package/dist/gaia-ops/tools/review/__init__.py +1 -0
- package/dist/gaia-ops/tools/review/review_engine.py +157 -0
- package/dist/gaia-ops/tools/scan/__init__.py +35 -0
- package/dist/gaia-ops/tools/scan/config.py +247 -0
- package/dist/gaia-ops/tools/scan/merge.py +212 -0
- package/dist/gaia-ops/tools/scan/orchestrator.py +549 -0
- package/dist/gaia-ops/tools/scan/registry.py +127 -0
- package/dist/gaia-ops/tools/scan/scanners/__init__.py +18 -0
- package/dist/gaia-ops/tools/scan/scanners/base.py +137 -0
- package/dist/gaia-ops/tools/scan/scanners/environment.py +349 -0
- package/dist/gaia-ops/tools/scan/scanners/git.py +570 -0
- package/dist/gaia-ops/tools/scan/scanners/infrastructure.py +875 -0
- package/dist/gaia-ops/tools/scan/scanners/orchestration.py +600 -0
- package/dist/gaia-ops/tools/scan/scanners/stack.py +1085 -0
- package/dist/gaia-ops/tools/scan/scanners/tools.py +260 -0
- package/dist/gaia-ops/tools/scan/setup.py +686 -0
- package/dist/gaia-ops/tools/scan/tests/__init__.py +1 -0
- package/dist/gaia-ops/tools/scan/tests/conftest.py +796 -0
- package/dist/gaia-ops/tools/scan/tests/test_environment.py +323 -0
- package/dist/gaia-ops/tools/scan/tests/test_git.py +419 -0
- package/dist/gaia-ops/tools/scan/tests/test_infrastructure.py +382 -0
- package/dist/gaia-ops/tools/scan/tests/test_integration.py +920 -0
- package/dist/gaia-ops/tools/scan/tests/test_merge.py +269 -0
- package/dist/gaia-ops/tools/scan/tests/test_orchestration.py +304 -0
- package/dist/gaia-ops/tools/scan/tests/test_stack.py +604 -0
- package/dist/gaia-ops/tools/scan/tests/test_tools.py +349 -0
- package/dist/gaia-ops/tools/scan/ui.py +624 -0
- package/dist/gaia-ops/tools/scan/verify.py +270 -0
- package/dist/gaia-ops/tools/scan/walk.py +118 -0
- package/dist/gaia-ops/tools/scan/workspace.py +85 -0
- package/dist/gaia-ops/tools/validation/README.md +244 -0
- package/dist/gaia-ops/tools/validation/__init__.py +17 -0
- package/dist/gaia-ops/tools/validation/approval_gate.py +321 -0
- package/dist/gaia-ops/tools/validation/validate_skills.py +189 -0
- package/dist/gaia-security/.claude-plugin/plugin.json +24 -0
- package/dist/gaia-security/README.md +90 -0
- package/dist/gaia-security/config/universal-rules.json +102 -0
- package/dist/gaia-security/hooks/adapters/__init__.py +52 -0
- package/dist/gaia-security/hooks/adapters/base.py +219 -0
- package/dist/gaia-security/hooks/adapters/channel.py +17 -0
- package/dist/gaia-security/hooks/adapters/claude_code.py +1890 -0
- package/dist/gaia-security/hooks/adapters/types.py +194 -0
- package/dist/gaia-security/hooks/adapters/utils.py +25 -0
- package/dist/gaia-security/hooks/hooks.json +84 -0
- package/dist/gaia-security/hooks/modules/__init__.py +15 -0
- package/dist/gaia-security/hooks/modules/agents/__init__.py +29 -0
- package/dist/gaia-security/hooks/modules/agents/contract_validator.py +647 -0
- package/dist/gaia-security/hooks/modules/agents/response_contract.py +496 -0
- package/dist/gaia-security/hooks/modules/agents/skill_injection_verifier.py +120 -0
- package/dist/gaia-security/hooks/modules/agents/state_tracker.py +267 -0
- package/dist/gaia-security/hooks/modules/agents/task_info_builder.py +74 -0
- package/dist/gaia-security/hooks/modules/agents/transcript_analyzer.py +458 -0
- package/dist/gaia-security/hooks/modules/agents/transcript_reader.py +152 -0
- package/dist/gaia-security/hooks/modules/audit/__init__.py +28 -0
- package/dist/gaia-security/hooks/modules/audit/event_detector.py +168 -0
- package/dist/gaia-security/hooks/modules/audit/logger.py +131 -0
- package/dist/gaia-security/hooks/modules/audit/metrics.py +134 -0
- package/dist/gaia-security/hooks/modules/audit/workflow_auditor.py +611 -0
- package/dist/gaia-security/hooks/modules/audit/workflow_recorder.py +296 -0
- package/dist/gaia-security/hooks/modules/context/__init__.py +11 -0
- package/dist/gaia-security/hooks/modules/context/agentic_loop_detector.py +165 -0
- package/dist/gaia-security/hooks/modules/context/anchor_tracker.py +317 -0
- package/dist/gaia-security/hooks/modules/context/compact_context_builder.py +218 -0
- package/dist/gaia-security/hooks/modules/context/context_freshness.py +145 -0
- package/dist/gaia-security/hooks/modules/context/context_injector.py +558 -0
- package/dist/gaia-security/hooks/modules/context/context_writer.py +530 -0
- package/dist/gaia-security/hooks/modules/context/contracts_loader.py +161 -0
- package/dist/gaia-security/hooks/modules/core/__init__.py +40 -0
- package/dist/gaia-security/hooks/modules/core/hook_entry.py +78 -0
- package/dist/gaia-security/hooks/modules/core/paths.py +160 -0
- package/dist/gaia-security/hooks/modules/core/plugin_mode.py +149 -0
- package/dist/gaia-security/hooks/modules/core/plugin_setup.py +577 -0
- package/dist/gaia-security/hooks/modules/core/state.py +179 -0
- package/dist/gaia-security/hooks/modules/core/stdin.py +24 -0
- package/dist/gaia-security/hooks/modules/events/__init__.py +1 -0
- package/dist/gaia-security/hooks/modules/events/event_writer.py +210 -0
- package/dist/gaia-security/hooks/modules/memory/__init__.py +8 -0
- package/dist/gaia-security/hooks/modules/memory/episode_writer.py +216 -0
- package/dist/gaia-security/hooks/modules/orchestrator/__init__.py +1 -0
- package/dist/gaia-security/hooks/modules/orchestrator/delegate_mode.py +122 -0
- package/dist/gaia-security/hooks/modules/scanning/__init__.py +8 -0
- package/dist/gaia-security/hooks/modules/scanning/scan_trigger.py +84 -0
- package/dist/gaia-security/hooks/modules/security/__init__.py +120 -0
- package/dist/gaia-security/hooks/modules/security/approval_cleanup.py +87 -0
- package/dist/gaia-security/hooks/modules/security/approval_constants.py +23 -0
- package/dist/gaia-security/hooks/modules/security/approval_grants.py +1638 -0
- package/dist/gaia-security/hooks/modules/security/approval_messages.py +71 -0
- package/dist/gaia-security/hooks/modules/security/approval_scopes.py +222 -0
- package/dist/gaia-security/hooks/modules/security/blocked_commands.py +595 -0
- package/dist/gaia-security/hooks/modules/security/blocked_message_formatter.py +87 -0
- package/dist/gaia-security/hooks/modules/security/command_semantics.py +181 -0
- package/dist/gaia-security/hooks/modules/security/composition_rules.py +547 -0
- package/dist/gaia-security/hooks/modules/security/flag_classifiers.py +873 -0
- package/dist/gaia-security/hooks/modules/security/gitops_validator.py +179 -0
- package/dist/gaia-security/hooks/modules/security/mutative_verbs.py +1131 -0
- package/dist/gaia-security/hooks/modules/security/network_hosts.py +481 -0
- package/dist/gaia-security/hooks/modules/security/prompt_validator.py +40 -0
- package/dist/gaia-security/hooks/modules/security/shell_unwrapper.py +165 -0
- package/dist/gaia-security/hooks/modules/security/tiers.py +196 -0
- package/dist/gaia-security/hooks/modules/session/__init__.py +10 -0
- package/dist/gaia-security/hooks/modules/session/pending_scanner.py +174 -0
- package/dist/gaia-security/hooks/modules/session/session_context_writer.py +100 -0
- package/dist/gaia-security/hooks/modules/session/session_event_injector.py +160 -0
- package/dist/gaia-security/hooks/modules/session/session_manager.py +31 -0
- package/dist/gaia-security/hooks/modules/session/session_registry.py +232 -0
- package/dist/gaia-security/hooks/modules/tools/__init__.py +29 -0
- package/dist/gaia-security/hooks/modules/tools/bash_validator.py +1008 -0
- package/dist/gaia-security/hooks/modules/tools/cloud_pipe_validator.py +231 -0
- package/dist/gaia-security/hooks/modules/tools/hook_response.py +55 -0
- package/dist/gaia-security/hooks/modules/tools/shell_parser.py +227 -0
- package/dist/gaia-security/hooks/modules/tools/stage_decomposer.py +315 -0
- package/dist/gaia-security/hooks/modules/tools/task_validator.py +294 -0
- package/dist/gaia-security/hooks/modules/validation/__init__.py +23 -0
- package/dist/gaia-security/hooks/modules/validation/commit_validator.py +380 -0
- package/dist/gaia-security/hooks/post_tool_use.py +54 -0
- package/dist/gaia-security/hooks/pre_tool_use.py +413 -0
- package/dist/gaia-security/hooks/session_start.py +81 -0
- package/dist/gaia-security/hooks/stop_hook.py +82 -0
- package/dist/gaia-security/hooks/user_prompt_submit.py +246 -0
- package/dist/gaia-security/settings.json +58 -0
- package/git-hooks/commit-msg +41 -0
- package/hooks/README.md +100 -0
- package/hooks/adapters/__init__.py +52 -0
- package/hooks/adapters/base.py +219 -0
- package/hooks/adapters/channel.py +17 -0
- package/hooks/adapters/claude_code.py +1890 -0
- package/hooks/adapters/types.py +194 -0
- package/hooks/adapters/utils.py +25 -0
- package/hooks/elicitation_result.py +179 -0
- package/hooks/hooks.json +84 -0
- package/hooks/modules/README.md +189 -0
- package/hooks/modules/__init__.py +15 -0
- package/hooks/modules/agents/__init__.py +29 -0
- package/hooks/modules/agents/contract_validator.py +647 -0
- package/hooks/modules/agents/response_contract.py +496 -0
- package/hooks/modules/agents/skill_injection_verifier.py +120 -0
- package/hooks/modules/agents/state_tracker.py +267 -0
- package/hooks/modules/agents/task_info_builder.py +74 -0
- package/hooks/modules/agents/transcript_analyzer.py +458 -0
- package/hooks/modules/agents/transcript_reader.py +152 -0
- package/hooks/modules/audit/__init__.py +28 -0
- package/hooks/modules/audit/event_detector.py +168 -0
- package/hooks/modules/audit/logger.py +131 -0
- package/hooks/modules/audit/metrics.py +134 -0
- package/hooks/modules/audit/workflow_auditor.py +611 -0
- package/hooks/modules/audit/workflow_recorder.py +296 -0
- package/hooks/modules/context/__init__.py +11 -0
- package/hooks/modules/context/agentic_loop_detector.py +165 -0
- package/hooks/modules/context/anchor_tracker.py +317 -0
- package/hooks/modules/context/compact_context_builder.py +218 -0
- package/hooks/modules/context/context_freshness.py +145 -0
- package/hooks/modules/context/context_injector.py +558 -0
- package/hooks/modules/context/context_writer.py +530 -0
- package/hooks/modules/context/contracts_loader.py +161 -0
- package/hooks/modules/core/__init__.py +40 -0
- package/hooks/modules/core/hook_entry.py +78 -0
- package/hooks/modules/core/paths.py +160 -0
- package/hooks/modules/core/plugin_mode.py +149 -0
- package/hooks/modules/core/plugin_setup.py +577 -0
- package/hooks/modules/core/state.py +179 -0
- package/hooks/modules/core/stdin.py +24 -0
- package/hooks/modules/events/__init__.py +1 -0
- package/hooks/modules/events/event_writer.py +210 -0
- package/hooks/modules/evidence/__init__.py +34 -0
- package/hooks/modules/evidence/assertions.py +137 -0
- package/hooks/modules/evidence/index_writer.py +57 -0
- package/hooks/modules/evidence/loader.py +126 -0
- package/hooks/modules/evidence/runner.py +241 -0
- package/hooks/modules/memory/__init__.py +8 -0
- package/hooks/modules/memory/episode_writer.py +216 -0
- package/hooks/modules/orchestrator/__init__.py +1 -0
- package/hooks/modules/orchestrator/delegate_mode.py +122 -0
- package/hooks/modules/scanning/__init__.py +8 -0
- package/hooks/modules/scanning/scan_trigger.py +84 -0
- package/hooks/modules/security/__init__.py +120 -0
- package/hooks/modules/security/approval_cleanup.py +87 -0
- package/hooks/modules/security/approval_constants.py +23 -0
- package/hooks/modules/security/approval_grants.py +1638 -0
- package/hooks/modules/security/approval_messages.py +71 -0
- package/hooks/modules/security/approval_scopes.py +222 -0
- package/hooks/modules/security/blocked_commands.py +595 -0
- package/hooks/modules/security/blocked_message_formatter.py +87 -0
- package/hooks/modules/security/command_semantics.py +181 -0
- package/hooks/modules/security/composition_rules.py +547 -0
- package/hooks/modules/security/flag_classifiers.py +873 -0
- package/hooks/modules/security/gitops_validator.py +179 -0
- package/hooks/modules/security/mutative_verbs.py +1131 -0
- package/hooks/modules/security/network_hosts.py +481 -0
- package/hooks/modules/security/prompt_validator.py +40 -0
- package/hooks/modules/security/shell_unwrapper.py +165 -0
- package/hooks/modules/security/tiers.py +196 -0
- package/hooks/modules/session/__init__.py +10 -0
- package/hooks/modules/session/pending_scanner.py +174 -0
- package/hooks/modules/session/session_context_writer.py +100 -0
- package/hooks/modules/session/session_event_injector.py +160 -0
- package/hooks/modules/session/session_manager.py +31 -0
- package/hooks/modules/session/session_registry.py +232 -0
- package/hooks/modules/tools/__init__.py +29 -0
- package/hooks/modules/tools/bash_validator.py +1008 -0
- package/hooks/modules/tools/cloud_pipe_validator.py +231 -0
- package/hooks/modules/tools/hook_response.py +55 -0
- package/hooks/modules/tools/shell_parser.py +227 -0
- package/hooks/modules/tools/stage_decomposer.py +315 -0
- package/hooks/modules/tools/task_validator.py +294 -0
- package/hooks/modules/validation/__init__.py +23 -0
- package/hooks/modules/validation/commit_validator.py +380 -0
- package/hooks/post_compact.py +43 -0
- package/hooks/post_tool_use.py +54 -0
- package/hooks/pre_compact.py +60 -0
- package/hooks/pre_tool_use.py +413 -0
- package/hooks/session_start.py +81 -0
- package/hooks/stop_hook.py +82 -0
- package/hooks/subagent_start.py +71 -0
- package/hooks/subagent_stop.py +295 -0
- package/hooks/task_completed.py +70 -0
- package/hooks/user_prompt_submit.py +246 -0
- package/index.js +83 -0
- package/package.json +99 -0
- package/pyproject.toml +32 -0
- package/skills/README.md +154 -0
- package/skills/agent-protocol/SKILL.md +93 -0
- package/skills/agent-protocol/examples.md +223 -0
- package/skills/agent-response/SKILL.md +69 -0
- package/skills/agentic-loop/SKILL.md +80 -0
- package/skills/agentic-loop/reference.md +378 -0
- package/skills/blog-writing/SKILL.md +98 -0
- package/skills/blog-writing/reference.md +130 -0
- package/skills/brief-spec/SKILL.md +182 -0
- package/skills/command-execution/SKILL.md +64 -0
- package/skills/command-execution/reference.md +83 -0
- package/skills/context-updater/SKILL.md +87 -0
- package/skills/context-updater/examples.md +71 -0
- package/skills/developer-patterns/SKILL.md +50 -0
- package/skills/developer-patterns/reference.md +112 -0
- package/skills/execution/SKILL.md +99 -0
- package/skills/fast-queries/SKILL.md +43 -0
- package/skills/gaia-compact/SKILL.md +74 -0
- package/skills/gaia-patterns/SKILL.md +108 -0
- package/skills/gaia-patterns/reference.md +395 -0
- package/skills/gaia-planner/SKILL.md +37 -0
- package/skills/gaia-planner/reference.md +107 -0
- package/skills/gaia-release/SKILL.md +82 -0
- package/skills/gaia-release/reference.md +102 -0
- package/skills/gaia-self-check/SKILL.md +114 -0
- package/skills/gaia-self-check/reference.md +453 -0
- package/skills/gaia-verify/SKILL.md +77 -0
- package/skills/gaia-verify/reference.md +80 -0
- package/skills/git-conventions/SKILL.md +47 -0
- package/skills/gitops-patterns/SKILL.md +60 -0
- package/skills/gitops-patterns/reference.md +183 -0
- package/skills/gmail-policy/SKILL.md +200 -0
- package/skills/gmail-policy/reference.md +150 -0
- package/skills/gmail-triage/SKILL.md +100 -0
- package/skills/gws-setup/SKILL.md +99 -0
- package/skills/gws-setup/reference.md +73 -0
- package/skills/investigation/SKILL.md +100 -0
- package/skills/memory-curation/SKILL.md +83 -0
- package/skills/memory-search/SKILL.md +88 -0
- package/skills/orchestrator-approval/SKILL.md +160 -0
- package/skills/orchestrator-approval/reference.md +174 -0
- package/skills/pending-approvals/SKILL.md +72 -0
- package/skills/pending-approvals/reference.md +214 -0
- package/skills/readme-writing/SKILL.md +71 -0
- package/skills/readme-writing/reference.md +188 -0
- package/skills/reference.md +135 -0
- package/skills/request-approval/SKILL.md +140 -0
- package/skills/request-approval/examples.md +140 -0
- package/skills/request-approval/reference.md +57 -0
- package/skills/schedule-task/SKILL.md +64 -0
- package/skills/schedule-task/reference.md +233 -0
- package/skills/security-tiers/SKILL.md +141 -0
- package/skills/security-tiers/destructive-commands-reference.md +623 -0
- package/skills/security-tiers/reference.md +39 -0
- package/skills/skill-creation/SKILL.md +92 -0
- package/skills/skill-creation/reference.md +29 -0
- package/skills/terraform-patterns/SKILL.md +89 -0
- package/skills/terraform-patterns/reference.md +93 -0
- package/templates/README.md +69 -0
- package/templates/managed-settings.template.json +43 -0
- package/tools/__init__.py +9 -0
- package/tools/agentic-loop/decide-status.py +210 -0
- package/tools/agentic-loop/parse-metric.py +106 -0
- package/tools/agentic-loop/record-iteration.py +221 -0
- package/tools/context/README.md +132 -0
- package/tools/context/__init__.py +42 -0
- package/tools/context/_paths.py +20 -0
- package/tools/context/context_provider.py +721 -0
- package/tools/context/context_section_reader.py +342 -0
- package/tools/context/deep_merge.py +159 -0
- package/tools/context/pending_updates.py +760 -0
- package/tools/context/surface_router.py +278 -0
- package/tools/fast-queries/README.md +65 -0
- package/tools/fast-queries/__init__.py +30 -0
- package/tools/fast-queries/appservices/quicktriage_devops_developer.sh +75 -0
- package/tools/fast-queries/cloud/aws/quicktriage_aws_troubleshooter.sh +32 -0
- package/tools/fast-queries/cloud/gcp/quicktriage_gcp_troubleshooter.sh +88 -0
- package/tools/fast-queries/gitops/quicktriage_gitops_operator.sh +48 -0
- package/tools/fast-queries/run_triage.sh +59 -0
- package/tools/fast-queries/terraform/quicktriage_terraform_architect.sh +80 -0
- package/tools/gaia_simulator/__init__.py +33 -0
- package/tools/gaia_simulator/cli.py +354 -0
- package/tools/gaia_simulator/extractor.py +457 -0
- package/tools/gaia_simulator/reporter.py +258 -0
- package/tools/gaia_simulator/routing_simulator.py +334 -0
- package/tools/gaia_simulator/runner.py +539 -0
- package/tools/gaia_simulator/skills_mapper.py +264 -0
- package/tools/memory/README.md +0 -0
- package/tools/memory/__init__.py +20 -0
- package/tools/memory/backfill_fts5.py +107 -0
- package/tools/memory/conflict_detector.py +295 -0
- package/tools/memory/episodic.py +1210 -0
- package/tools/memory/git_invalidator.py +262 -0
- package/tools/memory/paths.py +102 -0
- package/tools/memory/scoring.py +193 -0
- package/tools/memory/search_store.py +360 -0
- package/tools/persist_transcript_analysis.py +85 -0
- package/tools/review/__init__.py +1 -0
- package/tools/review/review_engine.py +157 -0
- package/tools/scan/__init__.py +35 -0
- package/tools/scan/config.py +247 -0
- package/tools/scan/merge.py +212 -0
- package/tools/scan/orchestrator.py +549 -0
- package/tools/scan/registry.py +127 -0
- package/tools/scan/scanners/__init__.py +18 -0
- package/tools/scan/scanners/base.py +137 -0
- package/tools/scan/scanners/environment.py +349 -0
- package/tools/scan/scanners/git.py +570 -0
- package/tools/scan/scanners/infrastructure.py +875 -0
- package/tools/scan/scanners/orchestration.py +600 -0
- package/tools/scan/scanners/stack.py +1085 -0
- package/tools/scan/scanners/tools.py +260 -0
- package/tools/scan/setup.py +686 -0
- package/tools/scan/tests/__init__.py +1 -0
- package/tools/scan/tests/conftest.py +796 -0
- package/tools/scan/tests/test_environment.py +323 -0
- package/tools/scan/tests/test_git.py +419 -0
- package/tools/scan/tests/test_infrastructure.py +382 -0
- package/tools/scan/tests/test_integration.py +920 -0
- package/tools/scan/tests/test_merge.py +269 -0
- package/tools/scan/tests/test_orchestration.py +304 -0
- package/tools/scan/tests/test_stack.py +604 -0
- package/tools/scan/tests/test_tools.py +349 -0
- package/tools/scan/ui.py +624 -0
- package/tools/scan/verify.py +270 -0
- package/tools/scan/walk.py +118 -0
- package/tools/scan/workspace.py +85 -0
- package/tools/validation/README.md +244 -0
- package/tools/validation/__init__.py +17 -0
- package/tools/validation/approval_gate.py +321 -0
- package/tools/validation/validate_skills.py +189 -0
|
@@ -0,0 +1,610 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Pre-publish validation script for the gaia package
|
|
4
|
+
*
|
|
5
|
+
* Validates that changes work correctly before publishing to npm:
|
|
6
|
+
* 1. Checks for staged changes
|
|
7
|
+
* 2. Bumps package.json version (patch by default)
|
|
8
|
+
* 3. Runs npm install in the consuming project
|
|
9
|
+
* 4. Validates that changes are reflected in node_modules
|
|
10
|
+
* 5. Runs basic validation tests
|
|
11
|
+
* 6. Only then proceeds to publish
|
|
12
|
+
*
|
|
13
|
+
* Usage:
|
|
14
|
+
* node bin/pre-publish-validate.js [major|minor|patch]
|
|
15
|
+
* node bin/pre-publish-validate.js --dry-run
|
|
16
|
+
* node bin/pre-publish-validate.js --validate-only
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import fs from 'fs';
|
|
20
|
+
import path from 'path';
|
|
21
|
+
import { execSync } from 'child_process';
|
|
22
|
+
import chalk from 'chalk';
|
|
23
|
+
import { fileURLToPath } from 'url';
|
|
24
|
+
import { findPython } from './python-detect.js';
|
|
25
|
+
|
|
26
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
27
|
+
const __dirname = path.dirname(__filename);
|
|
28
|
+
|
|
29
|
+
// Detectar gaia root buscando package.json (lee el nombre dinámicamente)
|
|
30
|
+
function detectGaiaRoot(startPath) {
|
|
31
|
+
let currentPath = startPath;
|
|
32
|
+
|
|
33
|
+
while (currentPath !== path.dirname(currentPath)) { // hasta raíz
|
|
34
|
+
const packageJsonPath = path.join(currentPath, 'package.json');
|
|
35
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
36
|
+
const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
37
|
+
// Accept any @jaguilar87/* package (decouples validator from exact name)
|
|
38
|
+
if (pkg.name && pkg.name.startsWith('@jaguilar87/')) {
|
|
39
|
+
return { root: currentPath, name: pkg.name };
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
currentPath = path.dirname(currentPath);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
throw new Error('Could not find @jaguilar87/* package.json walking up from ' + startPath);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Buscar node_modules de múltiples maneras
|
|
49
|
+
function findNodeModulesPath(gaiaRoot, pkgName) {
|
|
50
|
+
const [scope, name] = pkgName.split('/');
|
|
51
|
+
const candidates = [
|
|
52
|
+
path.resolve(gaiaRoot, 'node_modules'), // ./node_modules (CI: npm ci in repo root)
|
|
53
|
+
path.resolve(gaiaRoot, '..', 'node_modules'), // ../node_modules (monorepo consumer)
|
|
54
|
+
path.resolve(process.cwd(), 'node_modules'), // cwd/node_modules
|
|
55
|
+
path.join(gaiaRoot, '..', '..', 'node_modules'), // ../../node_modules (deep nesting)
|
|
56
|
+
];
|
|
57
|
+
|
|
58
|
+
for (const candidate of candidates) {
|
|
59
|
+
const gaiaPath = path.join(candidate, scope, name);
|
|
60
|
+
if (fs.existsSync(gaiaPath)) {
|
|
61
|
+
return candidate;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// In CI, node_modules exists inside the repo root (npm ci) but won't contain
|
|
66
|
+
// the package itself as a nested dependency. Prefer gaiaRoot/node_modules
|
|
67
|
+
// over going up a level (which breaks in CI checkout structures).
|
|
68
|
+
const localNodeModules = path.resolve(gaiaRoot, 'node_modules');
|
|
69
|
+
if (fs.existsSync(localNodeModules)) {
|
|
70
|
+
return localNodeModules;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Fallback: use __dirname-relative path (repo root) instead of process.cwd()
|
|
74
|
+
return path.resolve(gaiaRoot, 'node_modules');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const { root: GAIA_OPS_ROOT, name: PKG_NAME } = detectGaiaRoot(path.resolve(__dirname, '..'));
|
|
78
|
+
const [PKG_SCOPE, PKG_SHORT] = PKG_NAME.split('/');
|
|
79
|
+
const NODE_MODULES_BASE = findNodeModulesPath(GAIA_OPS_ROOT, PKG_NAME);
|
|
80
|
+
const MONOREPO_ROOT = path.resolve(NODE_MODULES_BASE, '..');
|
|
81
|
+
const NODE_MODULES_INSTALL = path.resolve(NODE_MODULES_BASE, PKG_SCOPE, PKG_SHORT);
|
|
82
|
+
|
|
83
|
+
class PrePublishValidator {
|
|
84
|
+
constructor(options = {}) {
|
|
85
|
+
this.dryRun = options.dryRun || false;
|
|
86
|
+
this.validateOnly = options.validateOnly || false;
|
|
87
|
+
this.versionBump = options.versionBump || 'patch';
|
|
88
|
+
this.currentVersion = null;
|
|
89
|
+
this.newVersion = null;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
log(message, level = 'info') {
|
|
93
|
+
const timestamp = new Date().toLocaleTimeString();
|
|
94
|
+
const prefix = `[${timestamp}]`;
|
|
95
|
+
|
|
96
|
+
switch (level) {
|
|
97
|
+
case 'error':
|
|
98
|
+
console.error(chalk.red(`${prefix} ✗ ${message}`));
|
|
99
|
+
break;
|
|
100
|
+
case 'success':
|
|
101
|
+
console.log(chalk.green(`${prefix} ✓ ${message}`));
|
|
102
|
+
break;
|
|
103
|
+
case 'warning':
|
|
104
|
+
console.warn(chalk.yellow(`${prefix} ⚠️ ${message}`));
|
|
105
|
+
break;
|
|
106
|
+
case 'info':
|
|
107
|
+
console.log(chalk.blue(`${prefix} ℹ️ ${message}`));
|
|
108
|
+
break;
|
|
109
|
+
default:
|
|
110
|
+
console.log(message);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
execute(command, cwd = GAIA_OPS_ROOT, silent = false) {
|
|
115
|
+
try {
|
|
116
|
+
if (!silent) {
|
|
117
|
+
this.log(`Running: ${command}`, 'info');
|
|
118
|
+
}
|
|
119
|
+
const result = execSync(command, { cwd, encoding: 'utf-8' });
|
|
120
|
+
if (!silent) {
|
|
121
|
+
this.log(`Command completed`, 'success');
|
|
122
|
+
}
|
|
123
|
+
return result;
|
|
124
|
+
} catch (error) {
|
|
125
|
+
this.log(`Command failed: ${error.message}`, 'error');
|
|
126
|
+
throw error;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
validateGitStatus() {
|
|
131
|
+
this.log('Step 1: Validating git status...', 'info');
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
const status = this.execute('git status --porcelain', GAIA_OPS_ROOT, true);
|
|
135
|
+
|
|
136
|
+
if (!status.trim()) {
|
|
137
|
+
this.log('✓ No uncommitted changes - working tree clean', 'success');
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const lines = status.trim().split('\n');
|
|
142
|
+
this.log(`Found ${lines.length} uncommitted changes:`, 'warning');
|
|
143
|
+
lines.forEach(line => console.log(` ${line}`));
|
|
144
|
+
|
|
145
|
+
if (!this.dryRun && !this.validateOnly) {
|
|
146
|
+
this.log('Proceeding with validation (changes will be committed after validation)', 'info');
|
|
147
|
+
}
|
|
148
|
+
return true;
|
|
149
|
+
} catch (error) {
|
|
150
|
+
this.log('Failed to check git status', 'error');
|
|
151
|
+
throw error;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
readCurrentVersion() {
|
|
156
|
+
this.log('Step 2: Reading current version...', 'info');
|
|
157
|
+
|
|
158
|
+
const packageJsonPath = path.join(GAIA_OPS_ROOT, 'package.json');
|
|
159
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
160
|
+
this.currentVersion = packageJson.version;
|
|
161
|
+
|
|
162
|
+
this.log(`Current version: ${this.currentVersion}`, 'success');
|
|
163
|
+
return this.currentVersion;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
bumpVersion() {
|
|
167
|
+
this.log(`Step 3: Bumping version (${this.versionBump})...`, 'info');
|
|
168
|
+
|
|
169
|
+
// Handle prerelease versions (e.g., 4.4.0-beta.7)
|
|
170
|
+
const prereleaseMatch = this.currentVersion.match(/^(.+)-(.+)\.(\d+)$/);
|
|
171
|
+
if (prereleaseMatch) {
|
|
172
|
+
const [, baseVersion, prereleaseTag, prereleaseNum] = prereleaseMatch;
|
|
173
|
+
this.newVersion = `${baseVersion}-${prereleaseTag}.${parseInt(prereleaseNum) + 1}`;
|
|
174
|
+
} else {
|
|
175
|
+
const parts = this.currentVersion.split('.');
|
|
176
|
+
|
|
177
|
+
switch (this.versionBump) {
|
|
178
|
+
case 'major':
|
|
179
|
+
parts[0] = String(parseInt(parts[0]) + 1);
|
|
180
|
+
parts[1] = '0';
|
|
181
|
+
parts[2] = '0';
|
|
182
|
+
break;
|
|
183
|
+
case 'minor':
|
|
184
|
+
parts[1] = String(parseInt(parts[1]) + 1);
|
|
185
|
+
parts[2] = '0';
|
|
186
|
+
break;
|
|
187
|
+
case 'patch':
|
|
188
|
+
default:
|
|
189
|
+
parts[2] = String(parseInt(parts[2]) + 1);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
this.newVersion = parts.join('.');
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (this.dryRun) {
|
|
196
|
+
this.log(`[DRY RUN] Would bump version to: ${this.newVersion}`, 'info');
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const packageJsonPath = path.join(GAIA_OPS_ROOT, 'package.json');
|
|
201
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
202
|
+
packageJson.version = this.newVersion;
|
|
203
|
+
fs.writeFileSync(packageJsonPath, JSON.stringify(packageJson, null, 2) + '\n');
|
|
204
|
+
|
|
205
|
+
this.log(`Version bumped: ${this.currentVersion} → ${this.newVersion}`, 'success');
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
validateNodeModules() {
|
|
209
|
+
this.log('Step 4: Validating node_modules installation...', 'info');
|
|
210
|
+
|
|
211
|
+
if (!fs.existsSync(NODE_MODULES_INSTALL)) {
|
|
212
|
+
this.log(`⚠️ ${PKG_NAME} not found in node_modules, installing...`, 'warning');
|
|
213
|
+
this.reinstallNodeModules();
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const installedPackageJson = path.join(NODE_MODULES_INSTALL, 'package.json');
|
|
217
|
+
if (!fs.existsSync(installedPackageJson)) {
|
|
218
|
+
this.log('✗ node_modules installation is invalid', 'error');
|
|
219
|
+
throw new Error('node_modules installation failed');
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const installedPkg = JSON.parse(fs.readFileSync(installedPackageJson, 'utf-8'));
|
|
223
|
+
const expectedVersion = this.newVersion || this.currentVersion;
|
|
224
|
+
|
|
225
|
+
if (installedPkg.version !== expectedVersion) {
|
|
226
|
+
this.log(`✗ Version mismatch: expected ${expectedVersion}, got ${installedPkg.version}`, 'error');
|
|
227
|
+
throw new Error('Version mismatch in node_modules');
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
this.log(`✓ node_modules version matches: ${expectedVersion}`, 'success');
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
reinstallNodeModules() {
|
|
234
|
+
this.log('Reinstalling node_modules...', 'info');
|
|
235
|
+
|
|
236
|
+
if (this.dryRun) {
|
|
237
|
+
this.log('[DRY RUN] Would run: npm install', 'info');
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
// In CI, MONOREPO_ROOT may resolve incorrectly (one level above checkout).
|
|
242
|
+
// Use GAIA_OPS_ROOT if it contains a package.json (i.e., we ARE the root).
|
|
243
|
+
const installDir = fs.existsSync(path.join(GAIA_OPS_ROOT, 'package-lock.json'))
|
|
244
|
+
? GAIA_OPS_ROOT
|
|
245
|
+
: MONOREPO_ROOT;
|
|
246
|
+
|
|
247
|
+
this.log(`Install directory: ${installDir}`, 'info');
|
|
248
|
+
this.execute('npm install', installDir);
|
|
249
|
+
this.log('✓ npm install completed', 'success');
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
validateFiles() {
|
|
253
|
+
this.log('Step 5: Validating key files...', 'info');
|
|
254
|
+
|
|
255
|
+
const criticalFiles = [
|
|
256
|
+
'package.json',
|
|
257
|
+
'bin/gaia-scan',
|
|
258
|
+
'tools/context/context_provider.py',
|
|
259
|
+
'hooks/pre_tool_use.py',
|
|
260
|
+
];
|
|
261
|
+
|
|
262
|
+
let allValid = true;
|
|
263
|
+
|
|
264
|
+
criticalFiles.forEach(file => {
|
|
265
|
+
const sourcePath = path.join(GAIA_OPS_ROOT, file);
|
|
266
|
+
const installedPath = path.join(NODE_MODULES_INSTALL, file);
|
|
267
|
+
|
|
268
|
+
if (!fs.existsSync(sourcePath)) {
|
|
269
|
+
this.log(`✗ Source file missing: ${file}`, 'warning');
|
|
270
|
+
allValid = false;
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (!fs.existsSync(installedPath)) {
|
|
275
|
+
this.log(`✗ Installed file missing: ${file}`, 'warning');
|
|
276
|
+
allValid = false;
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
// Compare file hashes
|
|
281
|
+
const sourceContent = fs.readFileSync(sourcePath, 'utf-8');
|
|
282
|
+
const installedContent = fs.readFileSync(installedPath, 'utf-8');
|
|
283
|
+
|
|
284
|
+
if (sourceContent === installedContent) {
|
|
285
|
+
this.log(`✓ ${file}`, 'success');
|
|
286
|
+
} else {
|
|
287
|
+
this.log(`⚠️ ${file} differs (this is normal after version bump)`, 'warning');
|
|
288
|
+
}
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
if (!allValid) {
|
|
292
|
+
throw new Error('Some critical files are missing');
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
validatePluginManifest() {
|
|
297
|
+
this.log('Step 6: Validating plugin manifest (.claude-plugin/plugin.json)...', 'info');
|
|
298
|
+
|
|
299
|
+
const pluginJsonPath = path.join(GAIA_OPS_ROOT, '.claude-plugin', 'plugin.json');
|
|
300
|
+
|
|
301
|
+
// 1. File existence
|
|
302
|
+
if (!fs.existsSync(pluginJsonPath)) {
|
|
303
|
+
this.log('✗ .claude-plugin/plugin.json does not exist', 'error');
|
|
304
|
+
throw new Error('Plugin manifest missing: .claude-plugin/plugin.json');
|
|
305
|
+
}
|
|
306
|
+
this.log('✓ .claude-plugin/plugin.json exists', 'success');
|
|
307
|
+
|
|
308
|
+
const pluginData = JSON.parse(fs.readFileSync(pluginJsonPath, 'utf-8'));
|
|
309
|
+
|
|
310
|
+
// 2. Version sync with package.json
|
|
311
|
+
const packageJsonPath = path.join(GAIA_OPS_ROOT, 'package.json');
|
|
312
|
+
const packageData = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
313
|
+
const expectedVersion = this.newVersion || packageData.version;
|
|
314
|
+
|
|
315
|
+
if (pluginData.version !== expectedVersion) {
|
|
316
|
+
this.log(`✗ plugin.json version "${pluginData.version}" does not match package.json version "${expectedVersion}"`, 'error');
|
|
317
|
+
throw new Error(`Plugin manifest version mismatch: plugin.json="${pluginData.version}" vs package.json="${expectedVersion}"`);
|
|
318
|
+
}
|
|
319
|
+
this.log(`✓ plugin.json version matches package.json (${expectedVersion})`, 'success');
|
|
320
|
+
|
|
321
|
+
// 3. Engines field
|
|
322
|
+
const claudeCodeEngine = pluginData.engines && pluginData.engines['claude-code'];
|
|
323
|
+
if (!claudeCodeEngine || claudeCodeEngine !== '>=2.1.0') {
|
|
324
|
+
this.log(`✗ plugin.json engines["claude-code"] must be ">=2.1.0", got "${claudeCodeEngine || 'missing'}"`, 'error');
|
|
325
|
+
throw new Error(`Plugin manifest missing or invalid engines["claude-code"]: expected ">=2.1.0", got "${claudeCodeEngine || 'missing'}"`);
|
|
326
|
+
}
|
|
327
|
+
this.log('✓ plugin.json engines["claude-code"] is ">=2.1.0"', 'success');
|
|
328
|
+
|
|
329
|
+
// 4. Categories field
|
|
330
|
+
const requiredCategories = ['devops', 'security', 'orchestration'];
|
|
331
|
+
const categories = pluginData.categories || [];
|
|
332
|
+
const missingCategories = requiredCategories.filter(cat => !categories.includes(cat));
|
|
333
|
+
|
|
334
|
+
if (missingCategories.length > 0) {
|
|
335
|
+
this.log(`✗ plugin.json categories missing: ${missingCategories.join(', ')} (found: [${categories.join(', ')}])`, 'error');
|
|
336
|
+
throw new Error(`Plugin manifest categories incomplete: missing ${missingCategories.join(', ')}`);
|
|
337
|
+
}
|
|
338
|
+
this.log(`✓ plugin.json categories include all required: ${requiredCategories.join(', ')}`, 'success');
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
runTests() {
|
|
342
|
+
this.log('Step 7: Running validation tests...', 'info');
|
|
343
|
+
|
|
344
|
+
// In validate-only mode, validate source files directly
|
|
345
|
+
const baseDir = this.validateOnly ? GAIA_OPS_ROOT : NODE_MODULES_INSTALL;
|
|
346
|
+
|
|
347
|
+
try {
|
|
348
|
+
// Test 1: Validate JSON files
|
|
349
|
+
this.log('Test 1: Validating JSON configuration files...', 'info');
|
|
350
|
+
const jsonFiles = [
|
|
351
|
+
'config/clarification_rules.json',
|
|
352
|
+
'config/git_standards.json'
|
|
353
|
+
];
|
|
354
|
+
|
|
355
|
+
jsonFiles.forEach(file => {
|
|
356
|
+
const filePath = path.join(baseDir, file);
|
|
357
|
+
if (fs.existsSync(filePath)) {
|
|
358
|
+
try {
|
|
359
|
+
JSON.parse(fs.readFileSync(filePath, 'utf-8'));
|
|
360
|
+
this.log(` ✓ ${file}`, 'success');
|
|
361
|
+
} catch (error) {
|
|
362
|
+
this.log(` ✗ ${file}: ${error.message}`, 'error');
|
|
363
|
+
throw error;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
// Test 2: Validate Python syntax (if Python is available)
|
|
369
|
+
this.log('Test 2: Validating Python files syntax...', 'info');
|
|
370
|
+
try {
|
|
371
|
+
const pythonFiles = [
|
|
372
|
+
'hooks/pre_tool_use.py',
|
|
373
|
+
'hooks/post_tool_use.py',
|
|
374
|
+
'hooks/modules/validation/commit_validator.py',
|
|
375
|
+
'tools/context/context_provider.py'
|
|
376
|
+
];
|
|
377
|
+
|
|
378
|
+
const pyCmd = findPython();
|
|
379
|
+
if (!pyCmd) throw new Error('Python not available');
|
|
380
|
+
pythonFiles.forEach(file => {
|
|
381
|
+
const filePath = path.join(baseDir, file);
|
|
382
|
+
if (fs.existsSync(filePath)) {
|
|
383
|
+
this.execute(`${pyCmd} -m py_compile "${filePath}"`, GAIA_OPS_ROOT, true);
|
|
384
|
+
this.log(` ✓ ${file}`, 'success');
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
} catch (error) {
|
|
388
|
+
this.log(` ⚠️ Python validation skipped (python3/python not available or syntax error)`, 'warning');
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
// Test 3: Check if bin scripts are executable
|
|
392
|
+
this.log('Test 3: Checking bin scripts...', 'info');
|
|
393
|
+
const binDir = path.join(baseDir, 'bin');
|
|
394
|
+
if (fs.existsSync(binDir)) {
|
|
395
|
+
const scripts = fs.readdirSync(binDir);
|
|
396
|
+
this.log(` ✓ Found ${scripts.length} bin scripts`, 'success');
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Test 4: Version sync across all manifest files
|
|
400
|
+
this.log('Test 4: Validating version sync across manifests...', 'info');
|
|
401
|
+
const packageJsonPath = path.join(baseDir, 'package.json');
|
|
402
|
+
const packageJsonData = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
403
|
+
const expectedVersion = this.newVersion || packageJsonData.version;
|
|
404
|
+
const versionMismatches = [];
|
|
405
|
+
|
|
406
|
+
// Check .claude-plugin/plugin.json
|
|
407
|
+
const pluginJsonPath = path.join(baseDir, '.claude-plugin', 'plugin.json');
|
|
408
|
+
if (fs.existsSync(pluginJsonPath)) {
|
|
409
|
+
const pluginData = JSON.parse(fs.readFileSync(pluginJsonPath, 'utf-8'));
|
|
410
|
+
if (pluginData.version !== expectedVersion) {
|
|
411
|
+
versionMismatches.push(`plugin.json: ${pluginData.version}`);
|
|
412
|
+
} else {
|
|
413
|
+
this.log(` ✓ .claude-plugin/plugin.json version matches`, 'success');
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// Check .claude-plugin/marketplace.json plugin versions
|
|
418
|
+
const marketplacePath = path.join(baseDir, '.claude-plugin', 'marketplace.json');
|
|
419
|
+
if (fs.existsSync(marketplacePath)) {
|
|
420
|
+
const marketplaceData = JSON.parse(fs.readFileSync(marketplacePath, 'utf-8'));
|
|
421
|
+
for (const plugin of (marketplaceData.plugins || [])) {
|
|
422
|
+
if (plugin.version !== expectedVersion) {
|
|
423
|
+
versionMismatches.push(`marketplace/${plugin.name}: ${plugin.version}`);
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
if (!versionMismatches.some(m => m.startsWith('marketplace/'))) {
|
|
427
|
+
this.log(` ✓ marketplace.json plugin versions match`, 'success');
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
// Check sub-plugin plugin.json files
|
|
432
|
+
const subPlugins = [
|
|
433
|
+
{ name: 'gaia-security', path: path.join(baseDir, 'plugins', 'gaia-security', '.claude-plugin', 'plugin.json') },
|
|
434
|
+
{ name: 'gaia-ops', path: path.join(baseDir, 'plugins', 'gaia-ops', '.claude-plugin', 'plugin.json') }
|
|
435
|
+
];
|
|
436
|
+
|
|
437
|
+
for (const subPlugin of subPlugins) {
|
|
438
|
+
if (fs.existsSync(subPlugin.path)) {
|
|
439
|
+
const subData = JSON.parse(fs.readFileSync(subPlugin.path, 'utf-8'));
|
|
440
|
+
if (subData.version !== expectedVersion) {
|
|
441
|
+
versionMismatches.push(`${subPlugin.name}/plugin.json: ${subData.version}`);
|
|
442
|
+
} else {
|
|
443
|
+
this.log(` ✓ ${subPlugin.name}/plugin.json version matches`, 'success');
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
// Check pyproject.toml [project].version
|
|
449
|
+
const pyprojectPath = path.join(baseDir, 'pyproject.toml');
|
|
450
|
+
if (fs.existsSync(pyprojectPath)) {
|
|
451
|
+
const pyprojectText = fs.readFileSync(pyprojectPath, 'utf-8');
|
|
452
|
+
// Match the first `version = "..."` after [project] section header.
|
|
453
|
+
// Simple parser: find [project] block, then the version line within it.
|
|
454
|
+
const projectSectionMatch = pyprojectText.match(/\[project\]([\s\S]*?)(?:\n\[|$)/);
|
|
455
|
+
if (projectSectionMatch) {
|
|
456
|
+
const versionMatch = projectSectionMatch[1].match(/^\s*version\s*=\s*["']([^"']+)["']/m);
|
|
457
|
+
if (versionMatch) {
|
|
458
|
+
const pyVersion = versionMatch[1];
|
|
459
|
+
if (pyVersion !== expectedVersion) {
|
|
460
|
+
versionMismatches.push(`pyproject.toml: ${pyVersion}`);
|
|
461
|
+
} else {
|
|
462
|
+
this.log(` ✓ pyproject.toml version matches`, 'success');
|
|
463
|
+
}
|
|
464
|
+
} else {
|
|
465
|
+
this.log(` ⚠️ pyproject.toml [project].version not found — skipping`, 'warning');
|
|
466
|
+
}
|
|
467
|
+
} else {
|
|
468
|
+
this.log(` ⚠️ pyproject.toml [project] section not found — skipping`, 'warning');
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Check CHANGELOG.md top-most version header
|
|
473
|
+
const changelogPath = path.join(baseDir, 'CHANGELOG.md');
|
|
474
|
+
if (fs.existsSync(changelogPath)) {
|
|
475
|
+
const changelogText = fs.readFileSync(changelogPath, 'utf-8');
|
|
476
|
+
// Find the first `## [x.y.z...]` header, skipping `## [Unreleased]`.
|
|
477
|
+
const headerRegex = /^##\s*\[([^\]]+)\]/gm;
|
|
478
|
+
let match;
|
|
479
|
+
let topVersion = null;
|
|
480
|
+
while ((match = headerRegex.exec(changelogText)) !== null) {
|
|
481
|
+
const header = match[1].trim();
|
|
482
|
+
if (header.toLowerCase() === 'unreleased') continue;
|
|
483
|
+
topVersion = header;
|
|
484
|
+
break;
|
|
485
|
+
}
|
|
486
|
+
if (topVersion) {
|
|
487
|
+
if (topVersion !== expectedVersion) {
|
|
488
|
+
versionMismatches.push(`CHANGELOG.md top: ${topVersion}`);
|
|
489
|
+
} else {
|
|
490
|
+
this.log(` ✓ CHANGELOG.md top version matches`, 'success');
|
|
491
|
+
}
|
|
492
|
+
} else {
|
|
493
|
+
this.log(` ⚠️ CHANGELOG.md has no versioned header — skipping`, 'warning');
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
if (versionMismatches.length > 0) {
|
|
498
|
+
const sources = [
|
|
499
|
+
`package.json=${expectedVersion}`,
|
|
500
|
+
...versionMismatches.map(m => m.replace(/: /, '=')),
|
|
501
|
+
];
|
|
502
|
+
this.log(`✗ Version drift detected. Align all sources before publish: ${sources.join(', ')}`, 'error');
|
|
503
|
+
throw new Error(
|
|
504
|
+
`Version drift: ${sources.join(', ')} — align all sources (package.json, plugin.json, marketplace.json, sub-plugin manifests, pyproject.toml, CHANGELOG.md top) before publish`
|
|
505
|
+
);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
} catch (error) {
|
|
509
|
+
this.log('Tests failed', 'error');
|
|
510
|
+
throw error;
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
summary() {
|
|
515
|
+
console.log('\n' + '='.repeat(70));
|
|
516
|
+
this.log('PRE-PUBLISH VALIDATION SUMMARY', 'info');
|
|
517
|
+
console.log('='.repeat(70));
|
|
518
|
+
|
|
519
|
+
console.log(`
|
|
520
|
+
┌─ Path Detection
|
|
521
|
+
│ package: ${PKG_NAME}
|
|
522
|
+
│ repo root: ${GAIA_OPS_ROOT}
|
|
523
|
+
│ node_modules: ${NODE_MODULES_BASE}
|
|
524
|
+
│ monorepo root: ${MONOREPO_ROOT}
|
|
525
|
+
│ installed path: ${NODE_MODULES_INSTALL}
|
|
526
|
+
│
|
|
527
|
+
├─ Version Info
|
|
528
|
+
│ Current: ${this.currentVersion}
|
|
529
|
+
│ ${this.newVersion ? `New: ${this.newVersion}` : ' (No change)'}
|
|
530
|
+
│
|
|
531
|
+
└─ Options
|
|
532
|
+
Dry Run: ${this.dryRun ? 'YES' : 'NO'}
|
|
533
|
+
Validate Only: ${this.validateOnly ? 'YES' : 'NO'}
|
|
534
|
+
`);
|
|
535
|
+
|
|
536
|
+
console.log('='.repeat(70));
|
|
537
|
+
|
|
538
|
+
if (this.validateOnly) {
|
|
539
|
+
this.log('✓ Validation completed successfully (--validate-only mode)', 'success');
|
|
540
|
+
} else if (this.dryRun) {
|
|
541
|
+
this.log('✓ Dry run completed - no changes made', 'success');
|
|
542
|
+
this.log('To proceed with actual validation, run without --dry-run flag', 'info');
|
|
543
|
+
} else {
|
|
544
|
+
this.log('✓ All validations passed!', 'success');
|
|
545
|
+
this.log('Ready to publish with: npm publish', 'info');
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
async run() {
|
|
550
|
+
try {
|
|
551
|
+
this.log('Starting pre-publish validation...', 'info');
|
|
552
|
+
this.log(`Detected paths: pkg=${PKG_NAME} root=${path.basename(GAIA_OPS_ROOT)}, monorepo=${path.basename(MONOREPO_ROOT)}`, 'info');
|
|
553
|
+
console.log('');
|
|
554
|
+
|
|
555
|
+
this.validateGitStatus();
|
|
556
|
+
this.readCurrentVersion();
|
|
557
|
+
|
|
558
|
+
if (!this.validateOnly) {
|
|
559
|
+
this.bumpVersion();
|
|
560
|
+
this.reinstallNodeModules();
|
|
561
|
+
this.validateNodeModules();
|
|
562
|
+
this.validateFiles();
|
|
563
|
+
}
|
|
564
|
+
this.validatePluginManifest();
|
|
565
|
+
this.runTests();
|
|
566
|
+
|
|
567
|
+
this.summary();
|
|
568
|
+
|
|
569
|
+
return true;
|
|
570
|
+
} catch (error) {
|
|
571
|
+
console.log('\n' + '='.repeat(70));
|
|
572
|
+
this.log('VALIDATION FAILED', 'error');
|
|
573
|
+
console.log('='.repeat(70));
|
|
574
|
+
this.log(error.message, 'error');
|
|
575
|
+
process.exit(1);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Parse command line arguments and run
|
|
581
|
+
async function main() {
|
|
582
|
+
const args = process.argv.slice(2);
|
|
583
|
+
const isCI = process.env.CI === 'true' || process.env.GITHUB_ACTIONS === 'true';
|
|
584
|
+
|
|
585
|
+
const options = {
|
|
586
|
+
dryRun: args.includes('--dry-run'),
|
|
587
|
+
validateOnly: args.includes('--validate-only') || isCI,
|
|
588
|
+
versionBump: 'patch'
|
|
589
|
+
};
|
|
590
|
+
|
|
591
|
+
if (isCI && !args.includes('--validate-only')) {
|
|
592
|
+
console.log(chalk.blue(
|
|
593
|
+
'[CI] Auto-enabling --validate-only: ' +
|
|
594
|
+
'self-install validation is not possible during npm publish ' +
|
|
595
|
+
'(package is not yet on the registry).'
|
|
596
|
+
));
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
if (args.includes('major')) options.versionBump = 'major';
|
|
600
|
+
if (args.includes('minor')) options.versionBump = 'minor';
|
|
601
|
+
if (args.includes('patch')) options.versionBump = 'patch';
|
|
602
|
+
|
|
603
|
+
const validator = new PrePublishValidator(options);
|
|
604
|
+
await validator.run();
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
main().catch(err => {
|
|
608
|
+
console.error(chalk.red('Fatal error:', err.message));
|
|
609
|
+
process.exit(1);
|
|
610
|
+
});
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-platform Python 3 detection.
|
|
3
|
+
*
|
|
4
|
+
* On Linux/macOS the binary is typically `python3`.
|
|
5
|
+
* On Windows it is often just `python` (the Microsoft Store alias
|
|
6
|
+
* or the official installer both register `python`).
|
|
7
|
+
*
|
|
8
|
+
* This module tries each candidate in order and returns the first
|
|
9
|
+
* one that reports Python 3.x. The result is cached for the
|
|
10
|
+
* lifetime of the process so repeated calls are free.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { execSync, execFileSync } from 'child_process';
|
|
14
|
+
|
|
15
|
+
/** @type {string | null | undefined} */
|
|
16
|
+
let _cached;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Detect a working Python 3 command.
|
|
20
|
+
*
|
|
21
|
+
* @returns {string | null} The command name ('python3' or 'python'),
|
|
22
|
+
* or null if no Python 3 was found.
|
|
23
|
+
*/
|
|
24
|
+
export function findPython() {
|
|
25
|
+
if (_cached !== undefined) return _cached;
|
|
26
|
+
|
|
27
|
+
for (const cmd of ['python3', 'python']) {
|
|
28
|
+
try {
|
|
29
|
+
const version = execFileSync(cmd, ['--version'], {
|
|
30
|
+
encoding: 'utf8',
|
|
31
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
32
|
+
timeout: 5000,
|
|
33
|
+
}).trim();
|
|
34
|
+
if (version.startsWith('Python 3.')) {
|
|
35
|
+
_cached = cmd;
|
|
36
|
+
return _cached;
|
|
37
|
+
}
|
|
38
|
+
} catch {
|
|
39
|
+
// Not found or not Python 3 -- try next candidate
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
_cached = null;
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Return the Python command or throw with a helpful message.
|
|
49
|
+
*
|
|
50
|
+
* @returns {string}
|
|
51
|
+
*/
|
|
52
|
+
export function requirePython() {
|
|
53
|
+
const cmd = findPython();
|
|
54
|
+
if (!cmd) {
|
|
55
|
+
throw new Error(
|
|
56
|
+
'Python 3 not found. Install Python 3.9+ and ensure "python3" or "python" is on PATH.'
|
|
57
|
+
);
|
|
58
|
+
}
|
|
59
|
+
return cmd;
|
|
60
|
+
}
|