@trac3er/oh-my-god 2.0.5 → 2.0.7
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 +57 -4
- package/.agents/skills/omg/claim-judge/SKILL.md +11 -0
- package/.agents/skills/omg/claim-judge/openai.yaml +13 -0
- package/.agents/skills/omg/codex-rules.md +33 -0
- package/.agents/skills/omg/plan-council/SKILL.md +11 -0
- package/.agents/skills/omg/plan-council/openai.yaml +12 -0
- package/.agents/skills/omg/proof-gate/SKILL.md +11 -0
- package/.agents/skills/omg/proof-gate/openai.yaml +13 -0
- package/.agents/skills/omg/test-intent-lock/SKILL.md +11 -0
- package/.agents/skills/omg/test-intent-lock/openai.yaml +13 -0
- package/.claude-plugin/marketplace.json +5 -5
- package/.claude-plugin/plugin.json +1 -1
- package/.claude-plugin/scripts/uninstall.sh +1 -1
- package/.mcp.json +0 -22
- package/CHANGELOG.md +13 -0
- package/OMG-setup.sh +64 -14
- package/OMG_COMPAT_CONTRACT.md +1 -1
- package/README.md +8 -6
- package/agents/omg-security-auditor.md +1 -1
- package/artifacts/release/.agents/skills/omg/AGENTS.fragment.md +52 -0
- package/artifacts/release/.agents/skills/omg/algorithms/SKILL.md +11 -0
- package/artifacts/release/.agents/skills/omg/algorithms/openai.yaml +11 -0
- package/artifacts/release/.agents/skills/omg/api-twin/SKILL.md +11 -0
- package/artifacts/release/.agents/skills/omg/api-twin/openai.yaml +12 -0
- package/artifacts/release/.agents/skills/omg/codex-mcp.toml +4 -0
- package/artifacts/release/.agents/skills/omg/codex-rules.md +29 -0
- package/artifacts/release/.agents/skills/omg/control-plane/SKILL.md +11 -0
- package/artifacts/release/.agents/skills/omg/control-plane/openai.yaml +14 -0
- package/artifacts/release/.agents/skills/omg/data-lineage/SKILL.md +11 -0
- package/artifacts/release/.agents/skills/omg/data-lineage/openai.yaml +12 -0
- package/artifacts/release/.agents/skills/omg/delta-classifier/SKILL.md +11 -0
- package/artifacts/release/.agents/skills/omg/delta-classifier/openai.yaml +12 -0
- package/artifacts/release/.agents/skills/omg/eval-gate/SKILL.md +11 -0
- package/artifacts/release/.agents/skills/omg/eval-gate/openai.yaml +12 -0
- package/artifacts/release/.agents/skills/omg/health/SKILL.md +11 -0
- package/artifacts/release/.agents/skills/omg/health/openai.yaml +11 -0
- package/artifacts/release/.agents/skills/omg/hook-governor/SKILL.md +11 -0
- package/artifacts/release/.agents/skills/omg/hook-governor/openai.yaml +11 -0
- package/artifacts/release/.agents/skills/omg/incident-replay/SKILL.md +11 -0
- package/artifacts/release/.agents/skills/omg/incident-replay/openai.yaml +12 -0
- package/artifacts/release/.agents/skills/omg/lsp-pack/SKILL.md +11 -0
- package/artifacts/release/.agents/skills/omg/lsp-pack/openai.yaml +11 -0
- package/artifacts/release/.agents/skills/omg/mcp-fabric/SKILL.md +11 -0
- package/artifacts/release/.agents/skills/omg/mcp-fabric/openai.yaml +13 -0
- package/artifacts/release/.agents/skills/omg/preflight/SKILL.md +11 -0
- package/artifacts/release/.agents/skills/omg/preflight/openai.yaml +12 -0
- package/artifacts/release/.agents/skills/omg/remote-supervisor/SKILL.md +11 -0
- package/artifacts/release/.agents/skills/omg/remote-supervisor/openai.yaml +12 -0
- package/artifacts/release/.agents/skills/omg/robotics/SKILL.md +11 -0
- package/artifacts/release/.agents/skills/omg/robotics/openai.yaml +11 -0
- package/artifacts/release/.agents/skills/omg/secure-worktree-pipeline/SKILL.md +11 -0
- package/artifacts/release/.agents/skills/omg/secure-worktree-pipeline/openai.yaml +12 -0
- package/artifacts/release/.agents/skills/omg/security-check/SKILL.md +11 -0
- package/artifacts/release/.agents/skills/omg/security-check/openai.yaml +13 -0
- package/artifacts/release/.agents/skills/omg/tracebank/SKILL.md +11 -0
- package/artifacts/release/.agents/skills/omg/tracebank/openai.yaml +12 -0
- package/artifacts/release/.agents/skills/omg/vision/SKILL.md +11 -0
- package/artifacts/release/.agents/skills/omg/vision/openai.yaml +11 -0
- package/artifacts/release/.claude-plugin/marketplace.json +36 -0
- package/artifacts/release/.claude-plugin/plugin.json +23 -0
- package/artifacts/release/.mcp.json +40 -0
- package/artifacts/release/OMG_COMPAT_CONTRACT.md +92 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/AGENTS.fragment.md +52 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/algorithms/SKILL.md +11 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/algorithms/openai.yaml +11 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/api-twin/SKILL.md +11 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/api-twin/openai.yaml +12 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/codex-mcp.toml +4 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/codex-rules.md +29 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/control-plane/SKILL.md +11 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/control-plane/openai.yaml +14 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/data-lineage/SKILL.md +11 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/data-lineage/openai.yaml +12 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/delta-classifier/SKILL.md +11 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/delta-classifier/openai.yaml +12 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/eval-gate/SKILL.md +11 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/eval-gate/openai.yaml +12 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/health/SKILL.md +11 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/health/openai.yaml +11 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/hook-governor/SKILL.md +11 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/hook-governor/openai.yaml +11 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/incident-replay/SKILL.md +11 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/incident-replay/openai.yaml +12 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/lsp-pack/SKILL.md +11 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/lsp-pack/openai.yaml +11 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/mcp-fabric/SKILL.md +11 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/mcp-fabric/openai.yaml +13 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/preflight/SKILL.md +11 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/preflight/openai.yaml +12 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/remote-supervisor/SKILL.md +11 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/remote-supervisor/openai.yaml +12 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/robotics/SKILL.md +11 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/robotics/openai.yaml +11 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/secure-worktree-pipeline/SKILL.md +11 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/secure-worktree-pipeline/openai.yaml +12 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/security-check/SKILL.md +11 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/security-check/openai.yaml +13 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/tracebank/SKILL.md +11 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/tracebank/openai.yaml +12 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/vision/SKILL.md +11 -0
- package/artifacts/release/dist/enterprise/bundle/.agents/skills/omg/vision/openai.yaml +11 -0
- package/artifacts/release/dist/enterprise/bundle/OMG_COMPAT_CONTRACT.md +92 -0
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/algorithms.yaml +45 -0
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/api-twin.yaml +48 -0
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/control-plane.yaml +151 -0
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/data-lineage.yaml +47 -0
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/delta-classifier.yaml +47 -0
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/eval-gate.yaml +47 -0
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/health.yaml +45 -0
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/hook-governor.yaml +97 -0
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/incident-replay.yaml +47 -0
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/lsp-pack.yaml +48 -0
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/mcp-fabric.yaml +53 -0
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/preflight.yaml +48 -0
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/remote-supervisor.yaml +49 -0
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/robotics.yaml +45 -0
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/secure-worktree-pipeline.yaml +54 -0
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/security-check.yaml +50 -0
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/tracebank.yaml +47 -0
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/vision.yaml +45 -0
- package/artifacts/release/dist/enterprise/bundle/registry/omg-capability.schema.json +296 -0
- package/artifacts/release/dist/enterprise/manifest.json +243 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/AGENTS.fragment.md +7 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/algorithms/SKILL.md +11 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/algorithms/openai.yaml +11 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/api-twin/SKILL.md +11 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/api-twin/openai.yaml +12 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/codex-mcp.toml +4 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/control-plane/SKILL.md +11 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/control-plane/openai.yaml +14 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/data-lineage/SKILL.md +11 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/data-lineage/openai.yaml +12 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/delta-classifier/SKILL.md +11 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/delta-classifier/openai.yaml +12 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/eval-gate/SKILL.md +11 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/eval-gate/openai.yaml +12 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/health/SKILL.md +11 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/health/openai.yaml +11 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/hook-governor/SKILL.md +11 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/hook-governor/openai.yaml +11 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/incident-replay/SKILL.md +11 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/incident-replay/openai.yaml +12 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/lsp-pack/SKILL.md +11 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/lsp-pack/openai.yaml +11 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/mcp-fabric/SKILL.md +11 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/mcp-fabric/openai.yaml +13 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/preflight/SKILL.md +11 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/preflight/openai.yaml +12 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/remote-supervisor/SKILL.md +11 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/remote-supervisor/openai.yaml +12 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/robotics/SKILL.md +11 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/robotics/openai.yaml +11 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/secure-worktree-pipeline/SKILL.md +11 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/secure-worktree-pipeline/openai.yaml +12 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/security-check/SKILL.md +11 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/security-check/openai.yaml +13 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/tracebank/SKILL.md +11 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/tracebank/openai.yaml +12 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/vision/SKILL.md +11 -0
- package/artifacts/release/dist/public/bundle/.agents/skills/omg/vision/openai.yaml +11 -0
- package/artifacts/release/dist/public/bundle/.claude-plugin/marketplace.json +36 -0
- package/artifacts/release/dist/public/bundle/.claude-plugin/plugin.json +23 -0
- package/artifacts/release/dist/public/bundle/.mcp.json +40 -0
- package/artifacts/release/dist/public/bundle/OMG_COMPAT_CONTRACT.md +92 -0
- package/artifacts/release/dist/public/bundle/registry/bundles/algorithms.yaml +45 -0
- package/artifacts/release/dist/public/bundle/registry/bundles/api-twin.yaml +48 -0
- package/artifacts/release/dist/public/bundle/registry/bundles/control-plane.yaml +151 -0
- package/artifacts/release/dist/public/bundle/registry/bundles/data-lineage.yaml +47 -0
- package/artifacts/release/dist/public/bundle/registry/bundles/delta-classifier.yaml +47 -0
- package/artifacts/release/dist/public/bundle/registry/bundles/eval-gate.yaml +47 -0
- package/artifacts/release/dist/public/bundle/registry/bundles/health.yaml +45 -0
- package/artifacts/release/dist/public/bundle/registry/bundles/hook-governor.yaml +97 -0
- package/artifacts/release/dist/public/bundle/registry/bundles/incident-replay.yaml +47 -0
- package/artifacts/release/dist/public/bundle/registry/bundles/lsp-pack.yaml +48 -0
- package/artifacts/release/dist/public/bundle/registry/bundles/mcp-fabric.yaml +53 -0
- package/artifacts/release/dist/public/bundle/registry/bundles/preflight.yaml +48 -0
- package/artifacts/release/dist/public/bundle/registry/bundles/remote-supervisor.yaml +49 -0
- package/artifacts/release/dist/public/bundle/registry/bundles/robotics.yaml +45 -0
- package/artifacts/release/dist/public/bundle/registry/bundles/secure-worktree-pipeline.yaml +54 -0
- package/artifacts/release/dist/public/bundle/registry/bundles/security-check.yaml +50 -0
- package/artifacts/release/dist/public/bundle/registry/bundles/tracebank.yaml +47 -0
- package/artifacts/release/dist/public/bundle/registry/bundles/vision.yaml +45 -0
- package/artifacts/release/dist/public/bundle/registry/omg-capability.schema.json +296 -0
- package/artifacts/release/dist/public/bundle/settings.json +526 -0
- package/artifacts/release/dist/public/manifest.json +255 -0
- package/artifacts/release/registry/bundles/algorithms.yaml +45 -0
- package/artifacts/release/registry/bundles/api-twin.yaml +48 -0
- package/artifacts/release/registry/bundles/control-plane.yaml +151 -0
- package/artifacts/release/registry/bundles/data-lineage.yaml +47 -0
- package/artifacts/release/registry/bundles/delta-classifier.yaml +47 -0
- package/artifacts/release/registry/bundles/eval-gate.yaml +47 -0
- package/artifacts/release/registry/bundles/health.yaml +45 -0
- package/artifacts/release/registry/bundles/hook-governor.yaml +97 -0
- package/artifacts/release/registry/bundles/incident-replay.yaml +47 -0
- package/artifacts/release/registry/bundles/lsp-pack.yaml +48 -0
- package/artifacts/release/registry/bundles/mcp-fabric.yaml +53 -0
- package/artifacts/release/registry/bundles/preflight.yaml +48 -0
- package/artifacts/release/registry/bundles/remote-supervisor.yaml +49 -0
- package/artifacts/release/registry/bundles/robotics.yaml +45 -0
- package/artifacts/release/registry/bundles/secure-worktree-pipeline.yaml +54 -0
- package/artifacts/release/registry/bundles/security-check.yaml +50 -0
- package/artifacts/release/registry/bundles/tracebank.yaml +47 -0
- package/artifacts/release/registry/bundles/vision.yaml +45 -0
- package/artifacts/release/registry/omg-capability.schema.json +296 -0
- package/artifacts/release/settings.json +594 -0
- package/build/lib/agents/__init__.py +1 -0
- package/build/lib/agents/designer.md +67 -0
- package/build/lib/agents/explore.md +60 -0
- package/build/lib/agents/model_roles.py +196 -0
- package/build/lib/agents/omg-api-builder.md +23 -0
- package/build/lib/agents/omg-architect-mode.md +41 -0
- package/build/lib/agents/omg-architect.md +13 -0
- package/build/lib/agents/omg-backend-engineer.md +41 -0
- package/build/lib/agents/omg-critic.md +16 -0
- package/build/lib/agents/omg-database-engineer.md +41 -0
- package/build/lib/agents/omg-escalation-router.md +17 -0
- package/build/lib/agents/omg-executor.md +12 -0
- package/build/lib/agents/omg-frontend-designer.md +41 -0
- package/build/lib/agents/omg-implement-mode.md +49 -0
- package/build/lib/agents/omg-infra-engineer.md +41 -0
- package/build/lib/agents/omg-qa-tester.md +16 -0
- package/build/lib/agents/omg-research-mode.md +41 -0
- package/build/lib/agents/omg-security-auditor.md +41 -0
- package/build/lib/agents/omg-testing-engineer.md +41 -0
- package/build/lib/agents/plan.md +80 -0
- package/build/lib/agents/quick_task.md +64 -0
- package/build/lib/agents/reviewer.md +83 -0
- package/build/lib/agents/task.md +71 -0
- package/build/lib/commands/OMG:ai-commit.md +113 -0
- package/build/lib/commands/OMG:api-twin.md +22 -0
- package/build/lib/commands/OMG:arch.md +313 -0
- package/build/lib/commands/OMG:ccg.md +22 -0
- package/build/lib/commands/OMG:compat.md +57 -0
- package/build/lib/commands/OMG:cost.md +181 -0
- package/build/lib/commands/OMG:crazy.md +125 -0
- package/build/lib/commands/OMG:create-agent.md +183 -0
- package/build/lib/commands/OMG:deps.md +248 -0
- package/build/lib/commands/OMG:doctor.md +37 -0
- package/build/lib/commands/OMG:domain-init.md +11 -0
- package/build/lib/commands/OMG:escalate.md +52 -0
- package/build/lib/commands/OMG:health-check.md +45 -0
- package/build/lib/commands/OMG:init.md +134 -0
- package/build/lib/commands/OMG:mode.md +44 -0
- package/build/lib/commands/OMG:preflight.md +26 -0
- package/build/lib/commands/OMG:project-init.md +11 -0
- package/build/lib/commands/OMG:ralph-start.md +43 -0
- package/build/lib/commands/OMG:ralph-stop.md +23 -0
- package/build/lib/commands/OMG:security-check.md +28 -0
- package/build/lib/commands/OMG:session-branch.md +85 -0
- package/build/lib/commands/OMG:session-fork.md +53 -0
- package/build/lib/commands/OMG:session-merge.md +134 -0
- package/build/lib/commands/OMG:setup.md +78 -0
- package/build/lib/commands/OMG:stats.md +225 -0
- package/build/lib/commands/OMG:teams.md +39 -0
- package/build/lib/commands/OMG:theme.md +44 -0
- package/build/lib/commands/__init__.py +1 -0
- package/build/lib/control_plane/__init__.py +2 -0
- package/build/lib/control_plane/openapi.yaml +260 -0
- package/build/lib/control_plane/server.py +147 -0
- package/build/lib/control_plane/service.py +222 -0
- package/build/lib/hooks/__init__.py +0 -0
- package/build/lib/hooks/_agent_registry.py +423 -0
- package/build/lib/hooks/_analytics.py +291 -0
- package/build/lib/hooks/_budget.py +31 -0
- package/build/lib/hooks/_common.py +569 -0
- package/build/lib/hooks/_compression_optimizer.py +119 -0
- package/build/lib/hooks/_cost_ledger.py +176 -0
- package/build/lib/hooks/_learnings.py +126 -0
- package/build/lib/hooks/_memory.py +103 -0
- package/build/lib/hooks/_protected_context.py +150 -0
- package/build/lib/hooks/_token_counter.py +221 -0
- package/build/lib/hooks/branch_manager.py +236 -0
- package/build/lib/hooks/budget_governor.py +232 -0
- package/build/lib/hooks/circuit-breaker.py +270 -0
- package/build/lib/hooks/compression_feedback.py +254 -0
- package/build/lib/hooks/config-guard.py +216 -0
- package/build/lib/hooks/context_pressure.py +53 -0
- package/build/lib/hooks/credential_store.py +1020 -0
- package/build/lib/hooks/fetch-rate-limits.py +212 -0
- package/build/lib/hooks/firewall.py +48 -0
- package/build/lib/hooks/hashline-formatter-bridge.py +224 -0
- package/build/lib/hooks/hashline-injector.py +273 -0
- package/build/lib/hooks/hashline-validator.py +216 -0
- package/build/lib/hooks/idle-detector.py +95 -0
- package/build/lib/hooks/intentgate-keyword-detector.py +188 -0
- package/build/lib/hooks/magic-keyword-router.py +195 -0
- package/build/lib/hooks/policy_engine.py +641 -0
- package/build/lib/hooks/post-tool-failure.py +19 -0
- package/build/lib/hooks/post-write.py +219 -0
- package/build/lib/hooks/post_write.py +46 -0
- package/build/lib/hooks/pre-compact.py +398 -0
- package/build/lib/hooks/pre-tool-inject.py +98 -0
- package/build/lib/hooks/prompt-enhancer.py +672 -0
- package/build/lib/hooks/quality-runner.py +191 -0
- package/build/lib/hooks/query.py +512 -0
- package/build/lib/hooks/secret-guard.py +61 -0
- package/build/lib/hooks/secret_audit.py +144 -0
- package/build/lib/hooks/security_validators.py +75 -0
- package/build/lib/hooks/session-end-capture.py +137 -0
- package/build/lib/hooks/session-start.py +277 -0
- package/build/lib/hooks/setup_wizard.py +646 -0
- package/build/lib/hooks/shadow_manager.py +344 -0
- package/build/lib/hooks/state_migration.py +225 -0
- package/build/lib/hooks/stop-gate.py +7 -0
- package/build/lib/hooks/stop_dispatcher.py +945 -0
- package/build/lib/hooks/test-validator.py +361 -0
- package/build/lib/hooks/test_generator_hook.py +123 -0
- package/build/lib/hooks/todo-state-tracker.py +114 -0
- package/build/lib/hooks/tool-ledger.py +149 -0
- package/build/lib/hooks/trust_review.py +585 -0
- package/build/lib/plugins/README.md +60 -0
- package/build/lib/plugins/__init__.py +1 -0
- package/build/lib/plugins/advanced/commands/OMG:code-review.md +114 -0
- package/build/lib/plugins/advanced/commands/OMG:deep-plan.md +265 -0
- package/build/lib/plugins/advanced/commands/OMG:handoff.md +115 -0
- package/build/lib/plugins/advanced/commands/OMG:learn.md +110 -0
- package/build/lib/plugins/advanced/commands/OMG:maintainer.md +31 -0
- package/build/lib/plugins/advanced/commands/OMG:ralph-start.md +43 -0
- package/build/lib/plugins/advanced/commands/OMG:ralph-stop.md +23 -0
- package/build/lib/plugins/advanced/commands/OMG:security-review.md +16 -0
- package/build/lib/plugins/advanced/commands/OMG:sequential-thinking.md +20 -0
- package/build/lib/plugins/advanced/commands/OMG:ship.md +46 -0
- package/build/lib/plugins/advanced/plugin.json +87 -0
- package/build/lib/plugins/core/plugin.json +145 -0
- package/build/lib/plugins/dephealth/__init__.py +0 -0
- package/build/lib/plugins/dephealth/cve_scanner.py +188 -0
- package/build/lib/plugins/dephealth/license_checker.py +135 -0
- package/build/lib/plugins/dephealth/manifest_detector.py +423 -0
- package/build/lib/plugins/dephealth/vuln_analyzer.py +169 -0
- package/build/lib/plugins/testgen/__init__.py +0 -0
- package/build/lib/plugins/testgen/codamosa_engine.py +402 -0
- package/build/lib/plugins/testgen/edge_case_synthesizer.py +184 -0
- package/build/lib/plugins/testgen/framework_detector.py +271 -0
- package/build/lib/plugins/testgen/skeleton_generator.py +219 -0
- package/build/lib/plugins/viz/__init__.py +0 -0
- package/build/lib/plugins/viz/ast_parser.py +139 -0
- package/build/lib/plugins/viz/diagram_generator.py +192 -0
- package/build/lib/plugins/viz/graph_builder.py +444 -0
- package/build/lib/plugins/viz/native_parsers.py +259 -0
- package/build/lib/plugins/viz/regex_parser.py +112 -0
- package/build/lib/registry/__init__.py +1 -0
- package/build/lib/registry/bundles/algorithms.yaml +45 -0
- package/build/lib/registry/bundles/api-twin.yaml +48 -0
- package/build/lib/registry/bundles/claim-judge.yaml +49 -0
- package/build/lib/registry/bundles/control-plane.yaml +151 -0
- package/build/lib/registry/bundles/data-lineage.yaml +47 -0
- package/build/lib/registry/bundles/delta-classifier.yaml +47 -0
- package/build/lib/registry/bundles/eval-gate.yaml +47 -0
- package/build/lib/registry/bundles/health.yaml +45 -0
- package/build/lib/registry/bundles/hook-governor.yaml +97 -0
- package/build/lib/registry/bundles/incident-replay.yaml +47 -0
- package/build/lib/registry/bundles/lsp-pack.yaml +48 -0
- package/build/lib/registry/bundles/mcp-fabric.yaml +53 -0
- package/build/lib/registry/bundles/plan-council.yaml +51 -0
- package/build/lib/registry/bundles/preflight.yaml +48 -0
- package/build/lib/registry/bundles/proof-gate.yaml +49 -0
- package/build/lib/registry/bundles/remote-supervisor.yaml +49 -0
- package/build/lib/registry/bundles/robotics.yaml +45 -0
- package/build/lib/registry/bundles/secure-worktree-pipeline.yaml +54 -0
- package/build/lib/registry/bundles/security-check.yaml +50 -0
- package/build/lib/registry/bundles/test-intent-lock.yaml +49 -0
- package/build/lib/registry/bundles/tracebank.yaml +47 -0
- package/build/lib/registry/bundles/vision.yaml +45 -0
- package/build/lib/registry/omg-capability.schema.json +296 -0
- package/build/lib/registry/verify_artifact.py +90 -0
- package/build/lib/runtime/__init__.py +32 -0
- package/build/lib/runtime/adapters/__init__.py +13 -0
- package/build/lib/runtime/adapters/claude.py +63 -0
- package/build/lib/runtime/adapters/gpt.py +56 -0
- package/build/lib/runtime/adapters/local.py +56 -0
- package/build/lib/runtime/adoption.py +212 -0
- package/build/lib/runtime/api_twin.py +450 -0
- package/build/lib/runtime/asset_loader.py +62 -0
- package/build/lib/runtime/business_workflow.py +234 -0
- package/build/lib/runtime/claim_judge.py +95 -0
- package/build/lib/runtime/cli_provider.py +85 -0
- package/build/lib/runtime/compat.py +1459 -0
- package/build/lib/runtime/contract_compiler.py +1918 -0
- package/build/lib/runtime/custom_agent_loader.py +366 -0
- package/build/lib/runtime/data_lineage.py +73 -0
- package/build/lib/runtime/delta_classifier.py +81 -0
- package/build/lib/runtime/dispatcher.py +47 -0
- package/build/lib/runtime/domain_packs.py +46 -0
- package/build/lib/runtime/ecosystem.py +371 -0
- package/build/lib/runtime/eval_gate.py +96 -0
- package/build/lib/runtime/guide_assert.py +45 -0
- package/build/lib/runtime/incident_replay.py +47 -0
- package/build/lib/runtime/legacy_compat.py +7 -0
- package/build/lib/runtime/mcp_config_writers.py +233 -0
- package/build/lib/runtime/mcp_lifecycle.py +175 -0
- package/build/lib/runtime/mcp_memory_server.py +135 -0
- package/build/lib/runtime/memory_parsers/__init__.py +0 -0
- package/build/lib/runtime/memory_parsers/chatgpt_parser.py +257 -0
- package/build/lib/runtime/memory_parsers/claude_import.py +107 -0
- package/build/lib/runtime/memory_parsers/export.py +97 -0
- package/build/lib/runtime/memory_parsers/gemini_import.py +91 -0
- package/build/lib/runtime/memory_parsers/kimi_import.py +91 -0
- package/build/lib/runtime/memory_store.py +215 -0
- package/build/lib/runtime/omc_compat.py +7 -0
- package/build/lib/runtime/omg_compat_contract_snapshot.json +916 -0
- package/build/lib/runtime/omg_contract_snapshot.json +916 -0
- package/build/lib/runtime/omg_mcp_server.py +212 -0
- package/build/lib/runtime/playwright_pack.py +169 -0
- package/build/lib/runtime/preflight.py +117 -0
- package/build/lib/runtime/proof_chain.py +228 -0
- package/build/lib/runtime/proof_gate.py +163 -0
- package/build/lib/runtime/providers/__init__.py +0 -0
- package/build/lib/runtime/providers/codex_provider.py +102 -0
- package/build/lib/runtime/providers/gemini_provider.py +109 -0
- package/build/lib/runtime/providers/kimi_provider.py +132 -0
- package/build/lib/runtime/remote_supervisor.py +64 -0
- package/build/lib/runtime/runtime_profile.py +61 -0
- package/build/lib/runtime/security_check.py +965 -0
- package/build/lib/runtime/subagent_dispatcher.py +469 -0
- package/build/lib/runtime/team_router.py +1167 -0
- package/build/lib/runtime/test_intent_lock.py +91 -0
- package/build/lib/runtime/tmux_session_manager.py +169 -0
- package/build/lib/runtime/tracebank.py +95 -0
- package/build/lib/runtime/untrusted_content.py +269 -0
- package/commands/OMG:doctor.md +37 -0
- package/commands/OMG:preflight.md +1 -1
- package/control_plane/openapi.yaml +33 -1
- package/control_plane/server.py +26 -2
- package/control_plane/service.py +37 -0
- package/dist/enterprise/bundle/.agents/skills/omg/AGENTS.fragment.md +50 -3
- package/dist/enterprise/bundle/.agents/skills/omg/codex-rules.md +29 -0
- package/dist/enterprise/bundle/.claude-plugin/marketplace.json +5 -5
- 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/commands/OMG:code-review.md +114 -0
- package/dist/enterprise/bundle/plugins/advanced/commands/OMG:deep-plan.md +221 -0
- package/dist/enterprise/bundle/plugins/advanced/commands/OMG:handoff.md +115 -0
- package/dist/enterprise/bundle/plugins/advanced/commands/OMG:learn.md +110 -0
- package/dist/enterprise/bundle/plugins/advanced/commands/OMG:maintainer.md +31 -0
- package/dist/enterprise/bundle/plugins/advanced/commands/OMG:ralph-start.md +43 -0
- package/dist/enterprise/bundle/plugins/advanced/commands/OMG:ralph-stop.md +23 -0
- package/dist/enterprise/bundle/plugins/advanced/commands/OMG:security-review.md +16 -0
- package/dist/enterprise/bundle/plugins/advanced/commands/OMG:sequential-thinking.md +20 -0
- package/dist/enterprise/bundle/plugins/advanced/commands/OMG:ship.md +46 -0
- package/dist/enterprise/bundle/plugins/advanced/plugin.json +87 -0
- 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/control-plane.yaml +91 -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/preflight.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/tracebank.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/vision.yaml +1 -1
- package/dist/enterprise/bundle/registry/omg-capability.schema.json +217 -1
- package/dist/enterprise/bundle/settings.json +219 -6
- package/dist/enterprise/manifest.json +73 -25
- package/dist/public/bundle/.agents/skills/omg/AGENTS.fragment.md +50 -3
- package/dist/public/bundle/.agents/skills/omg/codex-rules.md +29 -0
- package/dist/public/bundle/.claude-plugin/marketplace.json +5 -5
- 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/commands/OMG:code-review.md +114 -0
- package/dist/public/bundle/plugins/advanced/commands/OMG:deep-plan.md +221 -0
- package/dist/public/bundle/plugins/advanced/commands/OMG:handoff.md +115 -0
- package/dist/public/bundle/plugins/advanced/commands/OMG:learn.md +110 -0
- package/dist/public/bundle/plugins/advanced/commands/OMG:maintainer.md +31 -0
- package/dist/public/bundle/plugins/advanced/commands/OMG:ralph-start.md +43 -0
- package/dist/public/bundle/plugins/advanced/commands/OMG:ralph-stop.md +23 -0
- package/dist/public/bundle/plugins/advanced/commands/OMG:security-review.md +16 -0
- package/dist/public/bundle/plugins/advanced/commands/OMG:sequential-thinking.md +20 -0
- package/dist/public/bundle/plugins/advanced/commands/OMG:ship.md +46 -0
- package/dist/public/bundle/plugins/advanced/plugin.json +87 -0
- 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/control-plane.yaml +91 -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/preflight.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/tracebank.yaml +1 -1
- package/dist/public/bundle/registry/bundles/vision.yaml +1 -1
- package/dist/public/bundle/registry/omg-capability.schema.json +217 -1
- package/dist/public/bundle/settings.json +218 -3
- package/dist/public/manifest.json +73 -25
- package/docs/proof.md +16 -6
- package/docs/release-checklist.md +2 -0
- package/hooks/policy_engine.py +122 -17
- package/hooks/setup_wizard.py +52 -12
- package/hooks/shadow_manager.py +21 -0
- package/package.json +2 -2
- package/plugins/README.md +5 -1
- package/plugins/advanced/commands/OMG:deep-plan.md +50 -6
- package/plugins/advanced/commands/OMG:ship.md +1 -1
- package/plugins/advanced/plugin.json +1 -10
- package/plugins/core/plugin.json +7 -1
- package/pyproject.toml +2 -2
- package/registry/bundles/algorithms.yaml +1 -1
- package/registry/bundles/api-twin.yaml +1 -1
- package/registry/bundles/claim-judge.yaml +49 -0
- package/registry/bundles/control-plane.yaml +91 -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 +51 -0
- package/registry/bundles/preflight.yaml +1 -1
- package/registry/bundles/proof-gate.yaml +49 -0
- 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 +49 -0
- package/registry/bundles/tracebank.yaml +1 -1
- package/registry/bundles/vision.yaml +1 -1
- package/registry/omg-capability.schema.json +217 -1
- package/runtime/adoption.py +1 -1
- package/runtime/api_twin.py +279 -8
- package/runtime/business_workflow.py +14 -0
- package/runtime/claim_judge.py +95 -0
- package/runtime/compat.py +139 -0
- package/runtime/contract_compiler.py +1099 -28
- package/runtime/ecosystem.py +1 -1
- package/runtime/eval_gate.py +48 -2
- package/runtime/mcp_config_writers.py +12 -0
- package/runtime/mcp_lifecycle.py +31 -9
- package/runtime/mcp_memory_server.py +1 -1
- package/runtime/omg_compat_contract_snapshot.json +1 -1
- package/runtime/omg_contract_snapshot.json +1 -1
- package/runtime/omg_mcp_server.py +13 -8
- package/runtime/playwright_pack.py +169 -0
- package/runtime/preflight.py +45 -1
- package/runtime/proof_chain.py +228 -0
- package/runtime/proof_gate.py +163 -0
- package/runtime/security_check.py +523 -22
- package/runtime/team_router.py +6 -6
- package/runtime/test_intent_lock.py +91 -0
- package/runtime/tracebank.py +43 -1
- package/runtime/untrusted_content.py +172 -5
- package/scripts/check-omg-public-ready.py +77 -0
- package/scripts/omg.py +28 -9
- package/scripts/verify-standalone.sh +7 -0
- package/settings.json +219 -6
|
@@ -3,14 +3,17 @@ from __future__ import annotations
|
|
|
3
3
|
|
|
4
4
|
import hashlib
|
|
5
5
|
import asyncio
|
|
6
|
+
import importlib
|
|
6
7
|
import json
|
|
7
8
|
import os
|
|
8
9
|
from pathlib import Path
|
|
10
|
+
import re
|
|
9
11
|
import shutil
|
|
10
12
|
import subprocess
|
|
11
13
|
import sys
|
|
12
14
|
import tempfile
|
|
13
15
|
from typing import Any, Iterable
|
|
16
|
+
from urllib.parse import urlparse
|
|
14
17
|
import zipfile
|
|
15
18
|
|
|
16
19
|
import yaml
|
|
@@ -32,6 +35,10 @@ SUPPORTED_HOSTS = ("claude", "codex")
|
|
|
32
35
|
SUPPORTED_CHANNELS = ("public", "enterprise")
|
|
33
36
|
DEFAULT_REQUIRED_BUNDLES = (
|
|
34
37
|
"control-plane",
|
|
38
|
+
"plan-council",
|
|
39
|
+
"claim-judge",
|
|
40
|
+
"test-intent-lock",
|
|
41
|
+
"proof-gate",
|
|
35
42
|
"hook-governor",
|
|
36
43
|
"mcp-fabric",
|
|
37
44
|
"lsp-pack",
|
|
@@ -50,6 +57,11 @@ DEFAULT_REQUIRED_BUNDLES = (
|
|
|
50
57
|
"data-lineage",
|
|
51
58
|
"remote-supervisor",
|
|
52
59
|
)
|
|
60
|
+
REQUIRED_ADVANCED_PLUGIN_ARTIFACTS = (
|
|
61
|
+
"bundle/plugins/advanced/plugin.json",
|
|
62
|
+
"bundle/plugins/advanced/commands/OMG:deep-plan.md",
|
|
63
|
+
"bundle/plugins/advanced/commands/OMG:security-review.md",
|
|
64
|
+
)
|
|
53
65
|
REQUIRED_DOC_TOKENS = (
|
|
54
66
|
"execution_contract",
|
|
55
67
|
"tool_policy",
|
|
@@ -74,6 +86,237 @@ REQUIRED_BUNDLE_FIELDS = (
|
|
|
74
86
|
"execution_contract",
|
|
75
87
|
"channel_overrides",
|
|
76
88
|
)
|
|
89
|
+
REQUIRED_POLICY_MODEL_FIELDS = (
|
|
90
|
+
"trust_tiers",
|
|
91
|
+
"tool_policies",
|
|
92
|
+
"protected_paths",
|
|
93
|
+
"evidence_contract",
|
|
94
|
+
"host_rules",
|
|
95
|
+
)
|
|
96
|
+
REQUIRED_CLAUDE_HOOK_EVENTS = (
|
|
97
|
+
"UserPromptSubmit",
|
|
98
|
+
"PreToolUse",
|
|
99
|
+
"PostToolUse",
|
|
100
|
+
"PostToolUseFailure",
|
|
101
|
+
"InstructionsLoaded",
|
|
102
|
+
)
|
|
103
|
+
REQUIRED_CLAUDE_SUBAGENT_NAMES = ("security-reviewer", "release-manager")
|
|
104
|
+
REQUIRED_CODEX_AGENTS_SECTIONS = (
|
|
105
|
+
"## Build & Test",
|
|
106
|
+
"## Protected Paths",
|
|
107
|
+
"## Evidence Contract",
|
|
108
|
+
"## Required Skills",
|
|
109
|
+
"## Web Search Policy",
|
|
110
|
+
"## Approval Constraints",
|
|
111
|
+
)
|
|
112
|
+
REQUIRED_CODEX_OUTPUTS = (
|
|
113
|
+
"AGENTS.fragment.md",
|
|
114
|
+
"codex-rules.md",
|
|
115
|
+
"codex-mcp.toml",
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
def _ensure_list(
|
|
120
|
+
*,
|
|
121
|
+
bundle_id: str,
|
|
122
|
+
path: str,
|
|
123
|
+
value: Any,
|
|
124
|
+
errors: list[str],
|
|
125
|
+
min_items: int = 1,
|
|
126
|
+
) -> list[Any]:
|
|
127
|
+
if not isinstance(value, list):
|
|
128
|
+
errors.append(f"{bundle_id}: {path} must be a list")
|
|
129
|
+
return []
|
|
130
|
+
if len(value) < min_items:
|
|
131
|
+
errors.append(f"{bundle_id}: {path} must contain at least {min_items} item(s)")
|
|
132
|
+
return value
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _ensure_dict(*, bundle_id: str, path: str, value: Any, errors: list[str]) -> dict[str, Any]:
|
|
136
|
+
if not isinstance(value, dict):
|
|
137
|
+
errors.append(f"{bundle_id}: {path} must be an object")
|
|
138
|
+
return {}
|
|
139
|
+
return value
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def _validate_host_rule(
|
|
143
|
+
*,
|
|
144
|
+
bundle_id: str,
|
|
145
|
+
host_name: str,
|
|
146
|
+
host_rule: Any,
|
|
147
|
+
required_fields: tuple[str, ...],
|
|
148
|
+
errors: list[str],
|
|
149
|
+
) -> None:
|
|
150
|
+
path = f"policy_model.host_rules.{host_name}"
|
|
151
|
+
host_payload = _ensure_dict(bundle_id=bundle_id, path=path, value=host_rule, errors=errors)
|
|
152
|
+
if not host_payload:
|
|
153
|
+
return
|
|
154
|
+
for field in required_fields:
|
|
155
|
+
if field not in host_payload:
|
|
156
|
+
errors.append(f"{bundle_id}: malformed host_rules entry for {host_name}: missing '{field}'")
|
|
157
|
+
continue
|
|
158
|
+
_ensure_list(
|
|
159
|
+
bundle_id=bundle_id,
|
|
160
|
+
path=f"{path}.{field}",
|
|
161
|
+
value=host_payload[field],
|
|
162
|
+
errors=errors,
|
|
163
|
+
min_items=1,
|
|
164
|
+
)
|
|
165
|
+
|
|
166
|
+
|
|
167
|
+
def _validate_policy_model(bundle_id: str, policy_model: Any) -> list[str]:
|
|
168
|
+
errors: list[str] = []
|
|
169
|
+
payload = _ensure_dict(bundle_id=bundle_id, path="policy_model", value=policy_model, errors=errors)
|
|
170
|
+
if not payload:
|
|
171
|
+
return errors
|
|
172
|
+
|
|
173
|
+
for field in REQUIRED_POLICY_MODEL_FIELDS:
|
|
174
|
+
if field not in payload:
|
|
175
|
+
errors.append(f"{bundle_id}: policy_model missing field {field}")
|
|
176
|
+
|
|
177
|
+
tier_names: set[str] = set()
|
|
178
|
+
for index, tier in enumerate(
|
|
179
|
+
_ensure_list(
|
|
180
|
+
bundle_id=bundle_id,
|
|
181
|
+
path="policy_model.trust_tiers",
|
|
182
|
+
value=payload.get("trust_tiers", []),
|
|
183
|
+
errors=errors,
|
|
184
|
+
)
|
|
185
|
+
):
|
|
186
|
+
tier_payload = _ensure_dict(
|
|
187
|
+
bundle_id=bundle_id,
|
|
188
|
+
path=f"policy_model.trust_tiers[{index}]",
|
|
189
|
+
value=tier,
|
|
190
|
+
errors=errors,
|
|
191
|
+
)
|
|
192
|
+
if not tier_payload:
|
|
193
|
+
continue
|
|
194
|
+
for field in ("name", "level", "label", "allowed_sources"):
|
|
195
|
+
if field not in tier_payload:
|
|
196
|
+
errors.append(f"{bundle_id}: policy_model.trust_tiers[{index}] missing field {field}")
|
|
197
|
+
if isinstance(tier_payload.get("name"), str) and tier_payload["name"].strip():
|
|
198
|
+
tier_names.add(tier_payload["name"].strip())
|
|
199
|
+
if "allowed_sources" in tier_payload:
|
|
200
|
+
_ensure_list(
|
|
201
|
+
bundle_id=bundle_id,
|
|
202
|
+
path=f"policy_model.trust_tiers[{index}].allowed_sources",
|
|
203
|
+
value=tier_payload.get("allowed_sources"),
|
|
204
|
+
errors=errors,
|
|
205
|
+
min_items=1,
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
for index, tool in enumerate(
|
|
209
|
+
_ensure_list(
|
|
210
|
+
bundle_id=bundle_id,
|
|
211
|
+
path="policy_model.tool_policies",
|
|
212
|
+
value=payload.get("tool_policies", []),
|
|
213
|
+
errors=errors,
|
|
214
|
+
)
|
|
215
|
+
):
|
|
216
|
+
tool_payload = _ensure_dict(
|
|
217
|
+
bundle_id=bundle_id,
|
|
218
|
+
path=f"policy_model.tool_policies[{index}]",
|
|
219
|
+
value=tool,
|
|
220
|
+
errors=errors,
|
|
221
|
+
)
|
|
222
|
+
if not tool_payload:
|
|
223
|
+
continue
|
|
224
|
+
for field in ("tool_name", "allowed_tiers", "requires_approval"):
|
|
225
|
+
if field not in tool_payload:
|
|
226
|
+
errors.append(f"{bundle_id}: policy_model.tool_policies[{index}] missing field {field}")
|
|
227
|
+
allowed_tiers = _ensure_list(
|
|
228
|
+
bundle_id=bundle_id,
|
|
229
|
+
path=f"policy_model.tool_policies[{index}].allowed_tiers",
|
|
230
|
+
value=tool_payload.get("allowed_tiers", []),
|
|
231
|
+
errors=errors,
|
|
232
|
+
min_items=1,
|
|
233
|
+
)
|
|
234
|
+
if tier_names:
|
|
235
|
+
unknown_tiers = sorted(
|
|
236
|
+
tier_name
|
|
237
|
+
for tier_name in allowed_tiers
|
|
238
|
+
if isinstance(tier_name, str) and tier_name not in tier_names
|
|
239
|
+
)
|
|
240
|
+
if unknown_tiers:
|
|
241
|
+
errors.append(
|
|
242
|
+
f"{bundle_id}: policy_model.tool_policies[{index}] references unknown tiers {unknown_tiers}"
|
|
243
|
+
)
|
|
244
|
+
|
|
245
|
+
for index, item in enumerate(
|
|
246
|
+
_ensure_list(
|
|
247
|
+
bundle_id=bundle_id,
|
|
248
|
+
path="policy_model.protected_paths",
|
|
249
|
+
value=payload.get("protected_paths", []),
|
|
250
|
+
errors=errors,
|
|
251
|
+
)
|
|
252
|
+
):
|
|
253
|
+
path_payload = _ensure_dict(
|
|
254
|
+
bundle_id=bundle_id,
|
|
255
|
+
path=f"policy_model.protected_paths[{index}]",
|
|
256
|
+
value=item,
|
|
257
|
+
errors=errors,
|
|
258
|
+
)
|
|
259
|
+
if not path_payload:
|
|
260
|
+
continue
|
|
261
|
+
for field in ("path_pattern", "required_tier"):
|
|
262
|
+
if field not in path_payload:
|
|
263
|
+
errors.append(f"{bundle_id}: policy_model.protected_paths[{index}] missing field {field}")
|
|
264
|
+
required_tier = path_payload.get("required_tier")
|
|
265
|
+
if tier_names and isinstance(required_tier, str) and required_tier not in tier_names:
|
|
266
|
+
errors.append(
|
|
267
|
+
f"{bundle_id}: policy_model.protected_paths[{index}] references unknown tier '{required_tier}'"
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
evidence_contract = _ensure_dict(
|
|
271
|
+
bundle_id=bundle_id,
|
|
272
|
+
path="policy_model.evidence_contract",
|
|
273
|
+
value=payload.get("evidence_contract", {}),
|
|
274
|
+
errors=errors,
|
|
275
|
+
)
|
|
276
|
+
for field in ("timestamp", "executor", "trace_id", "lineage"):
|
|
277
|
+
if field not in evidence_contract:
|
|
278
|
+
errors.append(f"{bundle_id}: policy_model.evidence_contract missing field {field}")
|
|
279
|
+
|
|
280
|
+
host_rules = _ensure_dict(
|
|
281
|
+
bundle_id=bundle_id,
|
|
282
|
+
path="policy_model.host_rules",
|
|
283
|
+
value=payload.get("host_rules", {}),
|
|
284
|
+
errors=errors,
|
|
285
|
+
)
|
|
286
|
+
_validate_host_rule(
|
|
287
|
+
bundle_id=bundle_id,
|
|
288
|
+
host_name="claude",
|
|
289
|
+
host_rule=host_rules.get("claude"),
|
|
290
|
+
required_fields=("compilation_targets", "hooks", "subagents", "skills"),
|
|
291
|
+
errors=errors,
|
|
292
|
+
)
|
|
293
|
+
_validate_host_rule(
|
|
294
|
+
bundle_id=bundle_id,
|
|
295
|
+
host_name="codex",
|
|
296
|
+
host_rule=host_rules.get("codex"),
|
|
297
|
+
required_fields=("compilation_targets", "skills", "agents_fragments", "rules", "automations"),
|
|
298
|
+
errors=errors,
|
|
299
|
+
)
|
|
300
|
+
return errors
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def _policy_model_for_bundle(bundles: Iterable[dict[str, Any]], bundle_id: str) -> dict[str, Any] | None:
|
|
304
|
+
for bundle in bundles:
|
|
305
|
+
if str(bundle.get("id", "")) == bundle_id and isinstance(bundle.get("policy_model"), dict):
|
|
306
|
+
return dict(bundle["policy_model"])
|
|
307
|
+
return None
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
def _policy_protected_paths(policy_model: dict[str, Any] | None, *, channel: str) -> list[str]:
|
|
311
|
+
if not policy_model:
|
|
312
|
+
return _protected_paths_for_channel(channel)
|
|
313
|
+
values: list[str] = []
|
|
314
|
+
for item in policy_model.get("protected_paths", []):
|
|
315
|
+
if isinstance(item, dict):
|
|
316
|
+
pattern = str(item.get("path_pattern", "")).strip()
|
|
317
|
+
if pattern:
|
|
318
|
+
values.append(pattern)
|
|
319
|
+
return values or _protected_paths_for_channel(channel)
|
|
77
320
|
|
|
78
321
|
|
|
79
322
|
def _resolve_root(root_dir: str | Path | None) -> Path:
|
|
@@ -211,6 +454,8 @@ def validate_contract_registry(root_dir: str | Path | None = None) -> dict[str,
|
|
|
211
454
|
bad_hosts = [host for host in hosts if host not in SUPPORTED_HOSTS]
|
|
212
455
|
if bad_hosts:
|
|
213
456
|
errors.append(f"{bundle_id}: unsupported hosts {bad_hosts}")
|
|
457
|
+
if "policy_model" in bundle:
|
|
458
|
+
errors.extend(_validate_policy_model(bundle_id, bundle.get("policy_model")))
|
|
214
459
|
|
|
215
460
|
missing_bundles = [bundle_id for bundle_id in DEFAULT_REQUIRED_BUNDLES if bundle_id not in bundle_ids]
|
|
216
461
|
for bundle_id in missing_bundles:
|
|
@@ -244,31 +489,33 @@ def _copy_contract_inputs(root: Path, output_root: Path) -> list[Path]:
|
|
|
244
489
|
dst = output_root / rel_path
|
|
245
490
|
_write_text(dst, src.read_text(encoding="utf-8"))
|
|
246
491
|
copied.append(dst)
|
|
492
|
+
|
|
493
|
+
# Copy advanced plugin artifacts (plugin.json + all command markdown files)
|
|
494
|
+
advanced_plugin_json = Path("plugins") / "advanced" / "plugin.json"
|
|
495
|
+
try:
|
|
496
|
+
src = resolve_asset(advanced_plugin_json)
|
|
497
|
+
dst = output_root / advanced_plugin_json
|
|
498
|
+
_write_text(dst, src.read_text(encoding="utf-8"))
|
|
499
|
+
copied.append(dst)
|
|
500
|
+
except FileNotFoundError:
|
|
501
|
+
pass
|
|
502
|
+
|
|
503
|
+
advanced_commands = resolve_assets(Path("plugins") / "advanced" / "commands", suffix=".md")
|
|
504
|
+
for src in advanced_commands:
|
|
505
|
+
rel = Path("plugins") / "advanced" / "commands" / src.name
|
|
506
|
+
dst = output_root / rel
|
|
507
|
+
_write_text(dst, src.read_text(encoding="utf-8"))
|
|
508
|
+
copied.append(dst)
|
|
509
|
+
|
|
247
510
|
return copied
|
|
248
511
|
|
|
249
512
|
|
|
250
513
|
def _base_mcp_servers() -> dict[str, Any]:
|
|
251
514
|
return {
|
|
252
|
-
"context7": {
|
|
253
|
-
"command": "npx",
|
|
254
|
-
"args": ["@upstash/context7-mcp@2.1.3"],
|
|
255
|
-
},
|
|
256
515
|
"filesystem": {
|
|
257
516
|
"command": "npx",
|
|
258
517
|
"args": ["@modelcontextprotocol/server-filesystem@2026.1.14", "."],
|
|
259
518
|
},
|
|
260
|
-
"websearch": {
|
|
261
|
-
"command": "npx",
|
|
262
|
-
"args": ["@zhafron/mcp-web-search@1.2.2"],
|
|
263
|
-
},
|
|
264
|
-
"chrome-devtools": {
|
|
265
|
-
"command": "npx",
|
|
266
|
-
"args": ["chrome-devtools-mcp@0.19.0"],
|
|
267
|
-
},
|
|
268
|
-
"omg-memory": {
|
|
269
|
-
"type": "http",
|
|
270
|
-
"url": "http://127.0.0.1:8765/mcp",
|
|
271
|
-
},
|
|
272
519
|
"omg-control": {
|
|
273
520
|
"command": "python3",
|
|
274
521
|
"args": ["-m", "runtime.omg_mcp_server"],
|
|
@@ -306,7 +553,7 @@ def _build_claude_marketplace() -> dict[str, Any]:
|
|
|
306
553
|
"description": "Marketplace metadata for the OMG Claude plugin",
|
|
307
554
|
"owner": {"name": "trac3er00"},
|
|
308
555
|
"metadata": {
|
|
309
|
-
"description": "OMG - Oh-My-God for Claude Code",
|
|
556
|
+
"description": "OMG - Oh-My-God for Claude Code and supported agent hosts",
|
|
310
557
|
"version": CANONICAL_VERSION,
|
|
311
558
|
"homepage": CANONICAL_REPO_URL,
|
|
312
559
|
"repository": CANONICAL_REPO_URL,
|
|
@@ -314,7 +561,7 @@ def _build_claude_marketplace() -> dict[str, Any]:
|
|
|
314
561
|
"plugins": [
|
|
315
562
|
{
|
|
316
563
|
"name": CANONICAL_PLUGIN_ID,
|
|
317
|
-
|
|
564
|
+
"description": "OMG plugin layer for Claude Code and supported agent hosts with native setup, orchestration, and interop.",
|
|
318
565
|
"version": CANONICAL_VERSION,
|
|
319
566
|
"source": "./",
|
|
320
567
|
"author": {"name": "trac3er00"},
|
|
@@ -375,12 +622,166 @@ def _protected_paths_for_channel(channel: str) -> list[str]:
|
|
|
375
622
|
return paths
|
|
376
623
|
|
|
377
624
|
|
|
625
|
+
def _default_claude_hook_registrations() -> dict[str, list[dict[str, Any]]]:
|
|
626
|
+
"""Default OMG hook registrations for each required Claude event."""
|
|
627
|
+
return {
|
|
628
|
+
"UserPromptSubmit": [
|
|
629
|
+
{
|
|
630
|
+
"hooks": [
|
|
631
|
+
{
|
|
632
|
+
"type": "command",
|
|
633
|
+
"command": 'python3 "$HOME/.claude/hooks/user-prompt-submit.py"',
|
|
634
|
+
"timeout": 10,
|
|
635
|
+
}
|
|
636
|
+
],
|
|
637
|
+
}
|
|
638
|
+
],
|
|
639
|
+
"PreToolUse": [
|
|
640
|
+
{
|
|
641
|
+
"hooks": [
|
|
642
|
+
{
|
|
643
|
+
"type": "command",
|
|
644
|
+
"command": 'python3 "$HOME/.claude/hooks/firewall.py"',
|
|
645
|
+
"timeout": 10,
|
|
646
|
+
}
|
|
647
|
+
],
|
|
648
|
+
"matcher": "Bash",
|
|
649
|
+
},
|
|
650
|
+
{
|
|
651
|
+
"hooks": [
|
|
652
|
+
{
|
|
653
|
+
"type": "command",
|
|
654
|
+
"command": 'python3 "$HOME/.claude/hooks/secret-guard.py"',
|
|
655
|
+
"timeout": 10,
|
|
656
|
+
}
|
|
657
|
+
],
|
|
658
|
+
"matcher": "Read|Write|Edit|MultiEdit",
|
|
659
|
+
},
|
|
660
|
+
],
|
|
661
|
+
"PostToolUse": [
|
|
662
|
+
{
|
|
663
|
+
"hooks": [
|
|
664
|
+
{
|
|
665
|
+
"type": "command",
|
|
666
|
+
"command": 'python3 "$HOME/.claude/hooks/tool-ledger.py"',
|
|
667
|
+
"timeout": 10,
|
|
668
|
+
}
|
|
669
|
+
],
|
|
670
|
+
"matcher": "Write|Edit|MultiEdit",
|
|
671
|
+
},
|
|
672
|
+
],
|
|
673
|
+
"PostToolUseFailure": [
|
|
674
|
+
{
|
|
675
|
+
"hooks": [
|
|
676
|
+
{
|
|
677
|
+
"type": "command",
|
|
678
|
+
"command": 'python3 "$HOME/.claude/hooks/post-tool-failure.py"',
|
|
679
|
+
}
|
|
680
|
+
],
|
|
681
|
+
}
|
|
682
|
+
],
|
|
683
|
+
"InstructionsLoaded": [
|
|
684
|
+
{
|
|
685
|
+
"hooks": [
|
|
686
|
+
{
|
|
687
|
+
"type": "command",
|
|
688
|
+
"command": 'python3 "$HOME/.claude/hooks/instructions-loaded.py"',
|
|
689
|
+
"timeout": 10,
|
|
690
|
+
}
|
|
691
|
+
],
|
|
692
|
+
}
|
|
693
|
+
],
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
|
|
697
|
+
def _build_claude_subagents(protected_paths: list[str]) -> list[dict[str, Any]]:
|
|
698
|
+
"""Build narrow-tool Claude subagent definitions. No bypassPermissions allowed."""
|
|
699
|
+
return [
|
|
700
|
+
{
|
|
701
|
+
"name": "security-reviewer",
|
|
702
|
+
"description": "Read-only security review subagent with scoped tool access.",
|
|
703
|
+
"tools": [
|
|
704
|
+
"Read",
|
|
705
|
+
"Grep",
|
|
706
|
+
"Glob",
|
|
707
|
+
"Bash(grep *)",
|
|
708
|
+
"Bash(find *)",
|
|
709
|
+
"Bash(git log *)",
|
|
710
|
+
"Bash(git diff *)",
|
|
711
|
+
],
|
|
712
|
+
"bypassPermissions": False,
|
|
713
|
+
},
|
|
714
|
+
{
|
|
715
|
+
"name": "release-manager",
|
|
716
|
+
"description": "Release management subagent with write access governed by protected-path policy.",
|
|
717
|
+
"tools": [
|
|
718
|
+
"Read",
|
|
719
|
+
"Write",
|
|
720
|
+
"Edit",
|
|
721
|
+
"Grep",
|
|
722
|
+
"Glob",
|
|
723
|
+
"Bash(git *)",
|
|
724
|
+
"Bash(python3 scripts/omg.py *)",
|
|
725
|
+
],
|
|
726
|
+
"bypassPermissions": False,
|
|
727
|
+
"protectedPaths": protected_paths,
|
|
728
|
+
},
|
|
729
|
+
]
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
def _build_claude_skills(policy_model: dict[str, Any] | None) -> list[dict[str, Any]]:
|
|
733
|
+
"""Build Claude skill definitions from the policy model host_rules."""
|
|
734
|
+
skill_refs: list[str] = []
|
|
735
|
+
if isinstance(policy_model, dict):
|
|
736
|
+
host_rules = policy_model.get("host_rules", {})
|
|
737
|
+
if isinstance(host_rules, dict):
|
|
738
|
+
claude_rules = host_rules.get("claude", {})
|
|
739
|
+
if isinstance(claude_rules, dict):
|
|
740
|
+
skill_refs = [str(s) for s in claude_rules.get("skills", []) if str(s).strip()]
|
|
741
|
+
skills: list[dict[str, Any]] = []
|
|
742
|
+
for ref in skill_refs:
|
|
743
|
+
skills.append({"name": ref, "source": f".agents/skills/{ref}/"})
|
|
744
|
+
return skills
|
|
745
|
+
|
|
746
|
+
|
|
747
|
+
def _validate_compiled_claude_output(output_root: Path) -> list[str]:
|
|
748
|
+
"""Validate compiled Claude settings.json contains required hooks and subagents."""
|
|
749
|
+
settings_path = output_root / "settings.json"
|
|
750
|
+
if not settings_path.exists():
|
|
751
|
+
return ["claude: missing compiled settings.json"]
|
|
752
|
+
|
|
753
|
+
settings = _load_json(settings_path)
|
|
754
|
+
errors: list[str] = []
|
|
755
|
+
|
|
756
|
+
hooks = settings.get("hooks", {})
|
|
757
|
+
for event in REQUIRED_CLAUDE_HOOK_EVENTS:
|
|
758
|
+
if event not in hooks or not hooks[event]:
|
|
759
|
+
errors.append(f"claude: missing required hook event '{event}'")
|
|
760
|
+
|
|
761
|
+
omg = settings.get("_omg", {})
|
|
762
|
+
generated = omg.get("generated", {})
|
|
763
|
+
subagents = generated.get("subagents", [])
|
|
764
|
+
subagent_names = {sa.get("name") for sa in subagents if isinstance(sa, dict)}
|
|
765
|
+
for name in REQUIRED_CLAUDE_SUBAGENT_NAMES:
|
|
766
|
+
if name not in subagent_names:
|
|
767
|
+
errors.append(f"claude: missing required subagent '{name}'")
|
|
768
|
+
|
|
769
|
+
for sa in subagents:
|
|
770
|
+
if isinstance(sa, dict) and sa.get("bypassPermissions"):
|
|
771
|
+
errors.append(
|
|
772
|
+
f"claude: subagent '{sa.get('name', '<unknown>')}' has bypassPermissions enabled"
|
|
773
|
+
)
|
|
774
|
+
|
|
775
|
+
return errors
|
|
776
|
+
|
|
777
|
+
|
|
378
778
|
def _compile_claude_outputs(
|
|
379
779
|
*,
|
|
380
780
|
root: Path,
|
|
381
781
|
output_root: Path,
|
|
382
782
|
bundles: list[dict[str, Any]],
|
|
383
783
|
channel: str,
|
|
784
|
+
policy_model: dict[str, Any] | None,
|
|
384
785
|
) -> list[Path]:
|
|
385
786
|
artifacts: list[Path] = []
|
|
386
787
|
|
|
@@ -399,15 +800,28 @@ def _compile_claude_outputs(
|
|
|
399
800
|
settings_path = resolve_asset("settings.json")
|
|
400
801
|
settings = _load_json(settings_path)
|
|
401
802
|
hook_bundle = _bundle_map(bundles)["hook-governor"]
|
|
402
|
-
|
|
803
|
+
compiled_hooks = _compile_hook_settings(hook_bundle)
|
|
804
|
+
defaults = _default_claude_hook_registrations()
|
|
805
|
+
for event in REQUIRED_CLAUDE_HOOK_EVENTS:
|
|
806
|
+
if event not in compiled_hooks or not compiled_hooks[event]:
|
|
807
|
+
compiled_hooks[event] = defaults[event]
|
|
808
|
+
settings["hooks"] = compiled_hooks
|
|
809
|
+
|
|
810
|
+
protected_paths = _policy_protected_paths(policy_model, channel=channel)
|
|
811
|
+
subagents = _build_claude_subagents(protected_paths)
|
|
812
|
+
skills = _build_claude_skills(policy_model)
|
|
813
|
+
|
|
403
814
|
omg_settings = dict(settings.get("_omg", {}))
|
|
404
815
|
omg_settings["_version"] = CANONICAL_VERSION
|
|
405
816
|
omg_settings["generated"] = {
|
|
406
817
|
"contract_version": CANONICAL_VERSION,
|
|
407
818
|
"channel": channel,
|
|
408
819
|
"required_bundles": list(DEFAULT_REQUIRED_BUNDLES),
|
|
409
|
-
"protected_paths":
|
|
820
|
+
"protected_paths": protected_paths,
|
|
410
821
|
"emulated_events": list(hook_bundle.get("lifecycle_hooks", {}).get("emulated", [])),
|
|
822
|
+
"policy_model": policy_model or {},
|
|
823
|
+
"subagents": subagents,
|
|
824
|
+
"skills": skills,
|
|
411
825
|
}
|
|
412
826
|
settings["_omg"] = omg_settings
|
|
413
827
|
_write_json(output_root / "settings.json", settings)
|
|
@@ -458,25 +872,251 @@ def _render_openai_yaml(bundle: dict[str, Any], channel: str) -> str:
|
|
|
458
872
|
return "\n".join(lines) + "\n"
|
|
459
873
|
|
|
460
874
|
|
|
875
|
+
def _codex_skill_refs(policy_model: dict[str, Any] | None) -> list[str]:
|
|
876
|
+
"""Extract skill references from policy_model.host_rules.codex.skills."""
|
|
877
|
+
if not isinstance(policy_model, dict):
|
|
878
|
+
return []
|
|
879
|
+
host_rules = policy_model.get("host_rules", {})
|
|
880
|
+
if not isinstance(host_rules, dict):
|
|
881
|
+
return []
|
|
882
|
+
codex_rules = host_rules.get("codex", {})
|
|
883
|
+
if not isinstance(codex_rules, dict):
|
|
884
|
+
return []
|
|
885
|
+
return [str(s) for s in codex_rules.get("skills", []) if str(s).strip()]
|
|
886
|
+
|
|
887
|
+
|
|
888
|
+
def _codex_evidence_fields(policy_model: dict[str, Any] | None) -> list[str]:
|
|
889
|
+
"""Extract required evidence contract fields from the policy model."""
|
|
890
|
+
if not isinstance(policy_model, dict):
|
|
891
|
+
return []
|
|
892
|
+
ec = policy_model.get("evidence_contract", {})
|
|
893
|
+
if not isinstance(ec, dict):
|
|
894
|
+
return []
|
|
895
|
+
return sorted(ec.keys())
|
|
896
|
+
|
|
897
|
+
|
|
898
|
+
def _codex_protected_planning_skills(bundles: Iterable[dict[str, Any]]) -> list[str]:
|
|
899
|
+
protected: list[str] = []
|
|
900
|
+
for bundle in bundles:
|
|
901
|
+
if "codex" not in bundle.get("hosts", []):
|
|
902
|
+
continue
|
|
903
|
+
if str(bundle.get("kind", "")).strip().lower() != "planning":
|
|
904
|
+
continue
|
|
905
|
+
invocation = bundle.get("invocation_policy", {})
|
|
906
|
+
if not isinstance(invocation, dict):
|
|
907
|
+
continue
|
|
908
|
+
if invocation.get("allow_implicit_invocation") is False:
|
|
909
|
+
protected.append(f"omg/{bundle['id']}")
|
|
910
|
+
return sorted(set(protected))
|
|
911
|
+
|
|
912
|
+
|
|
913
|
+
def _render_codex_agents_fragment(
|
|
914
|
+
*,
|
|
915
|
+
channel: str,
|
|
916
|
+
protected_paths: list[str],
|
|
917
|
+
codex_rules: list[str],
|
|
918
|
+
codex_automations: list[str],
|
|
919
|
+
codex_skills: list[str],
|
|
920
|
+
evidence_fields: list[str],
|
|
921
|
+
protected_planning_skills: list[str],
|
|
922
|
+
) -> str:
|
|
923
|
+
"""Render a comprehensive AGENTS.fragment.md for Codex host."""
|
|
924
|
+
sections: list[str] = []
|
|
925
|
+
|
|
926
|
+
# Header
|
|
927
|
+
sections.append(f"# OMG Codex Governance (channel: {channel})\n")
|
|
928
|
+
|
|
929
|
+
# Build & Test
|
|
930
|
+
sections.append("## Build & Test\n")
|
|
931
|
+
sections.append("```bash")
|
|
932
|
+
sections.append("python3 -m pytest tests -q")
|
|
933
|
+
sections.append("python3 scripts/omg.py contract validate")
|
|
934
|
+
sections.append(f"python3 scripts/omg.py contract compile --host codex --channel {channel}")
|
|
935
|
+
sections.append("```\n")
|
|
936
|
+
|
|
937
|
+
# Protected Paths
|
|
938
|
+
sections.append("## Protected Paths\n")
|
|
939
|
+
sections.append("The following paths require tier-gated review before mutation:\n")
|
|
940
|
+
for path in protected_paths:
|
|
941
|
+
sections.append(f"- `{path}`")
|
|
942
|
+
sections.append("")
|
|
943
|
+
|
|
944
|
+
# Evidence Contract
|
|
945
|
+
sections.append("## Evidence Contract\n")
|
|
946
|
+
sections.append("Every production action must emit evidence containing these fields:\n")
|
|
947
|
+
if evidence_fields:
|
|
948
|
+
for field in evidence_fields:
|
|
949
|
+
sections.append(f"- `{field}`")
|
|
950
|
+
else:
|
|
951
|
+
sections.append("- `timestamp`")
|
|
952
|
+
sections.append("- `executor`")
|
|
953
|
+
sections.append("- `trace_id`")
|
|
954
|
+
sections.append("- `lineage`")
|
|
955
|
+
sections.append("")
|
|
956
|
+
|
|
957
|
+
# Required Skills
|
|
958
|
+
sections.append("## Required Skills\n")
|
|
959
|
+
if codex_skills:
|
|
960
|
+
for skill in codex_skills:
|
|
961
|
+
sections.append(f"- `{skill}`")
|
|
962
|
+
else:
|
|
963
|
+
sections.append("- `omg/control-plane`")
|
|
964
|
+
sections.append("")
|
|
965
|
+
|
|
966
|
+
sections.append("## Protected Planning Surface\n")
|
|
967
|
+
if protected_planning_skills:
|
|
968
|
+
sections.append("Council planning skills are protected and explicit-invocation only:")
|
|
969
|
+
sections.append("")
|
|
970
|
+
for skill in protected_planning_skills:
|
|
971
|
+
sections.append(f"- `{skill}`")
|
|
972
|
+
else:
|
|
973
|
+
sections.append("- No protected planning skills configured.")
|
|
974
|
+
sections.append("")
|
|
975
|
+
|
|
976
|
+
# Web Search Policy
|
|
977
|
+
sections.append("## Web Search Policy\n")
|
|
978
|
+
sections.append("- Prefer cached results over live network requests.")
|
|
979
|
+
sections.append("- Do NOT initiate live web searches unless explicitly instructed.")
|
|
980
|
+
sections.append("- Use `context7` or local documentation before external lookups.")
|
|
981
|
+
sections.append("- Set `cached_web_search: prefer_cached` as the default.\n")
|
|
982
|
+
|
|
983
|
+
# Approval Constraints
|
|
984
|
+
sections.append("## Approval Constraints\n")
|
|
985
|
+
sections.append("- Destructive file operations require explicit user approval.")
|
|
986
|
+
sections.append("- `git push --force` and branch deletions require explicit approval.")
|
|
987
|
+
sections.append("- Production deployments require explicit approval.")
|
|
988
|
+
sections.append("- Mutations to protected paths require tier-gated approval.\n")
|
|
989
|
+
|
|
990
|
+
# Rules & Automations (compact summary)
|
|
991
|
+
sections.append("## Rules & Automations\n")
|
|
992
|
+
rules_str = ", ".join(codex_rules) if codex_rules else "protected_paths, explicit_invocation"
|
|
993
|
+
auto_str = ", ".join(codex_automations) if codex_automations else "contract-compile"
|
|
994
|
+
sections.append(f"- Rules: `{rules_str}`")
|
|
995
|
+
sections.append(f"- Automations: `{auto_str}`")
|
|
996
|
+
sections.append("- Require explicit invocation for protected production planning skills.")
|
|
997
|
+
sections.append("")
|
|
998
|
+
|
|
999
|
+
return "\n".join(sections)
|
|
1000
|
+
|
|
1001
|
+
|
|
1002
|
+
def _render_codex_rules(
|
|
1003
|
+
*,
|
|
1004
|
+
channel: str,
|
|
1005
|
+
protected_paths: list[str],
|
|
1006
|
+
codex_skills: list[str],
|
|
1007
|
+
protected_planning_skills: list[str],
|
|
1008
|
+
) -> str:
|
|
1009
|
+
"""Render a codex-rules.md config fragment encoding defaults."""
|
|
1010
|
+
lines: list[str] = []
|
|
1011
|
+
lines.append(f"# OMG Codex Rules (channel: {channel})\n")
|
|
1012
|
+
|
|
1013
|
+
lines.append("## Defaults\n")
|
|
1014
|
+
lines.append("- `cached_web_search: prefer_cached`")
|
|
1015
|
+
lines.append("- `live_network: deny_by_default`")
|
|
1016
|
+
lines.append("- `destructive_approval: required`\n")
|
|
1017
|
+
|
|
1018
|
+
lines.append("## Protected Paths\n")
|
|
1019
|
+
for path in protected_paths:
|
|
1020
|
+
lines.append(f"- `{path}`")
|
|
1021
|
+
lines.append("")
|
|
1022
|
+
|
|
1023
|
+
lines.append("## Required Skills\n")
|
|
1024
|
+
for skill in (codex_skills or ["omg/control-plane"]):
|
|
1025
|
+
lines.append(f"- `{skill}`")
|
|
1026
|
+
lines.append("")
|
|
1027
|
+
|
|
1028
|
+
lines.append("## Protected Planning Surface\n")
|
|
1029
|
+
if protected_planning_skills:
|
|
1030
|
+
for skill in protected_planning_skills:
|
|
1031
|
+
lines.append(f"- `{skill}` (explicit invocation only)")
|
|
1032
|
+
else:
|
|
1033
|
+
lines.append("- none")
|
|
1034
|
+
lines.append("")
|
|
1035
|
+
|
|
1036
|
+
lines.append("## Approval Matrix\n")
|
|
1037
|
+
lines.append("| Action | Approval Required |")
|
|
1038
|
+
lines.append("|--------|------------------|")
|
|
1039
|
+
lines.append("| Read / Grep | No |")
|
|
1040
|
+
lines.append("| Write to protected paths | Yes |")
|
|
1041
|
+
lines.append("| Bash (python3:*) | Yes (balanced+ tier) |")
|
|
1042
|
+
lines.append("| git push --force | Yes |")
|
|
1043
|
+
lines.append("| Production deploy | Yes |")
|
|
1044
|
+
lines.append("")
|
|
1045
|
+
|
|
1046
|
+
return "\n".join(lines)
|
|
1047
|
+
|
|
1048
|
+
|
|
1049
|
+
def _validate_compiled_codex_output(output_root: Path) -> list[str]:
|
|
1050
|
+
"""Validate compiled Codex output contains required AGENTS sections and artifacts."""
|
|
1051
|
+
errors: list[str] = []
|
|
1052
|
+
shared_dir = output_root / ".agents" / "skills" / "omg"
|
|
1053
|
+
|
|
1054
|
+
for required_file in REQUIRED_CODEX_OUTPUTS:
|
|
1055
|
+
path = shared_dir / required_file
|
|
1056
|
+
if not path.exists():
|
|
1057
|
+
errors.append(f"codex: missing required output '{required_file}'")
|
|
1058
|
+
|
|
1059
|
+
agents_path = shared_dir / "AGENTS.fragment.md"
|
|
1060
|
+
if agents_path.exists():
|
|
1061
|
+
content = agents_path.read_text(encoding="utf-8")
|
|
1062
|
+
for section in REQUIRED_CODEX_AGENTS_SECTIONS:
|
|
1063
|
+
if section not in content:
|
|
1064
|
+
errors.append(f"codex: AGENTS.fragment.md missing required section '{section}'")
|
|
1065
|
+
else:
|
|
1066
|
+
errors.append("codex: cannot validate AGENTS.fragment.md — file missing")
|
|
1067
|
+
|
|
1068
|
+
return errors
|
|
1069
|
+
|
|
1070
|
+
|
|
461
1071
|
def _compile_codex_outputs(
|
|
462
1072
|
*,
|
|
463
1073
|
output_root: Path,
|
|
464
1074
|
bundles: list[dict[str, Any]],
|
|
465
1075
|
channel: str,
|
|
1076
|
+
policy_model: dict[str, Any] | None,
|
|
466
1077
|
) -> list[Path]:
|
|
467
1078
|
artifacts: list[Path] = []
|
|
468
1079
|
shared_dir = output_root / ".agents" / "skills" / "omg"
|
|
469
1080
|
shared_dir.mkdir(parents=True, exist_ok=True)
|
|
470
1081
|
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
1082
|
+
protected_paths = _policy_protected_paths(policy_model, channel=channel)
|
|
1083
|
+
codex_rules: list[str] = []
|
|
1084
|
+
codex_automations: list[str] = []
|
|
1085
|
+
if isinstance(policy_model, dict):
|
|
1086
|
+
host_rules = policy_model.get("host_rules", {})
|
|
1087
|
+
if isinstance(host_rules, dict):
|
|
1088
|
+
codex_policy = host_rules.get("codex", {})
|
|
1089
|
+
if isinstance(codex_policy, dict):
|
|
1090
|
+
codex_rules = [str(item) for item in codex_policy.get("rules", []) if str(item).strip()]
|
|
1091
|
+
codex_automations = [
|
|
1092
|
+
str(item) for item in codex_policy.get("automations", []) if str(item).strip()
|
|
1093
|
+
]
|
|
1094
|
+
|
|
1095
|
+
codex_skills = _codex_skill_refs(policy_model)
|
|
1096
|
+
evidence_fields = _codex_evidence_fields(policy_model)
|
|
1097
|
+
protected_planning_skills = _codex_protected_planning_skills(bundles)
|
|
1098
|
+
|
|
1099
|
+
agents_fragment = _render_codex_agents_fragment(
|
|
1100
|
+
channel=channel,
|
|
1101
|
+
protected_paths=protected_paths,
|
|
1102
|
+
codex_rules=codex_rules,
|
|
1103
|
+
codex_automations=codex_automations,
|
|
1104
|
+
codex_skills=codex_skills,
|
|
1105
|
+
evidence_fields=evidence_fields,
|
|
1106
|
+
protected_planning_skills=protected_planning_skills,
|
|
476
1107
|
)
|
|
477
|
-
_write_text(shared_dir / "AGENTS.fragment.md",
|
|
1108
|
+
_write_text(shared_dir / "AGENTS.fragment.md", agents_fragment)
|
|
478
1109
|
artifacts.append(shared_dir / "AGENTS.fragment.md")
|
|
479
1110
|
|
|
1111
|
+
rules_content = _render_codex_rules(
|
|
1112
|
+
channel=channel,
|
|
1113
|
+
protected_paths=protected_paths,
|
|
1114
|
+
codex_skills=codex_skills,
|
|
1115
|
+
protected_planning_skills=protected_planning_skills,
|
|
1116
|
+
)
|
|
1117
|
+
_write_text(shared_dir / "codex-rules.md", rules_content)
|
|
1118
|
+
artifacts.append(shared_dir / "codex-rules.md")
|
|
1119
|
+
|
|
480
1120
|
from runtime.mcp_config_writers import write_codex_mcp_stdio_config
|
|
481
1121
|
|
|
482
1122
|
codex_mcp_path = shared_dir / "codex-mcp.toml"
|
|
@@ -580,12 +1220,48 @@ def compile_contract_outputs(
|
|
|
580
1220
|
}
|
|
581
1221
|
|
|
582
1222
|
bundles = load_contract_bundles(root)
|
|
1223
|
+
policy_model = _policy_model_for_bundle(bundles, "control-plane")
|
|
583
1224
|
artifacts = _copy_contract_inputs(root, output)
|
|
584
1225
|
|
|
585
1226
|
if "claude" in selected_hosts:
|
|
586
|
-
artifacts.extend(
|
|
1227
|
+
artifacts.extend(
|
|
1228
|
+
_compile_claude_outputs(
|
|
1229
|
+
root=root,
|
|
1230
|
+
output_root=output,
|
|
1231
|
+
bundles=bundles,
|
|
1232
|
+
channel=channel,
|
|
1233
|
+
policy_model=policy_model,
|
|
1234
|
+
)
|
|
1235
|
+
)
|
|
1236
|
+
claude_errors = _validate_compiled_claude_output(output)
|
|
1237
|
+
if claude_errors:
|
|
1238
|
+
return {
|
|
1239
|
+
"schema": "OmgContractCompileResult",
|
|
1240
|
+
"status": "error",
|
|
1241
|
+
"channel": channel,
|
|
1242
|
+
"hosts": selected_hosts,
|
|
1243
|
+
"errors": claude_errors,
|
|
1244
|
+
"artifacts": [],
|
|
1245
|
+
}
|
|
587
1246
|
if "codex" in selected_hosts:
|
|
588
|
-
artifacts.extend(
|
|
1247
|
+
artifacts.extend(
|
|
1248
|
+
_compile_codex_outputs(
|
|
1249
|
+
output_root=output,
|
|
1250
|
+
bundles=bundles,
|
|
1251
|
+
channel=channel,
|
|
1252
|
+
policy_model=policy_model,
|
|
1253
|
+
)
|
|
1254
|
+
)
|
|
1255
|
+
codex_errors = _validate_compiled_codex_output(output)
|
|
1256
|
+
if codex_errors:
|
|
1257
|
+
return {
|
|
1258
|
+
"schema": "OmgContractCompileResult",
|
|
1259
|
+
"status": "error",
|
|
1260
|
+
"channel": channel,
|
|
1261
|
+
"hosts": selected_hosts,
|
|
1262
|
+
"errors": codex_errors,
|
|
1263
|
+
"artifacts": [],
|
|
1264
|
+
}
|
|
589
1265
|
|
|
590
1266
|
bundled_artifacts = _copy_release_bundle(output_root=output, channel=channel, artifacts=artifacts)
|
|
591
1267
|
manifest_path = _build_dist_manifest(output, channel=channel, artifacts=bundled_artifacts)
|
|
@@ -648,6 +1324,294 @@ def _check_mcp_fabric() -> dict[str, Any]:
|
|
|
648
1324
|
}
|
|
649
1325
|
|
|
650
1326
|
|
|
1327
|
+
def _check_version_identity_drift(root: Path) -> dict[str, Any]:
|
|
1328
|
+
"""Check version/identity drift across all public surface files.
|
|
1329
|
+
|
|
1330
|
+
Returns a dict with:
|
|
1331
|
+
- status: "ok" or "error"
|
|
1332
|
+
- blockers: list of named blockers for each mismatch
|
|
1333
|
+
- drift_details: dict mapping file paths to their found versions
|
|
1334
|
+
"""
|
|
1335
|
+
canonical_version = CANONICAL_VERSION
|
|
1336
|
+
blockers: list[str] = []
|
|
1337
|
+
drift_details: dict[str, str] = {}
|
|
1338
|
+
|
|
1339
|
+
# Files to check with their JSON paths to extract version
|
|
1340
|
+
files_to_check = [
|
|
1341
|
+
("package.json", ["version"]),
|
|
1342
|
+
("pyproject.toml", None), # Special case: extract from version = "X.Y.Z"
|
|
1343
|
+
("settings.json", ["_omg", "_version"]),
|
|
1344
|
+
(".claude-plugin/plugin.json", ["version"]),
|
|
1345
|
+
(".claude-plugin/marketplace.json", ["version"]),
|
|
1346
|
+
("plugins/core/plugin.json", ["version"]),
|
|
1347
|
+
("plugins/advanced/plugin.json", ["version"]),
|
|
1348
|
+
("CHANGELOG.md", None), # Special case: check for version in header
|
|
1349
|
+
]
|
|
1350
|
+
|
|
1351
|
+
for file_path, json_path in files_to_check:
|
|
1352
|
+
full_path = root / file_path
|
|
1353
|
+
if not full_path.exists():
|
|
1354
|
+
blockers.append(f"version_drift: missing file {file_path}")
|
|
1355
|
+
continue
|
|
1356
|
+
|
|
1357
|
+
found_version = None
|
|
1358
|
+
|
|
1359
|
+
try:
|
|
1360
|
+
if file_path == "pyproject.toml":
|
|
1361
|
+
# Extract from version = "X.Y.Z"
|
|
1362
|
+
content = full_path.read_text(encoding="utf-8")
|
|
1363
|
+
for line in content.split("\n"):
|
|
1364
|
+
if line.startswith("version = "):
|
|
1365
|
+
found_version = line.split('"')[1]
|
|
1366
|
+
break
|
|
1367
|
+
elif file_path == "CHANGELOG.md":
|
|
1368
|
+
# Extract from "## X.Y.Z -" header (skip "Unreleased" section)
|
|
1369
|
+
content = full_path.read_text(encoding="utf-8")
|
|
1370
|
+
for line in content.split("\n"):
|
|
1371
|
+
if line.startswith("## ") and " - " in line:
|
|
1372
|
+
version_str = line.split(" - ")[0].replace("## ", "").strip()
|
|
1373
|
+
if version_str.lower() != "unreleased":
|
|
1374
|
+
found_version = version_str
|
|
1375
|
+
break
|
|
1376
|
+
else:
|
|
1377
|
+
# JSON file: use json_path to navigate
|
|
1378
|
+
data = _load_json(full_path)
|
|
1379
|
+
current = data
|
|
1380
|
+
if json_path:
|
|
1381
|
+
for key in json_path:
|
|
1382
|
+
current = current.get(key)
|
|
1383
|
+
if current is None:
|
|
1384
|
+
break
|
|
1385
|
+
found_version = current
|
|
1386
|
+
except Exception as e:
|
|
1387
|
+
blockers.append(f"version_drift: failed to parse {file_path}: {e}")
|
|
1388
|
+
continue
|
|
1389
|
+
|
|
1390
|
+
if found_version is None:
|
|
1391
|
+
blockers.append(f"version_drift: could not extract version from {file_path}")
|
|
1392
|
+
elif str(found_version) != canonical_version:
|
|
1393
|
+
blockers.append(
|
|
1394
|
+
f"version_drift: {file_path} has version {found_version}, expected {canonical_version}"
|
|
1395
|
+
)
|
|
1396
|
+
drift_details[file_path] = str(found_version)
|
|
1397
|
+
else:
|
|
1398
|
+
drift_details[file_path] = str(found_version)
|
|
1399
|
+
|
|
1400
|
+
return {
|
|
1401
|
+
"status": "ok" if not blockers else "error",
|
|
1402
|
+
"canonical_version": canonical_version,
|
|
1403
|
+
"blockers": blockers,
|
|
1404
|
+
"drift_details": drift_details,
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
|
|
1408
|
+
def _check_doctor_output(output_root: Path) -> dict[str, Any]:
|
|
1409
|
+
evidence_dir = output_root / ".omg" / "evidence"
|
|
1410
|
+
doctor_path = evidence_dir / "doctor.json"
|
|
1411
|
+
if not doctor_path.exists():
|
|
1412
|
+
return {
|
|
1413
|
+
"status": "error",
|
|
1414
|
+
"path": "",
|
|
1415
|
+
"doctor": {},
|
|
1416
|
+
"blockers": ["doctor_check_missing: missing .omg/evidence/doctor.json"],
|
|
1417
|
+
}
|
|
1418
|
+
try:
|
|
1419
|
+
payload = _load_json(doctor_path)
|
|
1420
|
+
except Exception as exc:
|
|
1421
|
+
return {
|
|
1422
|
+
"status": "error",
|
|
1423
|
+
"path": str(doctor_path.relative_to(output_root)),
|
|
1424
|
+
"doctor": {},
|
|
1425
|
+
"blockers": [f"doctor_check_missing: invalid doctor output ({exc})"],
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
blockers: list[str] = []
|
|
1429
|
+
if payload.get("schema") != "DoctorResult":
|
|
1430
|
+
blockers.append("doctor_check_missing: doctor evidence schema mismatch")
|
|
1431
|
+
if payload.get("status") != "pass":
|
|
1432
|
+
blockers.append("doctor_check_missing: doctor status is not pass")
|
|
1433
|
+
checks = payload.get("checks", [])
|
|
1434
|
+
if not isinstance(checks, list) or not checks:
|
|
1435
|
+
blockers.append("doctor_check_missing: doctor checks missing")
|
|
1436
|
+
|
|
1437
|
+
return {
|
|
1438
|
+
"status": "ok" if not blockers else "error",
|
|
1439
|
+
"path": str(doctor_path.relative_to(output_root)),
|
|
1440
|
+
"doctor": payload,
|
|
1441
|
+
"blockers": blockers,
|
|
1442
|
+
}
|
|
1443
|
+
|
|
1444
|
+
|
|
1445
|
+
def _check_proof_surface(root: Path) -> dict[str, Any]:
|
|
1446
|
+
proof_path = root / "docs" / "proof.md"
|
|
1447
|
+
if not proof_path.exists():
|
|
1448
|
+
return {
|
|
1449
|
+
"status": "error",
|
|
1450
|
+
"path": "docs/proof.md",
|
|
1451
|
+
"blockers": ["prose_only_proof: docs/proof.md missing"],
|
|
1452
|
+
}
|
|
1453
|
+
|
|
1454
|
+
content = proof_path.read_text(encoding="utf-8")
|
|
1455
|
+
lowered = content.lower()
|
|
1456
|
+
hardcoded_counts = bool(
|
|
1457
|
+
re.search(r"\b\d+\s*/\s*\d+\b", lowered)
|
|
1458
|
+
or re.search(r"\b\d+\s+(tests?|checks?|providers?)\s+(passed|pass|green|successful)\b", lowered)
|
|
1459
|
+
or re.search(r"\ball\s+tests?\s+passed\b", lowered)
|
|
1460
|
+
)
|
|
1461
|
+
artifact_refs = (
|
|
1462
|
+
".omg/evidence/",
|
|
1463
|
+
".omg/tracebank/",
|
|
1464
|
+
".omg/evals/",
|
|
1465
|
+
".omg/lineage/",
|
|
1466
|
+
)
|
|
1467
|
+
has_artifact_refs = any(token in content for token in artifact_refs)
|
|
1468
|
+
|
|
1469
|
+
blockers: list[str] = []
|
|
1470
|
+
if hardcoded_counts and not has_artifact_refs:
|
|
1471
|
+
blockers.append("prose_only_proof: hardcoded proof counts without machine artifact references")
|
|
1472
|
+
|
|
1473
|
+
return {
|
|
1474
|
+
"status": "ok" if not blockers else "error",
|
|
1475
|
+
"path": str(proof_path.relative_to(root)),
|
|
1476
|
+
"hardcoded_counts": hardcoded_counts,
|
|
1477
|
+
"has_artifact_refs": has_artifact_refs,
|
|
1478
|
+
"blockers": blockers,
|
|
1479
|
+
}
|
|
1480
|
+
|
|
1481
|
+
|
|
1482
|
+
def _is_loopback_hostname(hostname: str) -> bool:
|
|
1483
|
+
lowered = hostname.strip().lower()
|
|
1484
|
+
return lowered in {"localhost", "127.0.0.1", "::1"}
|
|
1485
|
+
|
|
1486
|
+
|
|
1487
|
+
def _collect_http_urls(line: str) -> list[str]:
|
|
1488
|
+
return re.findall(r"https?://[^\s)\]>'\"]+", line)
|
|
1489
|
+
|
|
1490
|
+
|
|
1491
|
+
def _check_same_machine_scope(root: Path, output_root: Path) -> dict[str, Any]:
|
|
1492
|
+
blockers: list[str] = []
|
|
1493
|
+
scanned: list[str] = []
|
|
1494
|
+
|
|
1495
|
+
for rel_path in ("README.md", "docs/proof.md", "OMG_COMPAT_CONTRACT.md"):
|
|
1496
|
+
path = root / rel_path
|
|
1497
|
+
if not path.exists():
|
|
1498
|
+
continue
|
|
1499
|
+
scanned.append(rel_path)
|
|
1500
|
+
for line in path.read_text(encoding="utf-8").splitlines():
|
|
1501
|
+
if "production" not in line.lower():
|
|
1502
|
+
continue
|
|
1503
|
+
for url in _collect_http_urls(line):
|
|
1504
|
+
parsed = urlparse(url)
|
|
1505
|
+
if parsed.scheme != "http":
|
|
1506
|
+
continue
|
|
1507
|
+
host = parsed.hostname or ""
|
|
1508
|
+
if host and not _is_loopback_hostname(host):
|
|
1509
|
+
blockers.append(
|
|
1510
|
+
f"same_machine_scope_violation: {rel_path} claims production over non-loopback HTTP ({url})"
|
|
1511
|
+
)
|
|
1512
|
+
|
|
1513
|
+
mcp_path = output_root / ".mcp.json"
|
|
1514
|
+
if mcp_path.exists():
|
|
1515
|
+
scanned.append(str(mcp_path.relative_to(output_root)))
|
|
1516
|
+
mcp_payload = _load_json(mcp_path)
|
|
1517
|
+
servers = mcp_payload.get("mcpServers", {})
|
|
1518
|
+
if isinstance(servers, dict):
|
|
1519
|
+
for server_name, server_cfg in servers.items():
|
|
1520
|
+
if not isinstance(server_cfg, dict):
|
|
1521
|
+
continue
|
|
1522
|
+
for key in ("url", "httpUrl"):
|
|
1523
|
+
raw_url = str(server_cfg.get(key, "")).strip()
|
|
1524
|
+
if not raw_url:
|
|
1525
|
+
continue
|
|
1526
|
+
parsed = urlparse(raw_url)
|
|
1527
|
+
if parsed.scheme != "http":
|
|
1528
|
+
continue
|
|
1529
|
+
host = parsed.hostname or ""
|
|
1530
|
+
if host and not _is_loopback_hostname(host):
|
|
1531
|
+
blockers.append(
|
|
1532
|
+
"same_machine_scope_violation: "
|
|
1533
|
+
f".mcp.json server '{server_name}' uses non-loopback HTTP endpoint ({raw_url})"
|
|
1534
|
+
)
|
|
1535
|
+
|
|
1536
|
+
return {
|
|
1537
|
+
"status": "ok" if not blockers else "error",
|
|
1538
|
+
"scanned": scanned,
|
|
1539
|
+
"blockers": blockers,
|
|
1540
|
+
}
|
|
1541
|
+
|
|
1542
|
+
|
|
1543
|
+
def _check_provider_host_parity(output_root: Path, providers: dict[str, dict[str, Any]]) -> dict[str, Any]:
|
|
1544
|
+
blockers: list[str] = []
|
|
1545
|
+
required_for_provider = {
|
|
1546
|
+
"claude": (
|
|
1547
|
+
output_root / "settings.json",
|
|
1548
|
+
output_root / ".claude-plugin" / "plugin.json",
|
|
1549
|
+
),
|
|
1550
|
+
"codex": (
|
|
1551
|
+
output_root / ".agents" / "skills" / "omg" / "AGENTS.fragment.md",
|
|
1552
|
+
output_root / ".agents" / "skills" / "omg" / "codex-mcp.toml",
|
|
1553
|
+
),
|
|
1554
|
+
}
|
|
1555
|
+
for provider, status in providers.items():
|
|
1556
|
+
if not status.get("ready"):
|
|
1557
|
+
continue
|
|
1558
|
+
for required_path in required_for_provider.get(provider, ()):
|
|
1559
|
+
if not required_path.exists():
|
|
1560
|
+
blockers.append(
|
|
1561
|
+
"provider_host_parity: "
|
|
1562
|
+
f"provider '{provider}' ready but host artifact missing {required_path.relative_to(output_root)}"
|
|
1563
|
+
)
|
|
1564
|
+
return {
|
|
1565
|
+
"status": "ok" if not blockers else "error",
|
|
1566
|
+
"blockers": blockers,
|
|
1567
|
+
}
|
|
1568
|
+
|
|
1569
|
+
|
|
1570
|
+
def _has_waiver(risk: dict[str, Any]) -> bool:
|
|
1571
|
+
return bool(
|
|
1572
|
+
risk.get("waived")
|
|
1573
|
+
or risk.get("waiver")
|
|
1574
|
+
or risk.get("waiver_id")
|
|
1575
|
+
or risk.get("waiver_evidence")
|
|
1576
|
+
)
|
|
1577
|
+
|
|
1578
|
+
|
|
1579
|
+
def _check_high_risk_security_waivers(payload: dict[str, Any]) -> list[str]:
|
|
1580
|
+
blockers: list[str] = []
|
|
1581
|
+
unresolved = payload.get("unresolved_risks", [])
|
|
1582
|
+
if isinstance(unresolved, list):
|
|
1583
|
+
for item in unresolved:
|
|
1584
|
+
if isinstance(item, dict):
|
|
1585
|
+
severity = str(item.get("severity") or item.get("risk_level") or "").lower()
|
|
1586
|
+
if severity in {"high", "critical"} and not _has_waiver(item):
|
|
1587
|
+
blockers.append("security_blocker_unwaived: unresolved high-risk item without waiver evidence")
|
|
1588
|
+
break
|
|
1589
|
+
elif isinstance(item, str):
|
|
1590
|
+
lowered = item.lower()
|
|
1591
|
+
is_high = "high" in lowered or "critical" in lowered
|
|
1592
|
+
waived = "waiv" in lowered
|
|
1593
|
+
if is_high and not waived:
|
|
1594
|
+
blockers.append("security_blocker_unwaived: unresolved high-risk item without waiver evidence")
|
|
1595
|
+
break
|
|
1596
|
+
|
|
1597
|
+
scans = payload.get("security_scans", [])
|
|
1598
|
+
if isinstance(scans, list):
|
|
1599
|
+
for scan in scans:
|
|
1600
|
+
if not isinstance(scan, dict):
|
|
1601
|
+
continue
|
|
1602
|
+
findings = scan.get("findings", [])
|
|
1603
|
+
if not isinstance(findings, list):
|
|
1604
|
+
continue
|
|
1605
|
+
for finding in findings:
|
|
1606
|
+
if not isinstance(finding, dict):
|
|
1607
|
+
continue
|
|
1608
|
+
severity = str(finding.get("severity", "")).lower()
|
|
1609
|
+
if severity in {"high", "critical"} and not _has_waiver(finding):
|
|
1610
|
+
blockers.append("security_blocker_unwaived: high-risk security finding without waiver evidence")
|
|
1611
|
+
return blockers
|
|
1612
|
+
return blockers
|
|
1613
|
+
|
|
1614
|
+
|
|
651
1615
|
def build_release_readiness(
|
|
652
1616
|
*,
|
|
653
1617
|
root_dir: str | Path | None = None,
|
|
@@ -684,6 +1648,10 @@ def build_release_readiness(
|
|
|
684
1648
|
continue
|
|
685
1649
|
if _sha256_file(artifact_path) != expected_sha:
|
|
686
1650
|
manifest_errors.append(f"{required_channel}: sha mismatch for {rel_path}")
|
|
1651
|
+
manifest_paths = {str(a.get("path", "")) for a in manifest.get("artifacts", []) if isinstance(a, dict)}
|
|
1652
|
+
for req_path in REQUIRED_ADVANCED_PLUGIN_ARTIFACTS:
|
|
1653
|
+
if req_path not in manifest_paths:
|
|
1654
|
+
manifest_errors.append(f"{required_channel}: advanced_plugin_missing {req_path}")
|
|
687
1655
|
if manifest_errors:
|
|
688
1656
|
blockers.extend(manifest_errors)
|
|
689
1657
|
manifest["integrity_errors"] = manifest_errors
|
|
@@ -719,20 +1687,54 @@ def build_release_readiness(
|
|
|
719
1687
|
checks["evidence"] = evidence_check
|
|
720
1688
|
blockers.extend(evidence_check.get("blockers", []))
|
|
721
1689
|
|
|
1690
|
+
doctor_check = _check_doctor_output(output)
|
|
1691
|
+
checks["doctor"] = doctor_check
|
|
1692
|
+
blockers.extend(doctor_check.get("blockers", []))
|
|
1693
|
+
|
|
722
1694
|
eval_check = _check_eval_gate(output)
|
|
723
1695
|
checks["eval_gate"] = eval_check
|
|
724
1696
|
blockers.extend(eval_check.get("blockers", []))
|
|
725
1697
|
|
|
1698
|
+
proof_chain_check = _check_proof_chain(output)
|
|
1699
|
+
checks["proof_chain"] = proof_chain_check
|
|
1700
|
+
blockers.extend(proof_chain_check.get("blockers", []))
|
|
1701
|
+
|
|
1702
|
+
security_blockers = [
|
|
1703
|
+
blocker
|
|
1704
|
+
for blocker in evidence_check.get("blockers", [])
|
|
1705
|
+
if isinstance(blocker, str) and blocker.startswith("security_blocker_unwaived:")
|
|
1706
|
+
]
|
|
1707
|
+
checks["security_blocker_unwaived"] = {
|
|
1708
|
+
"status": "ok" if not security_blockers else "error",
|
|
1709
|
+
"blockers": security_blockers,
|
|
1710
|
+
}
|
|
1711
|
+
|
|
1712
|
+
proof_surface_check = _check_proof_surface(root)
|
|
1713
|
+
checks["proof_surface"] = proof_surface_check
|
|
1714
|
+
blockers.extend(proof_surface_check.get("blockers", []))
|
|
1715
|
+
|
|
1716
|
+
same_machine_scope = _check_same_machine_scope(root, output)
|
|
1717
|
+
checks["same_machine_scope"] = same_machine_scope
|
|
1718
|
+
blockers.extend(same_machine_scope.get("blockers", []))
|
|
1719
|
+
|
|
726
1720
|
package_check = _check_packaged_install_smoke(root)
|
|
727
1721
|
checks["package_smoke"] = package_check
|
|
728
1722
|
blockers.extend(package_check.get("blockers", []))
|
|
729
1723
|
|
|
1724
|
+
version_drift_check = _check_version_identity_drift(root)
|
|
1725
|
+
checks["version_identity_drift"] = version_drift_check
|
|
1726
|
+
blockers.extend(version_drift_check.get("blockers", []))
|
|
1727
|
+
|
|
730
1728
|
providers = _provider_statuses()
|
|
731
1729
|
checks["providers"] = providers
|
|
732
1730
|
for provider_name, status in providers.items():
|
|
733
1731
|
if not status.get("ready"):
|
|
734
1732
|
blockers.append(f"provider not ready: {provider_name}")
|
|
735
1733
|
|
|
1734
|
+
provider_parity = _check_provider_host_parity(output, providers)
|
|
1735
|
+
checks["provider_host_parity"] = provider_parity
|
|
1736
|
+
blockers.extend(provider_parity.get("blockers", []))
|
|
1737
|
+
|
|
736
1738
|
worktree_ready = shutil.which("git") is not None and (root / ".git").exists()
|
|
737
1739
|
checks["worktree"] = {"ready": worktree_ready}
|
|
738
1740
|
if not worktree_ready:
|
|
@@ -779,8 +1781,16 @@ def _check_recent_evidence(output_root: Path) -> dict[str, Any]:
|
|
|
779
1781
|
blockers.append("cosmetic evidence: security_scans is empty")
|
|
780
1782
|
if not payload.get("provenance"):
|
|
781
1783
|
blockers.append("cosmetic evidence: provenance is empty")
|
|
1784
|
+
if not payload.get("timestamp") and not payload.get("created_at"):
|
|
1785
|
+
blockers.append("missing_attribution: evidence missing timestamp")
|
|
1786
|
+
if not payload.get("executor"):
|
|
1787
|
+
blockers.append("missing_attribution: evidence missing executor")
|
|
1788
|
+
if not payload.get("environment"):
|
|
1789
|
+
blockers.append("missing_attribution: evidence missing environment")
|
|
782
1790
|
if not payload.get("trace_ids"):
|
|
783
1791
|
blockers.append("missing trace ids in evidence")
|
|
1792
|
+
if not payload.get("trace_id") and not payload.get("trace_ids"):
|
|
1793
|
+
blockers.append("missing trace_id in evidence")
|
|
784
1794
|
if not payload.get("lineage"):
|
|
785
1795
|
blockers.append("missing lineage in evidence")
|
|
786
1796
|
tests = payload.get("tests", [])
|
|
@@ -789,6 +1799,8 @@ def _check_recent_evidence(output_root: Path) -> dict[str, Any]:
|
|
|
789
1799
|
if isinstance(item, dict) and item.get("name") == "worker_implementation" and not item.get("passed", False):
|
|
790
1800
|
blockers.append("simulated worker evidence detected")
|
|
791
1801
|
break
|
|
1802
|
+
blockers.extend(_check_test_intent_claims(payload))
|
|
1803
|
+
blockers.extend(_check_high_risk_security_waivers(payload))
|
|
792
1804
|
return {
|
|
793
1805
|
"status": "ok" if not blockers else "error",
|
|
794
1806
|
"evidence_file": str(evidence_path.relative_to(output_root)),
|
|
@@ -796,6 +1808,37 @@ def _check_recent_evidence(output_root: Path) -> dict[str, Any]:
|
|
|
796
1808
|
}
|
|
797
1809
|
|
|
798
1810
|
|
|
1811
|
+
def _check_test_intent_claims(payload: dict[str, Any]) -> list[str]:
|
|
1812
|
+
test_delta = payload.get("test_delta")
|
|
1813
|
+
claims = payload.get("claims", [])
|
|
1814
|
+
if not isinstance(claims, list):
|
|
1815
|
+
return []
|
|
1816
|
+
|
|
1817
|
+
from runtime.test_intent_lock import evaluate_test_delta
|
|
1818
|
+
|
|
1819
|
+
blockers: list[str] = []
|
|
1820
|
+
guarded_claims = {"tests passed", "tests_passed", "bug fixed", "bug_fixed"}
|
|
1821
|
+
for claim in claims:
|
|
1822
|
+
if not isinstance(claim, dict):
|
|
1823
|
+
continue
|
|
1824
|
+
claim_type = str(claim.get("claim_type", "")).strip().lower()
|
|
1825
|
+
if claim_type not in guarded_claims:
|
|
1826
|
+
continue
|
|
1827
|
+
delta = claim.get("test_delta")
|
|
1828
|
+
if not isinstance(delta, dict):
|
|
1829
|
+
delta = test_delta if isinstance(test_delta, dict) else None
|
|
1830
|
+
if not isinstance(delta, dict):
|
|
1831
|
+
blockers.append(f"test_intent_lock_missing_delta: claim '{claim_type}' requires test_delta evidence")
|
|
1832
|
+
continue
|
|
1833
|
+
result = evaluate_test_delta(delta)
|
|
1834
|
+
if result.get("verdict") != "pass":
|
|
1835
|
+
reasons = result.get("reasons", [])
|
|
1836
|
+
reason_text = "; ".join(str(item) for item in reasons if str(item).strip())
|
|
1837
|
+
suffix = f": {reason_text}" if reason_text else ""
|
|
1838
|
+
blockers.append(f"test_intent_lock_blocked: claim '{claim_type}'{suffix}")
|
|
1839
|
+
return blockers
|
|
1840
|
+
|
|
1841
|
+
|
|
799
1842
|
def _check_eval_gate(output_root: Path) -> dict[str, Any]:
|
|
800
1843
|
latest_path = output_root / ".omg" / "evals" / "latest.json"
|
|
801
1844
|
if not latest_path.exists():
|
|
@@ -811,6 +1854,34 @@ def _check_eval_gate(output_root: Path) -> dict[str, Any]:
|
|
|
811
1854
|
}
|
|
812
1855
|
|
|
813
1856
|
|
|
1857
|
+
def _check_proof_chain(output_root: Path) -> dict[str, Any]:
|
|
1858
|
+
chain_module = importlib.import_module("runtime.proof_chain")
|
|
1859
|
+
gate_module = importlib.import_module("runtime.proof_gate")
|
|
1860
|
+
|
|
1861
|
+
gate_input = chain_module.build_proof_gate_input(str(output_root))
|
|
1862
|
+
chain = gate_input.get("proof_chain", {}) if isinstance(gate_input, dict) else {}
|
|
1863
|
+
chain_status = str(chain.get("status", "error"))
|
|
1864
|
+
raw_blockers = chain.get("blockers", [])
|
|
1865
|
+
blockers = [f"proof_chain_linkage: {item}" for item in raw_blockers] if isinstance(raw_blockers, list) else ["proof_chain_linkage: invalid blockers"]
|
|
1866
|
+
if chain_status == "ok":
|
|
1867
|
+
blockers = []
|
|
1868
|
+
|
|
1869
|
+
proof_gate = gate_module.evaluate_proof_gate(gate_input if isinstance(gate_input, dict) else {})
|
|
1870
|
+
if str(proof_gate.get("verdict", "fail")) != "pass":
|
|
1871
|
+
gate_blockers = proof_gate.get("blockers", [])
|
|
1872
|
+
if isinstance(gate_blockers, list) and gate_blockers:
|
|
1873
|
+
blockers.extend(f"proof_gate_blocked: {item}" for item in gate_blockers)
|
|
1874
|
+
else:
|
|
1875
|
+
blockers.append("proof_gate_blocked: verdict_fail")
|
|
1876
|
+
|
|
1877
|
+
return {
|
|
1878
|
+
"status": "ok" if not blockers else "error",
|
|
1879
|
+
"proof_chain": chain,
|
|
1880
|
+
"proof_gate": proof_gate,
|
|
1881
|
+
"blockers": blockers,
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
|
|
814
1885
|
def _check_packaged_install_smoke(root: Path) -> dict[str, Any]:
|
|
815
1886
|
blockers: list[str] = []
|
|
816
1887
|
with tempfile.TemporaryDirectory(prefix="omg-wheel-") as tmp_dir:
|