@trac3er/oh-my-god 2.1.0 → 2.1.4
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/.agents/skills/omg/AGENTS.fragment.md +2 -2
- package/.agents/skills/omg/algorithms/SKILL.md +1 -1
- package/.agents/skills/omg/algorithms/openai.yaml +1 -1
- package/.agents/skills/omg/api-twin/SKILL.md +1 -1
- package/.agents/skills/omg/api-twin/openai.yaml +1 -1
- package/.agents/skills/omg/claim-judge/SKILL.md +1 -1
- package/.agents/skills/omg/claim-judge/openai.yaml +1 -1
- package/.agents/skills/omg/codex-rules.md +1 -1
- package/.agents/skills/omg/control-plane/SKILL.md +1 -1
- package/.agents/skills/omg/control-plane/openai.yaml +1 -1
- package/.agents/skills/omg/data-lineage/SKILL.md +1 -1
- package/.agents/skills/omg/data-lineage/openai.yaml +1 -1
- package/.agents/skills/omg/delta-classifier/SKILL.md +1 -1
- package/.agents/skills/omg/delta-classifier/openai.yaml +1 -1
- package/.agents/skills/omg/eval-gate/SKILL.md +1 -1
- package/.agents/skills/omg/eval-gate/openai.yaml +1 -1
- package/.agents/skills/omg/health/SKILL.md +1 -1
- package/.agents/skills/omg/health/openai.yaml +1 -1
- package/.agents/skills/omg/hook-governor/SKILL.md +1 -1
- package/.agents/skills/omg/hook-governor/openai.yaml +1 -1
- package/.agents/skills/omg/incident-replay/SKILL.md +1 -1
- package/.agents/skills/omg/incident-replay/openai.yaml +1 -1
- package/.agents/skills/omg/lsp-pack/SKILL.md +1 -1
- package/.agents/skills/omg/lsp-pack/openai.yaml +1 -1
- package/.agents/skills/omg/mcp-fabric/SKILL.md +1 -1
- package/.agents/skills/omg/mcp-fabric/openai.yaml +1 -1
- package/.agents/skills/omg/plan-council/SKILL.md +1 -1
- package/.agents/skills/omg/plan-council/openai.yaml +1 -1
- package/.agents/skills/omg/preflight/SKILL.md +1 -1
- package/.agents/skills/omg/preflight/openai.yaml +1 -1
- package/.agents/skills/omg/proof-gate/SKILL.md +1 -1
- package/.agents/skills/omg/proof-gate/openai.yaml +1 -1
- package/.agents/skills/omg/remote-supervisor/SKILL.md +1 -1
- package/.agents/skills/omg/remote-supervisor/openai.yaml +1 -1
- package/.agents/skills/omg/robotics/SKILL.md +1 -1
- package/.agents/skills/omg/robotics/openai.yaml +1 -1
- package/.agents/skills/omg/secure-worktree-pipeline/SKILL.md +1 -1
- package/.agents/skills/omg/secure-worktree-pipeline/openai.yaml +1 -1
- package/.agents/skills/omg/security-check/SKILL.md +1 -1
- package/.agents/skills/omg/security-check/openai.yaml +1 -1
- package/.agents/skills/omg/test-intent-lock/SKILL.md +1 -1
- package/.agents/skills/omg/test-intent-lock/openai.yaml +1 -1
- package/.agents/skills/omg/tracebank/SKILL.md +1 -1
- package/.agents/skills/omg/tracebank/openai.yaml +1 -1
- package/.agents/skills/omg/vision/SKILL.md +1 -1
- package/.agents/skills/omg/vision/openai.yaml +1 -1
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +16 -0
- package/CLI-ADAPTER-MAP.md +3 -3
- package/OMG-setup.sh +114 -1
- package/OMG_COMPAT_CONTRACT.md +1 -1
- package/README.md +2 -1
- package/artifacts/release/.claude-plugin/marketplace.json +3 -3
- package/artifacts/release/.claude-plugin/plugin.json +1 -1
- package/artifacts/release/OMG_COMPAT_CONTRACT.md +1 -1
- package/artifacts/release/dist/enterprise/bundle/.claude-plugin/marketplace.json +3 -3
- package/artifacts/release/dist/enterprise/bundle/.claude-plugin/plugin.json +1 -1
- package/artifacts/release/dist/enterprise/bundle/OMG_COMPAT_CONTRACT.md +1 -1
- package/artifacts/release/dist/enterprise/bundle/plugins/advanced/plugin.json +26 -9
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/algorithms.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/api-twin.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/claim-judge.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/control-plane.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/data-lineage.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/delta-classifier.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/eval-gate.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/health.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/hook-governor.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/incident-replay.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/lsp-pack.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/mcp-fabric.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/plan-council.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/preflight.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/proof-gate.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/remote-supervisor.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/robotics.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/secure-worktree-pipeline.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/security-check.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/test-intent-lock.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/tracebank.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/vision.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/omg-capability.schema.json +1 -1
- package/artifacts/release/dist/enterprise/bundle/settings.json +3 -3
- package/artifacts/release/dist/enterprise/manifest.json +30 -40
- package/artifacts/release/dist/public/bundle/.claude-plugin/marketplace.json +3 -3
- package/artifacts/release/dist/public/bundle/.claude-plugin/plugin.json +1 -1
- package/artifacts/release/dist/public/bundle/OMG_COMPAT_CONTRACT.md +1 -1
- package/artifacts/release/dist/public/bundle/plugins/advanced/plugin.json +26 -9
- package/artifacts/release/dist/public/bundle/registry/bundles/algorithms.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/api-twin.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/claim-judge.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/control-plane.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/data-lineage.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/delta-classifier.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/eval-gate.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/health.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/hook-governor.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/incident-replay.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/lsp-pack.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/mcp-fabric.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/plan-council.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/preflight.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/proof-gate.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/remote-supervisor.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/robotics.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/secure-worktree-pipeline.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/security-check.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/test-intent-lock.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/tracebank.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/vision.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/omg-capability.schema.json +1 -1
- package/artifacts/release/dist/public/bundle/settings.json +3 -3
- package/artifacts/release/dist/public/manifest.json +30 -40
- package/artifacts/release/plugins/advanced/plugin.json +26 -9
- package/artifacts/release/registry/bundles/algorithms.yaml +1 -1
- package/artifacts/release/registry/bundles/api-twin.yaml +1 -1
- package/artifacts/release/registry/bundles/claim-judge.yaml +1 -1
- package/artifacts/release/registry/bundles/control-plane.yaml +1 -1
- package/artifacts/release/registry/bundles/data-lineage.yaml +1 -1
- package/artifacts/release/registry/bundles/delta-classifier.yaml +1 -1
- package/artifacts/release/registry/bundles/eval-gate.yaml +1 -1
- package/artifacts/release/registry/bundles/health.yaml +1 -1
- package/artifacts/release/registry/bundles/hook-governor.yaml +1 -1
- package/artifacts/release/registry/bundles/incident-replay.yaml +1 -1
- package/artifacts/release/registry/bundles/lsp-pack.yaml +1 -1
- package/artifacts/release/registry/bundles/mcp-fabric.yaml +1 -1
- package/artifacts/release/registry/bundles/plan-council.yaml +1 -1
- package/artifacts/release/registry/bundles/preflight.yaml +1 -1
- package/artifacts/release/registry/bundles/proof-gate.yaml +1 -1
- package/artifacts/release/registry/bundles/remote-supervisor.yaml +1 -1
- package/artifacts/release/registry/bundles/robotics.yaml +1 -1
- package/artifacts/release/registry/bundles/secure-worktree-pipeline.yaml +1 -1
- package/artifacts/release/registry/bundles/security-check.yaml +1 -1
- package/artifacts/release/registry/bundles/test-intent-lock.yaml +1 -1
- package/artifacts/release/registry/bundles/tracebank.yaml +1 -1
- package/artifacts/release/registry/bundles/vision.yaml +1 -1
- package/artifacts/release/registry/omg-capability.schema.json +1 -1
- package/artifacts/release/settings.json +3 -3
- package/build/lib/commands/OMG:profile-review.md +43 -0
- package/build/lib/commands/OMG:validate.md +59 -0
- package/build/lib/control_plane/service.py +40 -1
- package/build/lib/hooks/_agent_registry.py +2 -0
- package/build/lib/hooks/firewall.py +263 -4
- package/build/lib/hooks/intentgate-keyword-detector.py +15 -3
- package/build/lib/hooks/policy_engine.py +77 -0
- package/build/lib/hooks/prompt-enhancer.py +146 -0
- package/build/lib/hooks/session-end-capture.py +374 -6
- package/build/lib/hooks/session-start.py +13 -35
- package/build/lib/hooks/setup_wizard.py +333 -1
- package/build/lib/hooks/shadow_manager.py +111 -2
- package/build/lib/hooks/stop_dispatcher.py +108 -4
- package/build/lib/plugins/advanced/plugin.json +26 -9
- package/build/lib/plugins/core/plugin.json +44 -11
- package/build/lib/registry/bundles/algorithms.yaml +1 -1
- package/build/lib/registry/bundles/api-twin.yaml +1 -1
- package/build/lib/registry/bundles/claim-judge.yaml +1 -1
- package/build/lib/registry/bundles/control-plane.yaml +1 -1
- package/build/lib/registry/bundles/data-lineage.yaml +1 -1
- package/build/lib/registry/bundles/delta-classifier.yaml +1 -1
- package/build/lib/registry/bundles/eval-gate.yaml +1 -1
- package/build/lib/registry/bundles/health.yaml +1 -1
- package/build/lib/registry/bundles/hook-governor.yaml +1 -1
- package/build/lib/registry/bundles/incident-replay.yaml +1 -1
- package/build/lib/registry/bundles/lsp-pack.yaml +1 -1
- package/build/lib/registry/bundles/mcp-fabric.yaml +1 -1
- package/build/lib/registry/bundles/plan-council.yaml +1 -1
- package/build/lib/registry/bundles/preflight.yaml +1 -1
- package/build/lib/registry/bundles/proof-gate.yaml +1 -1
- package/build/lib/registry/bundles/remote-supervisor.yaml +1 -1
- package/build/lib/registry/bundles/robotics.yaml +1 -1
- package/build/lib/registry/bundles/secure-worktree-pipeline.yaml +1 -1
- package/build/lib/registry/bundles/security-check.yaml +1 -1
- package/build/lib/registry/bundles/test-intent-lock.yaml +1 -1
- package/build/lib/registry/bundles/tracebank.yaml +1 -1
- package/build/lib/registry/bundles/vision.yaml +1 -1
- package/build/lib/registry/omg-capability.schema.json +1 -1
- package/build/lib/runtime/adoption.py +1 -1
- package/build/lib/runtime/background_verification.py +62 -0
- package/build/lib/runtime/claim_judge.py +165 -5
- package/build/lib/runtime/compat.py +15 -1
- package/build/lib/runtime/context_engine.py +261 -4
- package/build/lib/runtime/contract_compiler.py +370 -93
- package/build/lib/runtime/defense_state.py +79 -8
- package/build/lib/runtime/delta_classifier.py +80 -2
- package/build/lib/runtime/evidence_query.py +56 -4
- package/build/lib/runtime/evidence_registry.py +16 -0
- package/build/lib/runtime/evidence_requirements.py +47 -0
- package/build/lib/runtime/forge_agents.py +179 -9
- package/build/lib/runtime/forge_contracts.py +208 -2
- package/build/lib/runtime/interaction_journal.py +318 -42
- package/build/lib/runtime/memory_store.py +134 -1
- package/build/lib/runtime/mutation_gate.py +57 -11
- package/build/lib/runtime/omg_compat_contract_snapshot.json +2 -2
- package/build/lib/runtime/omg_mcp_server.py +14 -4
- package/build/lib/runtime/preflight.py +14 -0
- package/build/lib/runtime/profile_io.py +294 -0
- package/build/lib/runtime/proof_gate.py +122 -7
- package/build/lib/runtime/release_run_coordinator.py +339 -0
- package/build/lib/runtime/release_surfaces.py +243 -0
- package/build/lib/runtime/rollback_manifest.py +136 -0
- package/build/lib/runtime/router_critics.py +50 -0
- package/build/lib/runtime/runtime_contracts.py +137 -0
- package/build/lib/runtime/security_check.py +16 -0
- package/build/lib/runtime/session_health.py +60 -16
- package/build/lib/runtime/team_router.py +156 -13
- package/build/lib/runtime/test_intent_lock.py +102 -0
- package/build/lib/runtime/tool_plan_gate.py +249 -24
- package/build/lib/runtime/validate.py +194 -0
- package/build/lib/runtime/verification_controller.py +52 -2
- package/commands/OMG:diagnose-plugins.md +33 -0
- package/commands/OMG:profile-review.md +43 -0
- package/commands/OMG:setup.md +4 -1
- package/commands/OMG:validate.md +59 -0
- package/control_plane/service.py +40 -1
- package/dist/enterprise/bundle/.claude-plugin/marketplace.json +3 -3
- package/dist/enterprise/bundle/.claude-plugin/plugin.json +1 -1
- package/dist/enterprise/bundle/OMG_COMPAT_CONTRACT.md +1 -1
- package/dist/enterprise/bundle/plugins/advanced/plugin.json +26 -9
- package/dist/enterprise/bundle/registry/bundles/algorithms.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/api-twin.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/claim-judge.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/control-plane.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/data-lineage.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/delta-classifier.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/eval-gate.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/health.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/hook-governor.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/incident-replay.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/lsp-pack.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/mcp-fabric.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/plan-council.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/preflight.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/proof-gate.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/remote-supervisor.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/robotics.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/secure-worktree-pipeline.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/security-check.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/test-intent-lock.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/tracebank.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/vision.yaml +1 -1
- package/dist/enterprise/bundle/registry/omg-capability.schema.json +1 -1
- package/dist/enterprise/bundle/settings.json +3 -3
- package/dist/enterprise/manifest.json +30 -40
- package/dist/oh_my_god-2.1.4-py3-none-any.whl +0 -0
- package/dist/oh_my_god-2.1.4.tar.gz +0 -0
- package/dist/public/bundle/.claude-plugin/marketplace.json +3 -3
- package/dist/public/bundle/.claude-plugin/plugin.json +1 -1
- package/dist/public/bundle/OMG_COMPAT_CONTRACT.md +1 -1
- package/dist/public/bundle/plugins/advanced/plugin.json +26 -9
- package/dist/public/bundle/registry/bundles/algorithms.yaml +1 -1
- package/dist/public/bundle/registry/bundles/api-twin.yaml +1 -1
- package/dist/public/bundle/registry/bundles/claim-judge.yaml +1 -1
- package/dist/public/bundle/registry/bundles/control-plane.yaml +1 -1
- package/dist/public/bundle/registry/bundles/data-lineage.yaml +1 -1
- package/dist/public/bundle/registry/bundles/delta-classifier.yaml +1 -1
- package/dist/public/bundle/registry/bundles/eval-gate.yaml +1 -1
- package/dist/public/bundle/registry/bundles/health.yaml +1 -1
- package/dist/public/bundle/registry/bundles/hook-governor.yaml +1 -1
- package/dist/public/bundle/registry/bundles/incident-replay.yaml +1 -1
- package/dist/public/bundle/registry/bundles/lsp-pack.yaml +1 -1
- package/dist/public/bundle/registry/bundles/mcp-fabric.yaml +1 -1
- package/dist/public/bundle/registry/bundles/plan-council.yaml +1 -1
- package/dist/public/bundle/registry/bundles/preflight.yaml +1 -1
- package/dist/public/bundle/registry/bundles/proof-gate.yaml +1 -1
- package/dist/public/bundle/registry/bundles/remote-supervisor.yaml +1 -1
- package/dist/public/bundle/registry/bundles/robotics.yaml +1 -1
- package/dist/public/bundle/registry/bundles/secure-worktree-pipeline.yaml +1 -1
- package/dist/public/bundle/registry/bundles/security-check.yaml +1 -1
- package/dist/public/bundle/registry/bundles/test-intent-lock.yaml +1 -1
- package/dist/public/bundle/registry/bundles/tracebank.yaml +1 -1
- package/dist/public/bundle/registry/bundles/vision.yaml +1 -1
- package/dist/public/bundle/registry/omg-capability.schema.json +1 -1
- package/dist/public/bundle/settings.json +3 -3
- package/dist/public/manifest.json +30 -40
- package/docs/install/opencode.md +30 -0
- package/docs/proof.md +11 -0
- package/docs/release-checklist.md +14 -1
- package/hooks/_agent_registry.py +2 -0
- package/hooks/firewall.py +263 -4
- package/hooks/intentgate-keyword-detector.py +15 -3
- package/hooks/policy_engine.py +77 -0
- package/hooks/prompt-enhancer.py +146 -0
- package/hooks/session-end-capture.py +374 -6
- package/hooks/session-start.py +13 -35
- package/hooks/setup_wizard.py +342 -2
- package/hooks/shadow_manager.py +111 -2
- package/hooks/stop_dispatcher.py +108 -4
- package/hud/omg-hud.mjs +30 -6
- package/lab/pipeline.py +197 -26
- package/package.json +1 -1
- package/plugins/advanced/plugin.json +26 -9
- package/plugins/core/plugin.json +51 -12
- package/pyproject.toml +10 -2
- package/registry/bundles/algorithms.yaml +1 -1
- package/registry/bundles/api-twin.yaml +1 -1
- package/registry/bundles/claim-judge.yaml +1 -1
- package/registry/bundles/control-plane.yaml +1 -1
- package/registry/bundles/data-lineage.yaml +1 -1
- package/registry/bundles/delta-classifier.yaml +1 -1
- package/registry/bundles/eval-gate.yaml +1 -1
- package/registry/bundles/health.yaml +1 -1
- package/registry/bundles/hook-governor.yaml +1 -1
- package/registry/bundles/incident-replay.yaml +1 -1
- package/registry/bundles/lsp-pack.yaml +1 -1
- package/registry/bundles/mcp-fabric.yaml +1 -1
- package/registry/bundles/plan-council.yaml +1 -1
- package/registry/bundles/preflight.yaml +1 -1
- package/registry/bundles/proof-gate.yaml +1 -1
- package/registry/bundles/remote-supervisor.yaml +1 -1
- package/registry/bundles/robotics.yaml +1 -1
- package/registry/bundles/secure-worktree-pipeline.yaml +1 -1
- package/registry/bundles/security-check.yaml +1 -1
- package/registry/bundles/test-intent-lock.yaml +1 -1
- package/registry/bundles/tracebank.yaml +1 -1
- package/registry/bundles/vision.yaml +1 -1
- package/registry/omg-capability.schema.json +1 -1
- package/runtime/adoption.py +7 -5
- package/runtime/background_verification.py +62 -0
- package/runtime/claim_judge.py +165 -5
- package/runtime/compat.py +48 -1
- package/runtime/context_engine.py +261 -4
- package/runtime/contract_compiler.py +370 -93
- package/runtime/defense_state.py +79 -8
- package/runtime/delta_classifier.py +80 -2
- package/runtime/evidence_query.py +56 -4
- package/runtime/evidence_registry.py +16 -0
- package/runtime/evidence_requirements.py +47 -0
- package/runtime/forge_agents.py +179 -9
- package/runtime/forge_contracts.py +208 -2
- package/runtime/hook_governor.py +19 -1
- package/runtime/interaction_journal.py +318 -42
- package/runtime/memory_store.py +134 -1
- package/runtime/mutation_gate.py +57 -11
- package/runtime/omg_compat_contract_snapshot.json +2 -2
- package/runtime/omg_mcp_server.py +14 -4
- package/runtime/plugin_diagnostics.py +248 -0
- package/runtime/plugin_interop.py +1007 -0
- package/runtime/preflight.py +14 -0
- package/runtime/profile_io.py +294 -0
- package/runtime/proof_gate.py +122 -7
- package/runtime/providers/opencode_provider.py +94 -0
- package/runtime/release_run_coordinator.py +339 -0
- package/runtime/release_surfaces.py +243 -0
- package/runtime/rollback_manifest.py +136 -0
- package/runtime/router_critics.py +50 -0
- package/runtime/runtime_contracts.py +137 -0
- package/runtime/security_check.py +16 -0
- package/runtime/session_health.py +60 -16
- package/runtime/team_router.py +156 -13
- package/runtime/test_intent_lock.py +102 -0
- package/runtime/tool_plan_gate.py +218 -19
- package/runtime/validate.py +289 -0
- package/runtime/verification_controller.py +52 -2
- package/scripts/omg.py +306 -3
- package/scripts/prepare-release-proof-fixtures.py +191 -7
- package/scripts/print-canonical-version.py +80 -0
- package/scripts/sync-release-identity.py +476 -0
- package/scripts/validate-release-identity.py +246 -0
- package/scripts/verify-standalone.sh +3 -0
- package/settings.json +3 -3
- package/templates/plugins-allowlist.yaml +19 -0
- package/artifacts/release/dist/enterprise/bundle/.gemini/settings.json +0 -11
- package/artifacts/release/dist/enterprise/bundle/.kimi/mcp.json +0 -11
- package/artifacts/release/dist/public/bundle/.gemini/settings.json +0 -11
- package/artifacts/release/dist/public/bundle/.kimi/mcp.json +0 -11
- package/build/lib/yaml.py +0 -321
- package/dist/enterprise/bundle/.gemini/settings.json +0 -11
- package/dist/enterprise/bundle/.kimi/mcp.json +0 -11
- package/dist/public/bundle/.gemini/settings.json +0 -11
- package/dist/public/bundle/.kimi/mcp.json +0 -11
|
@@ -8,6 +8,10 @@ from uuid import uuid4
|
|
|
8
8
|
|
|
9
9
|
import json
|
|
10
10
|
|
|
11
|
+
from runtime.context_engine import ContextEngine
|
|
12
|
+
from runtime.release_run_coordinator import resolve_current_run_id as resolve_coordinator_run_id
|
|
13
|
+
from runtime.runtime_contracts import read_run_state
|
|
14
|
+
|
|
11
15
|
|
|
12
16
|
_TOOL_KEYWORDS: dict[str, tuple[str, ...]] = {
|
|
13
17
|
"context7": ("doc", "docs", "documentation", "library", "api reference", "reference"),
|
|
@@ -16,14 +20,35 @@ _TOOL_KEYWORDS: dict[str, tuple[str, ...]] = {
|
|
|
16
20
|
"omg-control": ("policy", "governance", "release", "proof", "control plane"),
|
|
17
21
|
}
|
|
18
22
|
|
|
23
|
+
_READ_ONLY_TOOL_HINTS = (
|
|
24
|
+
"read",
|
|
25
|
+
"search",
|
|
26
|
+
"review",
|
|
27
|
+
"grep",
|
|
28
|
+
"glob",
|
|
29
|
+
"list",
|
|
30
|
+
"ls",
|
|
31
|
+
"context7",
|
|
32
|
+
"websearch",
|
|
33
|
+
)
|
|
34
|
+
_MUTATION_TOOLS = frozenset({"write", "edit", "multiedit", "bash"})
|
|
35
|
+
|
|
19
36
|
|
|
20
37
|
def build_tool_plan(
|
|
21
38
|
goal: str,
|
|
22
39
|
available_tools: list[str],
|
|
23
40
|
context_packet: dict[str, object] | None = None,
|
|
41
|
+
run_id: str | None = None,
|
|
24
42
|
) -> dict[str, object]:
|
|
25
43
|
normalized_goal = str(goal or "").strip()
|
|
26
44
|
normalized_tools = _normalize_tools(available_tools)
|
|
45
|
+
canonical_run_id = run_id or resolve_current_run_id(project_dir=None)
|
|
46
|
+
bounded_context = _resolve_bounded_context_packet(
|
|
47
|
+
project_dir=str(_project_dir()),
|
|
48
|
+
run_id=canonical_run_id,
|
|
49
|
+
fallback_context=context_packet,
|
|
50
|
+
)
|
|
51
|
+
council = _read_council_verdicts(str(_project_dir()), canonical_run_id)
|
|
27
52
|
|
|
28
53
|
selected_tools: list[dict[str, object]] = []
|
|
29
54
|
for tool_name in normalized_tools:
|
|
@@ -31,7 +56,7 @@ def build_tool_plan(
|
|
|
31
56
|
selected_tools.append(
|
|
32
57
|
{
|
|
33
58
|
"name": tool_name,
|
|
34
|
-
"args": _default_args(tool_name, normalized_goal,
|
|
59
|
+
"args": _default_args(tool_name, normalized_goal, bounded_context),
|
|
35
60
|
"rationale": _rationale(tool_name),
|
|
36
61
|
}
|
|
37
62
|
)
|
|
@@ -41,23 +66,25 @@ def build_tool_plan(
|
|
|
41
66
|
selected_tools.append(
|
|
42
67
|
{
|
|
43
68
|
"name": fallback,
|
|
44
|
-
"args": _default_args(fallback, normalized_goal,
|
|
69
|
+
"args": _default_args(fallback, normalized_goal, bounded_context),
|
|
45
70
|
"rationale": "fallback: no explicit keyword match; keep single minimal tool",
|
|
46
71
|
}
|
|
47
72
|
)
|
|
48
73
|
|
|
49
|
-
|
|
50
|
-
plan_id = _new_plan_id(run_id=
|
|
74
|
+
selected_tools = _apply_context_optimization(selected_tools, bounded_context, council)
|
|
75
|
+
plan_id = _new_plan_id(run_id=canonical_run_id)
|
|
51
76
|
payload: dict[str, object] = {
|
|
52
77
|
"plan_id": plan_id,
|
|
53
78
|
"goal": normalized_goal,
|
|
54
79
|
"tools": selected_tools,
|
|
55
80
|
"budget_estimate": {
|
|
56
81
|
"estimated_calls": len(selected_tools),
|
|
57
|
-
"estimated_context_chars": _estimate_context_chars(
|
|
82
|
+
"estimated_context_chars": _estimate_context_chars(bounded_context),
|
|
58
83
|
"goal_complexity": _goal_complexity(normalized_goal),
|
|
59
84
|
},
|
|
60
|
-
"
|
|
85
|
+
"context_packet": bounded_context,
|
|
86
|
+
"council_verdicts": council.get("verdicts", {}),
|
|
87
|
+
"run_id": canonical_run_id,
|
|
61
88
|
"created_at": datetime.now(timezone.utc).isoformat(),
|
|
62
89
|
}
|
|
63
90
|
_persist_plan(_project_dir(), plan_id, payload)
|
|
@@ -65,19 +92,8 @@ def build_tool_plan(
|
|
|
65
92
|
|
|
66
93
|
|
|
67
94
|
def resolve_current_run_id(project_dir: str | None = None) -> str | None:
|
|
68
|
-
run_id =
|
|
69
|
-
|
|
70
|
-
return run_id
|
|
71
|
-
|
|
72
|
-
root = _project_dir(project_dir)
|
|
73
|
-
active_run = root / ".omg" / "shadow" / "active-run"
|
|
74
|
-
if not active_run.exists():
|
|
75
|
-
return None
|
|
76
|
-
try:
|
|
77
|
-
value = active_run.read_text(encoding="utf-8").strip()
|
|
78
|
-
except OSError:
|
|
79
|
-
return None
|
|
80
|
-
return value or None
|
|
95
|
+
run_id = resolve_coordinator_run_id(project_dir=project_dir)
|
|
96
|
+
return run_id or None
|
|
81
97
|
|
|
82
98
|
|
|
83
99
|
def has_tool_plan_for_run(project_dir: str, run_id: str | None) -> bool:
|
|
@@ -93,7 +109,45 @@ def has_tool_plan_for_run(project_dir: str, run_id: str | None) -> bool:
|
|
|
93
109
|
def tool_plan_gate_check(project_dir: str, run_id: str | None, tool: str) -> dict[str, object]:
|
|
94
110
|
if not run_id:
|
|
95
111
|
return {"status": "allowed", "reason": "run_id unavailable; skip tool plan gate"}
|
|
112
|
+
|
|
113
|
+
context_packet = _resolve_bounded_context_packet(
|
|
114
|
+
project_dir=project_dir,
|
|
115
|
+
run_id=run_id,
|
|
116
|
+
fallback_context=None,
|
|
117
|
+
)
|
|
118
|
+
clarification = _clarification_status(context_packet)
|
|
119
|
+
if clarification["requires_clarification"]:
|
|
120
|
+
reason = _clarification_reason(str(clarification["clarification_prompt"]))
|
|
121
|
+
if _is_mutation_capable_tool(tool):
|
|
122
|
+
_persist_gate_error(project_dir, run_id, tool, reason)
|
|
123
|
+
return {
|
|
124
|
+
"status": "blocked",
|
|
125
|
+
"reason": reason,
|
|
126
|
+
"run_id": run_id,
|
|
127
|
+
"tool": tool,
|
|
128
|
+
"clarification_status": clarification,
|
|
129
|
+
}
|
|
130
|
+
if _is_read_search_review_tool(tool):
|
|
131
|
+
return {
|
|
132
|
+
"status": "allowed",
|
|
133
|
+
"reason": "clarification pending; read/search/review tool allowed",
|
|
134
|
+
"run_id": run_id,
|
|
135
|
+
"clarification_status": clarification,
|
|
136
|
+
}
|
|
137
|
+
|
|
96
138
|
if has_tool_plan_for_run(project_dir, run_id):
|
|
139
|
+
council = _read_council_verdicts(project_dir, run_id)
|
|
140
|
+
verdict = _council_gate_verdict(council)
|
|
141
|
+
if verdict["blocked"]:
|
|
142
|
+
reason = str(verdict["reason"])
|
|
143
|
+
_persist_gate_error(project_dir, run_id, tool, reason)
|
|
144
|
+
return {
|
|
145
|
+
"status": "blocked",
|
|
146
|
+
"reason": reason,
|
|
147
|
+
"run_id": run_id,
|
|
148
|
+
"tool": tool,
|
|
149
|
+
"council_verdicts": council.get("verdicts", {}),
|
|
150
|
+
}
|
|
97
151
|
return {"status": "allowed", "reason": "tool plan present", "run_id": run_id}
|
|
98
152
|
|
|
99
153
|
reason = "tool plan required before mutation-capable MCP evaluation"
|
|
@@ -197,7 +251,152 @@ def _atomic_write_json(path: Path, payload: Mapping[str, object]) -> None:
|
|
|
197
251
|
_ = os.replace(temp_path, path)
|
|
198
252
|
|
|
199
253
|
|
|
254
|
+
def journal_mutation_bash(
|
|
255
|
+
project_dir: str,
|
|
256
|
+
command: str,
|
|
257
|
+
run_id: str | None = None,
|
|
258
|
+
metadata: dict[str, object] | None = None,
|
|
259
|
+
) -> dict[str, object] | None:
|
|
260
|
+
try:
|
|
261
|
+
from runtime.interaction_journal import InteractionJournal
|
|
262
|
+
from runtime.rollback_manifest import classify_side_effect
|
|
263
|
+
except ImportError:
|
|
264
|
+
return None
|
|
265
|
+
|
|
266
|
+
canonical_run_id = run_id or resolve_current_run_id(project_dir)
|
|
267
|
+
if not canonical_run_id:
|
|
268
|
+
return None
|
|
269
|
+
|
|
270
|
+
meta: dict[str, object] = dict(metadata or {})
|
|
271
|
+
meta["command"] = command
|
|
272
|
+
meta["run_id"] = canonical_run_id
|
|
273
|
+
|
|
274
|
+
side_effect = classify_side_effect("bash", meta)
|
|
275
|
+
meta["side_effect_scope"] = str(side_effect.get("category", "unknown"))
|
|
276
|
+
meta["side_effect_classification"] = side_effect
|
|
277
|
+
|
|
278
|
+
journal = InteractionJournal(project_dir)
|
|
279
|
+
return journal.record_step("bash", meta)
|
|
280
|
+
|
|
281
|
+
|
|
200
282
|
def _safe_token(value: str) -> str:
|
|
201
283
|
chars = [ch if ch.isalnum() or ch in {"-", "_"} else "-" for ch in value.strip()]
|
|
202
284
|
token = "".join(chars).strip("-")
|
|
203
285
|
return token or "run"
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def _resolve_bounded_context_packet(
|
|
289
|
+
*,
|
|
290
|
+
project_dir: str,
|
|
291
|
+
run_id: str | None,
|
|
292
|
+
fallback_context: dict[str, object] | None,
|
|
293
|
+
) -> dict[str, object]:
|
|
294
|
+
if run_id:
|
|
295
|
+
packet = ContextEngine(project_dir).build_packet(run_id=run_id, delta_only=True)
|
|
296
|
+
if isinstance(fallback_context, dict) and str(fallback_context.get("summary", "")).strip():
|
|
297
|
+
summary = str(packet.get("summary", "")).strip()
|
|
298
|
+
if not summary or summary == "no context signals available":
|
|
299
|
+
packet["summary"] = str(fallback_context.get("summary", ""))
|
|
300
|
+
return packet
|
|
301
|
+
return dict(fallback_context or {"summary": "", "artifact_pointers": []})
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
def _read_council_verdicts(project_dir: str, run_id: str | None) -> dict[str, object]:
|
|
305
|
+
if not run_id:
|
|
306
|
+
return {}
|
|
307
|
+
payload = read_run_state(project_dir, "council_verdicts", run_id)
|
|
308
|
+
if isinstance(payload, dict):
|
|
309
|
+
return dict(payload)
|
|
310
|
+
return {}
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
def _council_gate_verdict(council: dict[str, object]) -> dict[str, object]:
|
|
314
|
+
verdicts = council.get("verdicts")
|
|
315
|
+
if not isinstance(verdicts, dict):
|
|
316
|
+
return {"blocked": False, "reason": ""}
|
|
317
|
+
|
|
318
|
+
for critic_name, critic_payload in verdicts.items():
|
|
319
|
+
if not isinstance(critic_payload, dict):
|
|
320
|
+
continue
|
|
321
|
+
token = str(critic_payload.get("verdict", "")).strip().lower()
|
|
322
|
+
if token == "fail":
|
|
323
|
+
return {
|
|
324
|
+
"blocked": True,
|
|
325
|
+
"reason": f"council critic '{critic_name}' failed; block mutation-capable tool execution",
|
|
326
|
+
}
|
|
327
|
+
return {"blocked": False, "reason": ""}
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def _apply_context_optimization(
|
|
331
|
+
tools: list[dict[str, object]],
|
|
332
|
+
context_packet: dict[str, object],
|
|
333
|
+
council: dict[str, object],
|
|
334
|
+
) -> list[dict[str, object]]:
|
|
335
|
+
if len(tools) <= 1:
|
|
336
|
+
return tools
|
|
337
|
+
|
|
338
|
+
budget = context_packet.get("budget")
|
|
339
|
+
used_chars = 0
|
|
340
|
+
max_chars = 0
|
|
341
|
+
if isinstance(budget, dict):
|
|
342
|
+
try:
|
|
343
|
+
used_chars = int(budget.get("used_chars", 0))
|
|
344
|
+
max_chars = int(budget.get("max_chars", 0))
|
|
345
|
+
except (TypeError, ValueError):
|
|
346
|
+
used_chars = 0
|
|
347
|
+
max_chars = 0
|
|
348
|
+
|
|
349
|
+
verdicts = council.get("verdicts")
|
|
350
|
+
evidence_warn = False
|
|
351
|
+
if isinstance(verdicts, dict):
|
|
352
|
+
evidence = verdicts.get("evidence_completeness")
|
|
353
|
+
if isinstance(evidence, dict):
|
|
354
|
+
evidence_warn = str(evidence.get("verdict", "")).strip().lower() in {"warn", "fail"}
|
|
355
|
+
|
|
356
|
+
pressure_high = max_chars > 0 and used_chars >= int(max_chars * 0.9)
|
|
357
|
+
if pressure_high or evidence_warn:
|
|
358
|
+
return tools[:1]
|
|
359
|
+
return tools
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
def _clarification_status(context_packet: dict[str, object]) -> dict[str, object]:
|
|
363
|
+
raw = context_packet.get("clarification_status")
|
|
364
|
+
if not isinstance(raw, dict):
|
|
365
|
+
return {
|
|
366
|
+
"requires_clarification": False,
|
|
367
|
+
"intent_class": "",
|
|
368
|
+
"clarification_prompt": "",
|
|
369
|
+
"confidence": 0.0,
|
|
370
|
+
}
|
|
371
|
+
prompt = str(raw.get("clarification_prompt", "")).strip().replace("\n", " ")
|
|
372
|
+
try:
|
|
373
|
+
confidence = float(raw.get("confidence", 0.0))
|
|
374
|
+
except (TypeError, ValueError):
|
|
375
|
+
confidence = 0.0
|
|
376
|
+
return {
|
|
377
|
+
"requires_clarification": bool(raw.get("requires_clarification") is True),
|
|
378
|
+
"intent_class": str(raw.get("intent_class", "")).strip(),
|
|
379
|
+
"clarification_prompt": prompt,
|
|
380
|
+
"confidence": round(max(0.0, min(1.0, confidence)), 2),
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
def _clarification_reason(clarification_prompt: str) -> str:
|
|
385
|
+
prompt = " ".join(str(clarification_prompt or "").split())
|
|
386
|
+
if prompt:
|
|
387
|
+
return f"Clarification required before mutation: {prompt}"
|
|
388
|
+
return "Clarification required before mutation: provide the missing intent details."
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
def _is_mutation_capable_tool(tool: str) -> bool:
|
|
392
|
+
token = str(tool or "").strip().lower()
|
|
393
|
+
if token in _MUTATION_TOOLS:
|
|
394
|
+
return True
|
|
395
|
+
return token.startswith("bash:")
|
|
396
|
+
|
|
397
|
+
|
|
398
|
+
def _is_read_search_review_tool(tool: str) -> bool:
|
|
399
|
+
token = str(tool or "").strip().lower()
|
|
400
|
+
if not token:
|
|
401
|
+
return False
|
|
402
|
+
return any(hint in token for hint in _READ_ONLY_TOOL_HINTS)
|
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
"""Canonical validation engine — composes doctor, contract, profile, and install checks.
|
|
2
|
+
|
|
3
|
+
This module is the single entrypoint for ``omg validate``. It delegates to
|
|
4
|
+
existing checkers (``run_doctor``, ``validate_contract_registry``, profile
|
|
5
|
+
governor, install integrity) rather than duplicating their logic.
|
|
6
|
+
"""
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import os
|
|
10
|
+
import shutil
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
from runtime.adoption import CANONICAL_VERSION
|
|
15
|
+
from runtime.compat import run_doctor, _doctor_check
|
|
16
|
+
from runtime.contract_compiler import validate_contract_registry
|
|
17
|
+
from runtime.plugin_diagnostics import run_plugin_diagnostics
|
|
18
|
+
from runtime.profile_io import load_profile, ensure_governed_preferences
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def _check_contract_registry(root_dir: Path) -> dict[str, Any]:
|
|
22
|
+
"""Compose contract registry validation into a single doctor-style check."""
|
|
23
|
+
try:
|
|
24
|
+
result = validate_contract_registry(root_dir)
|
|
25
|
+
except Exception as exc:
|
|
26
|
+
return _doctor_check(
|
|
27
|
+
"contract_registry",
|
|
28
|
+
ok=False,
|
|
29
|
+
message=f"contract validation error: {exc}",
|
|
30
|
+
)
|
|
31
|
+
if result.get("status") == "ok":
|
|
32
|
+
error_count = len(result.get("errors", []))
|
|
33
|
+
return _doctor_check(
|
|
34
|
+
"contract_registry",
|
|
35
|
+
ok=True,
|
|
36
|
+
message=f"contract registry valid ({error_count} errors)",
|
|
37
|
+
)
|
|
38
|
+
errors = result.get("errors", [])
|
|
39
|
+
summary = errors[0] if errors else "unknown error"
|
|
40
|
+
if len(errors) > 1:
|
|
41
|
+
summary += f" (+{len(errors) - 1} more)"
|
|
42
|
+
return _doctor_check(
|
|
43
|
+
"contract_registry",
|
|
44
|
+
ok=False,
|
|
45
|
+
message=f"contract registry invalid: {summary}",
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def _check_profile_governor(root_dir: Path) -> dict[str, Any]:
|
|
50
|
+
"""Validate that governed profile state is consistent."""
|
|
51
|
+
profile_path = os.path.join(root_dir, ".omg", "state", "profile.yaml")
|
|
52
|
+
profile = load_profile(profile_path)
|
|
53
|
+
|
|
54
|
+
if not profile:
|
|
55
|
+
return _doctor_check(
|
|
56
|
+
"profile_governor",
|
|
57
|
+
ok=True,
|
|
58
|
+
message="no profile found (optional — run /OMG:init to create)",
|
|
59
|
+
required=False,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
try:
|
|
63
|
+
ensure_governed_preferences(profile)
|
|
64
|
+
except Exception as exc:
|
|
65
|
+
return _doctor_check(
|
|
66
|
+
"profile_governor",
|
|
67
|
+
ok=False,
|
|
68
|
+
message=f"governed preferences malformed: {exc}",
|
|
69
|
+
required=False,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
governed = profile.get("governed_preferences", {})
|
|
73
|
+
governed = governed if isinstance(governed, dict) else {}
|
|
74
|
+
style_entries = governed.get("style", [])
|
|
75
|
+
style_entries = style_entries if isinstance(style_entries, list) else []
|
|
76
|
+
safety_entries = governed.get("safety", [])
|
|
77
|
+
safety_entries = safety_entries if isinstance(safety_entries, list) else []
|
|
78
|
+
|
|
79
|
+
pending = sum(
|
|
80
|
+
1 for e in style_entries + safety_entries
|
|
81
|
+
if isinstance(e, dict) and e.get("confirmation_state") == "pending_confirmation"
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
parts = [f"{len(style_entries)} style, {len(safety_entries)} safety"]
|
|
85
|
+
if pending:
|
|
86
|
+
parts.append(f"{pending} pending confirmation")
|
|
87
|
+
|
|
88
|
+
return _doctor_check(
|
|
89
|
+
"profile_governor",
|
|
90
|
+
ok=True,
|
|
91
|
+
message=f"profile governor ok ({', '.join(parts)})",
|
|
92
|
+
required=False,
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _check_install_integrity(root_dir: Path) -> dict[str, Any]:
|
|
97
|
+
"""Verify critical install paths exist and are coherent."""
|
|
98
|
+
issues: list[str] = []
|
|
99
|
+
|
|
100
|
+
# Check scripts/omg.py exists
|
|
101
|
+
omg_script = root_dir / "scripts" / "omg.py"
|
|
102
|
+
if not omg_script.exists():
|
|
103
|
+
issues.append("scripts/omg.py missing")
|
|
104
|
+
|
|
105
|
+
# Check runtime/ package exists
|
|
106
|
+
runtime_init = root_dir / "runtime" / "__init__.py"
|
|
107
|
+
runtime_dir = root_dir / "runtime"
|
|
108
|
+
if not runtime_dir.exists():
|
|
109
|
+
issues.append("runtime/ directory missing")
|
|
110
|
+
|
|
111
|
+
# Check commands/ directory exists
|
|
112
|
+
commands_dir = root_dir / "commands"
|
|
113
|
+
if not commands_dir.exists():
|
|
114
|
+
issues.append("commands/ directory missing")
|
|
115
|
+
|
|
116
|
+
# Check plugins/core/plugin.json exists
|
|
117
|
+
plugin_json = root_dir / "plugins" / "core" / "plugin.json"
|
|
118
|
+
if not plugin_json.exists():
|
|
119
|
+
issues.append("plugins/core/plugin.json missing")
|
|
120
|
+
|
|
121
|
+
# Check pyproject.toml exists
|
|
122
|
+
pyproject = root_dir / "pyproject.toml"
|
|
123
|
+
if not pyproject.exists():
|
|
124
|
+
issues.append("pyproject.toml missing")
|
|
125
|
+
|
|
126
|
+
if issues:
|
|
127
|
+
return _doctor_check(
|
|
128
|
+
"install_integrity",
|
|
129
|
+
ok=False,
|
|
130
|
+
message=f"install issues: {'; '.join(issues)}",
|
|
131
|
+
)
|
|
132
|
+
return _doctor_check(
|
|
133
|
+
"install_integrity",
|
|
134
|
+
ok=True,
|
|
135
|
+
message="install integrity ok (scripts, runtime, commands, plugins present)",
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
|
|
139
|
+
def _check_plugin_compatibility(root_dir: Path) -> dict[str, Any]:
|
|
140
|
+
try:
|
|
141
|
+
result = run_plugin_diagnostics(str(root_dir))
|
|
142
|
+
except Exception as exc:
|
|
143
|
+
return _doctor_check(
|
|
144
|
+
"plugin_compatibility",
|
|
145
|
+
ok=False,
|
|
146
|
+
message=f"plugin diagnostics error: {exc}",
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
status = str(result.get("status", "error"))
|
|
150
|
+
summary = result.get("summary", {})
|
|
151
|
+
summary = summary if isinstance(summary, dict) else {}
|
|
152
|
+
total_records = int(summary.get("total_records", 0))
|
|
153
|
+
total_conflicts = int(summary.get("total_conflicts", 0))
|
|
154
|
+
blockers = int(summary.get("blockers", 0))
|
|
155
|
+
|
|
156
|
+
return _doctor_check(
|
|
157
|
+
"plugin_compatibility",
|
|
158
|
+
ok=status in {"ok", "warn"},
|
|
159
|
+
message=(
|
|
160
|
+
f"plugin compatibility: {total_records} records, "
|
|
161
|
+
f"{total_conflicts} conflicts, {blockers} blockers"
|
|
162
|
+
),
|
|
163
|
+
)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
def _load_selected_mcps(root_dir: Path) -> list[str]:
|
|
167
|
+
"""Load selected MCP IDs from cli-config.yaml.
|
|
168
|
+
|
|
169
|
+
Checks CLAUDE_PROJECT_DIR env first, then falls back to root_dir.
|
|
170
|
+
Returns an empty list when the config file is absent or unparseable.
|
|
171
|
+
"""
|
|
172
|
+
import yaml as _yaml
|
|
173
|
+
|
|
174
|
+
project_dir = os.environ.get("CLAUDE_PROJECT_DIR", "")
|
|
175
|
+
if project_dir:
|
|
176
|
+
config_path = os.path.join(project_dir, ".omg", "state", "cli-config.yaml")
|
|
177
|
+
else:
|
|
178
|
+
config_path = os.path.join(root_dir, ".omg", "state", "cli-config.yaml")
|
|
179
|
+
|
|
180
|
+
if not os.path.isfile(config_path):
|
|
181
|
+
return []
|
|
182
|
+
|
|
183
|
+
try:
|
|
184
|
+
with open(config_path, "r", encoding="utf-8") as f:
|
|
185
|
+
data = _yaml.safe_load(f)
|
|
186
|
+
except Exception:
|
|
187
|
+
return []
|
|
188
|
+
|
|
189
|
+
if not isinstance(data, dict):
|
|
190
|
+
return []
|
|
191
|
+
|
|
192
|
+
mcps = data.get("selected_mcps", [])
|
|
193
|
+
return [str(m) for m in mcps] if isinstance(mcps, list) else []
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def _check_notebooklm(root_dir: Path) -> dict[str, Any] | None:
|
|
197
|
+
"""Optional NotebookLM health check — only runs when notebooklm is selected.
|
|
198
|
+
|
|
199
|
+
Returns None when NotebookLM is not in the selected MCP set (meaning:
|
|
200
|
+
skip entirely, no check emitted). When selected, checks that ``npx``
|
|
201
|
+
is reachable on PATH. Missing npx is a *warning*, never a blocker.
|
|
202
|
+
"""
|
|
203
|
+
selected = _load_selected_mcps(root_dir)
|
|
204
|
+
if "notebooklm" not in selected:
|
|
205
|
+
return None
|
|
206
|
+
|
|
207
|
+
npx_path = shutil.which("npx")
|
|
208
|
+
if npx_path is None:
|
|
209
|
+
return _doctor_check(
|
|
210
|
+
"notebooklm",
|
|
211
|
+
ok=False,
|
|
212
|
+
message="npx not found — install Node.js to use NotebookLM",
|
|
213
|
+
required=False,
|
|
214
|
+
)
|
|
215
|
+
|
|
216
|
+
return _doctor_check(
|
|
217
|
+
"notebooklm",
|
|
218
|
+
ok=True,
|
|
219
|
+
message="npx available, notebooklm-mcp callable",
|
|
220
|
+
required=False,
|
|
221
|
+
)
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
def run_validate(*, root_dir: Path | None = None) -> dict[str, Any]:
|
|
225
|
+
"""Run all validation checks and return a structured result.
|
|
226
|
+
|
|
227
|
+
Composes:
|
|
228
|
+
1. ``run_doctor()`` — install and runtime checks
|
|
229
|
+
2. Contract registry validation
|
|
230
|
+
3. Profile governor validation
|
|
231
|
+
4. Install integrity check
|
|
232
|
+
5. Optional NotebookLM check (only when selected in MCP config)
|
|
233
|
+
|
|
234
|
+
Returns a dict matching the ``ValidateResult`` schema:
|
|
235
|
+
``{"schema": "ValidateResult", "status": "pass"|"fail", "checks": [...], "version": "..."}``
|
|
236
|
+
"""
|
|
237
|
+
repo_root = root_dir or Path(__file__).resolve().parent.parent
|
|
238
|
+
|
|
239
|
+
checks: list[dict[str, Any]] = []
|
|
240
|
+
|
|
241
|
+
# 1. Compose doctor checks (never duplicate — delegate directly)
|
|
242
|
+
doctor_result = run_doctor(root_dir=repo_root)
|
|
243
|
+
checks.extend(doctor_result.get("checks", []))
|
|
244
|
+
|
|
245
|
+
# 2. Contract registry
|
|
246
|
+
checks.append(_check_contract_registry(repo_root))
|
|
247
|
+
|
|
248
|
+
# 3. Profile governor
|
|
249
|
+
checks.append(_check_profile_governor(repo_root))
|
|
250
|
+
|
|
251
|
+
# 4. Install integrity
|
|
252
|
+
checks.append(_check_install_integrity(repo_root))
|
|
253
|
+
|
|
254
|
+
if not any(c.get("name") == "plugin_compatibility" for c in checks):
|
|
255
|
+
checks.append(_check_plugin_compatibility(repo_root))
|
|
256
|
+
|
|
257
|
+
nb_check = _check_notebooklm(repo_root)
|
|
258
|
+
if nb_check is not None:
|
|
259
|
+
checks.append(nb_check)
|
|
260
|
+
|
|
261
|
+
has_blocker = any(c["status"] == "blocker" for c in checks)
|
|
262
|
+
|
|
263
|
+
return {
|
|
264
|
+
"schema": "ValidateResult",
|
|
265
|
+
"status": "fail" if has_blocker else "pass",
|
|
266
|
+
"checks": checks,
|
|
267
|
+
"version": CANONICAL_VERSION,
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
|
|
271
|
+
def format_text(result: dict[str, Any]) -> str:
|
|
272
|
+
"""Format a ValidateResult as human-readable text."""
|
|
273
|
+
lines: list[str] = []
|
|
274
|
+
for check in result.get("checks", []):
|
|
275
|
+
if check["status"] == "ok":
|
|
276
|
+
marker = "PASS"
|
|
277
|
+
elif check["status"] == "blocker":
|
|
278
|
+
marker = "BLOCKER"
|
|
279
|
+
else:
|
|
280
|
+
marker = "WARN"
|
|
281
|
+
req_tag = "" if check.get("required", True) else " (optional)"
|
|
282
|
+
lines.append(f" {marker:>7} {check['name']}: {check['message']}{req_tag}")
|
|
283
|
+
|
|
284
|
+
blockers = sum(1 for c in result.get("checks", []) if c["status"] == "blocker")
|
|
285
|
+
warnings = sum(1 for c in result.get("checks", []) if c["status"] == "warning")
|
|
286
|
+
passed = sum(1 for c in result.get("checks", []) if c["status"] == "ok")
|
|
287
|
+
lines.append(f"\nPASS [{passed}] | WARN [{warnings}] | BLOCKER [{blockers}]")
|
|
288
|
+
|
|
289
|
+
return "\n".join(lines)
|
|
@@ -4,7 +4,11 @@ import json
|
|
|
4
4
|
from pathlib import Path
|
|
5
5
|
from typing import cast
|
|
6
6
|
|
|
7
|
-
from runtime.background_verification import
|
|
7
|
+
from runtime.background_verification import (
|
|
8
|
+
publish_verification_state,
|
|
9
|
+
should_skip_validation,
|
|
10
|
+
skipped_stages_for_profile,
|
|
11
|
+
)
|
|
8
12
|
from runtime.runtime_contracts import read_run_state, write_run_state
|
|
9
13
|
|
|
10
14
|
|
|
@@ -80,8 +84,43 @@ class VerificationController:
|
|
|
80
84
|
payload = read_run_state(self.project_dir, "verification_controller", run_id)
|
|
81
85
|
return dict(payload) if isinstance(payload, dict) else {"run_id": run_id, "status": status}
|
|
82
86
|
|
|
87
|
+
def begin_run_with_profile(
|
|
88
|
+
self, run_id: str, evidence_profile: str | None = None
|
|
89
|
+
) -> dict[str, object]:
|
|
90
|
+
"""Start a run with evidence-profile-driven skip logic.
|
|
91
|
+
|
|
92
|
+
Computes which validation stages to skip based on the profile,
|
|
93
|
+
and includes step/total progress for HUD consumption.
|
|
94
|
+
"""
|
|
95
|
+
from runtime.evidence_requirements import requirements_for_profile
|
|
96
|
+
|
|
97
|
+
required = requirements_for_profile(evidence_profile)
|
|
98
|
+
skipped = skipped_stages_for_profile(evidence_profile)
|
|
99
|
+
|
|
100
|
+
state: dict[str, object] = {
|
|
101
|
+
"status": "running",
|
|
102
|
+
"blockers": [],
|
|
103
|
+
"evidence_links": [],
|
|
104
|
+
"progress": self._build_progress(
|
|
105
|
+
run_id,
|
|
106
|
+
step_total={
|
|
107
|
+
"step": 0,
|
|
108
|
+
"total": len(required),
|
|
109
|
+
"current_stage": required[0] if required else "",
|
|
110
|
+
"evidence_profile": evidence_profile or "code-change",
|
|
111
|
+
"skipped_stages": skipped,
|
|
112
|
+
},
|
|
113
|
+
),
|
|
114
|
+
}
|
|
115
|
+
_ = write_run_state(self.project_dir, "verification_controller", run_id, state)
|
|
116
|
+
payload = read_run_state(self.project_dir, "verification_controller", run_id)
|
|
117
|
+
return dict(payload) if isinstance(payload, dict) else {"run_id": run_id, "status": "running"}
|
|
118
|
+
|
|
83
119
|
def _build_progress(
|
|
84
|
-
self,
|
|
120
|
+
self,
|
|
121
|
+
run_id: str,
|
|
122
|
+
prior: dict[str, object] | None = None,
|
|
123
|
+
step_total: dict[str, object] | None = None,
|
|
85
124
|
) -> dict[str, object]:
|
|
86
125
|
progress = dict(prior) if isinstance(prior, dict) else {}
|
|
87
126
|
proof_artifacts = self._collect_run_artifacts("proof-gate", run_id)
|
|
@@ -98,6 +137,17 @@ class VerificationController:
|
|
|
98
137
|
"artifact_paths": proof_artifacts,
|
|
99
138
|
}
|
|
100
139
|
progress["tool_ledger"] = self._collect_tool_ledger(run_id)
|
|
140
|
+
|
|
141
|
+
# Merge step/total from explicit input or preserve prior values
|
|
142
|
+
if isinstance(step_total, dict):
|
|
143
|
+
progress["step"] = step_total.get("step", 0)
|
|
144
|
+
progress["total"] = step_total.get("total", 0)
|
|
145
|
+
if "current_stage" in step_total:
|
|
146
|
+
progress["current_stage"] = step_total["current_stage"]
|
|
147
|
+
if "evidence_profile" in step_total:
|
|
148
|
+
progress["evidence_profile"] = step_total["evidence_profile"]
|
|
149
|
+
if "skipped_stages" in step_total:
|
|
150
|
+
progress["skipped_stages"] = step_total["skipped_stages"]
|
|
101
151
|
return progress
|
|
102
152
|
|
|
103
153
|
def _collect_test_intent_lock(self, run_id: str) -> dict[str, object]:
|