@trac3er/oh-my-god 2.1.0 → 2.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/omg/AGENTS.fragment.md +2 -2
- package/.agents/skills/omg/algorithms/SKILL.md +1 -1
- package/.agents/skills/omg/algorithms/openai.yaml +1 -1
- package/.agents/skills/omg/api-twin/SKILL.md +1 -1
- package/.agents/skills/omg/api-twin/openai.yaml +1 -1
- package/.agents/skills/omg/claim-judge/SKILL.md +1 -1
- package/.agents/skills/omg/claim-judge/openai.yaml +1 -1
- package/.agents/skills/omg/codex-rules.md +1 -1
- package/.agents/skills/omg/control-plane/SKILL.md +1 -1
- package/.agents/skills/omg/control-plane/openai.yaml +1 -1
- package/.agents/skills/omg/data-lineage/SKILL.md +1 -1
- package/.agents/skills/omg/data-lineage/openai.yaml +1 -1
- package/.agents/skills/omg/delta-classifier/SKILL.md +1 -1
- package/.agents/skills/omg/delta-classifier/openai.yaml +1 -1
- package/.agents/skills/omg/eval-gate/SKILL.md +1 -1
- package/.agents/skills/omg/eval-gate/openai.yaml +1 -1
- package/.agents/skills/omg/health/SKILL.md +1 -1
- package/.agents/skills/omg/health/openai.yaml +1 -1
- package/.agents/skills/omg/hook-governor/SKILL.md +1 -1
- package/.agents/skills/omg/hook-governor/openai.yaml +1 -1
- package/.agents/skills/omg/incident-replay/SKILL.md +1 -1
- package/.agents/skills/omg/incident-replay/openai.yaml +1 -1
- package/.agents/skills/omg/lsp-pack/SKILL.md +1 -1
- package/.agents/skills/omg/lsp-pack/openai.yaml +1 -1
- package/.agents/skills/omg/mcp-fabric/SKILL.md +1 -1
- package/.agents/skills/omg/mcp-fabric/openai.yaml +1 -1
- package/.agents/skills/omg/plan-council/SKILL.md +1 -1
- package/.agents/skills/omg/plan-council/openai.yaml +1 -1
- package/.agents/skills/omg/preflight/SKILL.md +1 -1
- package/.agents/skills/omg/preflight/openai.yaml +1 -1
- package/.agents/skills/omg/proof-gate/SKILL.md +1 -1
- package/.agents/skills/omg/proof-gate/openai.yaml +1 -1
- package/.agents/skills/omg/remote-supervisor/SKILL.md +1 -1
- package/.agents/skills/omg/remote-supervisor/openai.yaml +1 -1
- package/.agents/skills/omg/robotics/SKILL.md +1 -1
- package/.agents/skills/omg/robotics/openai.yaml +1 -1
- package/.agents/skills/omg/secure-worktree-pipeline/SKILL.md +1 -1
- package/.agents/skills/omg/secure-worktree-pipeline/openai.yaml +1 -1
- package/.agents/skills/omg/security-check/SKILL.md +1 -1
- package/.agents/skills/omg/security-check/openai.yaml +1 -1
- package/.agents/skills/omg/test-intent-lock/SKILL.md +1 -1
- package/.agents/skills/omg/test-intent-lock/openai.yaml +1 -1
- package/.agents/skills/omg/tracebank/SKILL.md +1 -1
- package/.agents/skills/omg/tracebank/openai.yaml +1 -1
- package/.agents/skills/omg/vision/SKILL.md +1 -1
- package/.agents/skills/omg/vision/openai.yaml +1 -1
- package/.claude-plugin/marketplace.json +3 -3
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +16 -0
- package/CLI-ADAPTER-MAP.md +3 -3
- package/OMG-setup.sh +114 -1
- package/OMG_COMPAT_CONTRACT.md +1 -1
- package/README.md +2 -1
- package/artifacts/release/.claude-plugin/marketplace.json +3 -3
- package/artifacts/release/.claude-plugin/plugin.json +1 -1
- package/artifacts/release/OMG_COMPAT_CONTRACT.md +1 -1
- package/artifacts/release/dist/enterprise/bundle/.claude-plugin/marketplace.json +3 -3
- package/artifacts/release/dist/enterprise/bundle/.claude-plugin/plugin.json +1 -1
- package/artifacts/release/dist/enterprise/bundle/OMG_COMPAT_CONTRACT.md +1 -1
- package/artifacts/release/dist/enterprise/bundle/plugins/advanced/plugin.json +26 -9
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/algorithms.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/api-twin.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/claim-judge.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/control-plane.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/data-lineage.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/delta-classifier.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/eval-gate.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/health.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/hook-governor.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/incident-replay.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/lsp-pack.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/mcp-fabric.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/plan-council.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/preflight.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/proof-gate.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/remote-supervisor.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/robotics.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/secure-worktree-pipeline.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/security-check.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/test-intent-lock.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/tracebank.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/bundles/vision.yaml +1 -1
- package/artifacts/release/dist/enterprise/bundle/registry/omg-capability.schema.json +1 -1
- package/artifacts/release/dist/enterprise/bundle/settings.json +3 -3
- package/artifacts/release/dist/enterprise/manifest.json +30 -40
- package/artifacts/release/dist/public/bundle/.claude-plugin/marketplace.json +3 -3
- package/artifacts/release/dist/public/bundle/.claude-plugin/plugin.json +1 -1
- package/artifacts/release/dist/public/bundle/OMG_COMPAT_CONTRACT.md +1 -1
- package/artifacts/release/dist/public/bundle/plugins/advanced/plugin.json +26 -9
- package/artifacts/release/dist/public/bundle/registry/bundles/algorithms.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/api-twin.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/claim-judge.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/control-plane.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/data-lineage.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/delta-classifier.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/eval-gate.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/health.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/hook-governor.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/incident-replay.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/lsp-pack.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/mcp-fabric.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/plan-council.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/preflight.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/proof-gate.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/remote-supervisor.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/robotics.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/secure-worktree-pipeline.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/security-check.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/test-intent-lock.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/tracebank.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/bundles/vision.yaml +1 -1
- package/artifacts/release/dist/public/bundle/registry/omg-capability.schema.json +1 -1
- package/artifacts/release/dist/public/bundle/settings.json +3 -3
- package/artifacts/release/dist/public/manifest.json +30 -40
- package/artifacts/release/plugins/advanced/plugin.json +26 -9
- package/artifacts/release/registry/bundles/algorithms.yaml +1 -1
- package/artifacts/release/registry/bundles/api-twin.yaml +1 -1
- package/artifacts/release/registry/bundles/claim-judge.yaml +1 -1
- package/artifacts/release/registry/bundles/control-plane.yaml +1 -1
- package/artifacts/release/registry/bundles/data-lineage.yaml +1 -1
- package/artifacts/release/registry/bundles/delta-classifier.yaml +1 -1
- package/artifacts/release/registry/bundles/eval-gate.yaml +1 -1
- package/artifacts/release/registry/bundles/health.yaml +1 -1
- package/artifacts/release/registry/bundles/hook-governor.yaml +1 -1
- package/artifacts/release/registry/bundles/incident-replay.yaml +1 -1
- package/artifacts/release/registry/bundles/lsp-pack.yaml +1 -1
- package/artifacts/release/registry/bundles/mcp-fabric.yaml +1 -1
- package/artifacts/release/registry/bundles/plan-council.yaml +1 -1
- package/artifacts/release/registry/bundles/preflight.yaml +1 -1
- package/artifacts/release/registry/bundles/proof-gate.yaml +1 -1
- package/artifacts/release/registry/bundles/remote-supervisor.yaml +1 -1
- package/artifacts/release/registry/bundles/robotics.yaml +1 -1
- package/artifacts/release/registry/bundles/secure-worktree-pipeline.yaml +1 -1
- package/artifacts/release/registry/bundles/security-check.yaml +1 -1
- package/artifacts/release/registry/bundles/test-intent-lock.yaml +1 -1
- package/artifacts/release/registry/bundles/tracebank.yaml +1 -1
- package/artifacts/release/registry/bundles/vision.yaml +1 -1
- package/artifacts/release/registry/omg-capability.schema.json +1 -1
- package/artifacts/release/settings.json +3 -3
- package/build/lib/commands/OMG:profile-review.md +43 -0
- package/build/lib/commands/OMG:validate.md +59 -0
- package/build/lib/control_plane/service.py +40 -1
- package/build/lib/hooks/_agent_registry.py +2 -0
- package/build/lib/hooks/firewall.py +263 -4
- package/build/lib/hooks/intentgate-keyword-detector.py +15 -3
- package/build/lib/hooks/policy_engine.py +77 -0
- package/build/lib/hooks/prompt-enhancer.py +146 -0
- package/build/lib/hooks/session-end-capture.py +374 -6
- package/build/lib/hooks/session-start.py +13 -35
- package/build/lib/hooks/setup_wizard.py +333 -1
- package/build/lib/hooks/shadow_manager.py +111 -2
- package/build/lib/hooks/stop_dispatcher.py +108 -4
- package/build/lib/plugins/advanced/plugin.json +26 -9
- package/build/lib/plugins/core/plugin.json +44 -11
- package/build/lib/registry/bundles/algorithms.yaml +1 -1
- package/build/lib/registry/bundles/api-twin.yaml +1 -1
- package/build/lib/registry/bundles/claim-judge.yaml +1 -1
- package/build/lib/registry/bundles/control-plane.yaml +1 -1
- package/build/lib/registry/bundles/data-lineage.yaml +1 -1
- package/build/lib/registry/bundles/delta-classifier.yaml +1 -1
- package/build/lib/registry/bundles/eval-gate.yaml +1 -1
- package/build/lib/registry/bundles/health.yaml +1 -1
- package/build/lib/registry/bundles/hook-governor.yaml +1 -1
- package/build/lib/registry/bundles/incident-replay.yaml +1 -1
- package/build/lib/registry/bundles/lsp-pack.yaml +1 -1
- package/build/lib/registry/bundles/mcp-fabric.yaml +1 -1
- package/build/lib/registry/bundles/plan-council.yaml +1 -1
- package/build/lib/registry/bundles/preflight.yaml +1 -1
- package/build/lib/registry/bundles/proof-gate.yaml +1 -1
- package/build/lib/registry/bundles/remote-supervisor.yaml +1 -1
- package/build/lib/registry/bundles/robotics.yaml +1 -1
- package/build/lib/registry/bundles/secure-worktree-pipeline.yaml +1 -1
- package/build/lib/registry/bundles/security-check.yaml +1 -1
- package/build/lib/registry/bundles/test-intent-lock.yaml +1 -1
- package/build/lib/registry/bundles/tracebank.yaml +1 -1
- package/build/lib/registry/bundles/vision.yaml +1 -1
- package/build/lib/registry/omg-capability.schema.json +1 -1
- package/build/lib/runtime/adoption.py +1 -1
- package/build/lib/runtime/background_verification.py +62 -0
- package/build/lib/runtime/claim_judge.py +165 -5
- package/build/lib/runtime/compat.py +15 -1
- package/build/lib/runtime/context_engine.py +261 -4
- package/build/lib/runtime/contract_compiler.py +370 -93
- package/build/lib/runtime/defense_state.py +79 -8
- package/build/lib/runtime/delta_classifier.py +80 -2
- package/build/lib/runtime/evidence_query.py +56 -4
- package/build/lib/runtime/evidence_registry.py +16 -0
- package/build/lib/runtime/evidence_requirements.py +47 -0
- package/build/lib/runtime/forge_agents.py +179 -9
- package/build/lib/runtime/forge_contracts.py +208 -2
- package/build/lib/runtime/interaction_journal.py +318 -42
- package/build/lib/runtime/memory_store.py +134 -1
- package/build/lib/runtime/mutation_gate.py +57 -11
- package/build/lib/runtime/omg_compat_contract_snapshot.json +2 -2
- package/build/lib/runtime/omg_mcp_server.py +14 -4
- package/build/lib/runtime/preflight.py +14 -0
- package/build/lib/runtime/profile_io.py +294 -0
- package/build/lib/runtime/proof_gate.py +122 -7
- package/build/lib/runtime/release_run_coordinator.py +339 -0
- package/build/lib/runtime/release_surfaces.py +243 -0
- package/build/lib/runtime/rollback_manifest.py +136 -0
- package/build/lib/runtime/router_critics.py +50 -0
- package/build/lib/runtime/runtime_contracts.py +137 -0
- package/build/lib/runtime/security_check.py +16 -0
- package/build/lib/runtime/session_health.py +60 -16
- package/build/lib/runtime/team_router.py +156 -13
- package/build/lib/runtime/test_intent_lock.py +102 -0
- package/build/lib/runtime/tool_plan_gate.py +249 -24
- package/build/lib/runtime/validate.py +194 -0
- package/build/lib/runtime/verification_controller.py +52 -2
- package/commands/OMG:diagnose-plugins.md +33 -0
- package/commands/OMG:profile-review.md +43 -0
- package/commands/OMG:setup.md +4 -1
- package/commands/OMG:validate.md +59 -0
- package/control_plane/service.py +40 -1
- package/dist/enterprise/bundle/.claude-plugin/marketplace.json +3 -3
- package/dist/enterprise/bundle/.claude-plugin/plugin.json +1 -1
- package/dist/enterprise/bundle/OMG_COMPAT_CONTRACT.md +1 -1
- package/dist/enterprise/bundle/plugins/advanced/plugin.json +26 -9
- package/dist/enterprise/bundle/registry/bundles/algorithms.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/api-twin.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/claim-judge.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/control-plane.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/data-lineage.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/delta-classifier.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/eval-gate.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/health.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/hook-governor.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/incident-replay.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/lsp-pack.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/mcp-fabric.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/plan-council.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/preflight.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/proof-gate.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/remote-supervisor.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/robotics.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/secure-worktree-pipeline.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/security-check.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/test-intent-lock.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/tracebank.yaml +1 -1
- package/dist/enterprise/bundle/registry/bundles/vision.yaml +1 -1
- package/dist/enterprise/bundle/registry/omg-capability.schema.json +1 -1
- package/dist/enterprise/bundle/settings.json +3 -3
- package/dist/enterprise/manifest.json +30 -40
- package/dist/oh_my_god-2.1.4-py3-none-any.whl +0 -0
- package/dist/oh_my_god-2.1.4.tar.gz +0 -0
- package/dist/public/bundle/.claude-plugin/marketplace.json +3 -3
- package/dist/public/bundle/.claude-plugin/plugin.json +1 -1
- package/dist/public/bundle/OMG_COMPAT_CONTRACT.md +1 -1
- package/dist/public/bundle/plugins/advanced/plugin.json +26 -9
- package/dist/public/bundle/registry/bundles/algorithms.yaml +1 -1
- package/dist/public/bundle/registry/bundles/api-twin.yaml +1 -1
- package/dist/public/bundle/registry/bundles/claim-judge.yaml +1 -1
- package/dist/public/bundle/registry/bundles/control-plane.yaml +1 -1
- package/dist/public/bundle/registry/bundles/data-lineage.yaml +1 -1
- package/dist/public/bundle/registry/bundles/delta-classifier.yaml +1 -1
- package/dist/public/bundle/registry/bundles/eval-gate.yaml +1 -1
- package/dist/public/bundle/registry/bundles/health.yaml +1 -1
- package/dist/public/bundle/registry/bundles/hook-governor.yaml +1 -1
- package/dist/public/bundle/registry/bundles/incident-replay.yaml +1 -1
- package/dist/public/bundle/registry/bundles/lsp-pack.yaml +1 -1
- package/dist/public/bundle/registry/bundles/mcp-fabric.yaml +1 -1
- package/dist/public/bundle/registry/bundles/plan-council.yaml +1 -1
- package/dist/public/bundle/registry/bundles/preflight.yaml +1 -1
- package/dist/public/bundle/registry/bundles/proof-gate.yaml +1 -1
- package/dist/public/bundle/registry/bundles/remote-supervisor.yaml +1 -1
- package/dist/public/bundle/registry/bundles/robotics.yaml +1 -1
- package/dist/public/bundle/registry/bundles/secure-worktree-pipeline.yaml +1 -1
- package/dist/public/bundle/registry/bundles/security-check.yaml +1 -1
- package/dist/public/bundle/registry/bundles/test-intent-lock.yaml +1 -1
- package/dist/public/bundle/registry/bundles/tracebank.yaml +1 -1
- package/dist/public/bundle/registry/bundles/vision.yaml +1 -1
- package/dist/public/bundle/registry/omg-capability.schema.json +1 -1
- package/dist/public/bundle/settings.json +3 -3
- package/dist/public/manifest.json +30 -40
- package/docs/install/opencode.md +30 -0
- package/docs/proof.md +11 -0
- package/docs/release-checklist.md +14 -1
- package/hooks/_agent_registry.py +2 -0
- package/hooks/firewall.py +263 -4
- package/hooks/intentgate-keyword-detector.py +15 -3
- package/hooks/policy_engine.py +77 -0
- package/hooks/prompt-enhancer.py +146 -0
- package/hooks/session-end-capture.py +374 -6
- package/hooks/session-start.py +13 -35
- package/hooks/setup_wizard.py +342 -2
- package/hooks/shadow_manager.py +111 -2
- package/hooks/stop_dispatcher.py +108 -4
- package/hud/omg-hud.mjs +30 -6
- package/lab/pipeline.py +197 -26
- package/package.json +1 -1
- package/plugins/advanced/plugin.json +26 -9
- package/plugins/core/plugin.json +51 -12
- package/pyproject.toml +10 -2
- package/registry/bundles/algorithms.yaml +1 -1
- package/registry/bundles/api-twin.yaml +1 -1
- package/registry/bundles/claim-judge.yaml +1 -1
- package/registry/bundles/control-plane.yaml +1 -1
- package/registry/bundles/data-lineage.yaml +1 -1
- package/registry/bundles/delta-classifier.yaml +1 -1
- package/registry/bundles/eval-gate.yaml +1 -1
- package/registry/bundles/health.yaml +1 -1
- package/registry/bundles/hook-governor.yaml +1 -1
- package/registry/bundles/incident-replay.yaml +1 -1
- package/registry/bundles/lsp-pack.yaml +1 -1
- package/registry/bundles/mcp-fabric.yaml +1 -1
- package/registry/bundles/plan-council.yaml +1 -1
- package/registry/bundles/preflight.yaml +1 -1
- package/registry/bundles/proof-gate.yaml +1 -1
- package/registry/bundles/remote-supervisor.yaml +1 -1
- package/registry/bundles/robotics.yaml +1 -1
- package/registry/bundles/secure-worktree-pipeline.yaml +1 -1
- package/registry/bundles/security-check.yaml +1 -1
- package/registry/bundles/test-intent-lock.yaml +1 -1
- package/registry/bundles/tracebank.yaml +1 -1
- package/registry/bundles/vision.yaml +1 -1
- package/registry/omg-capability.schema.json +1 -1
- package/runtime/adoption.py +7 -5
- package/runtime/background_verification.py +62 -0
- package/runtime/claim_judge.py +165 -5
- package/runtime/compat.py +48 -1
- package/runtime/context_engine.py +261 -4
- package/runtime/contract_compiler.py +370 -93
- package/runtime/defense_state.py +79 -8
- package/runtime/delta_classifier.py +80 -2
- package/runtime/evidence_query.py +56 -4
- package/runtime/evidence_registry.py +16 -0
- package/runtime/evidence_requirements.py +47 -0
- package/runtime/forge_agents.py +179 -9
- package/runtime/forge_contracts.py +208 -2
- package/runtime/hook_governor.py +19 -1
- package/runtime/interaction_journal.py +318 -42
- package/runtime/memory_store.py +134 -1
- package/runtime/mutation_gate.py +57 -11
- package/runtime/omg_compat_contract_snapshot.json +2 -2
- package/runtime/omg_mcp_server.py +14 -4
- package/runtime/plugin_diagnostics.py +248 -0
- package/runtime/plugin_interop.py +1007 -0
- package/runtime/preflight.py +14 -0
- package/runtime/profile_io.py +294 -0
- package/runtime/proof_gate.py +122 -7
- package/runtime/providers/opencode_provider.py +94 -0
- package/runtime/release_run_coordinator.py +339 -0
- package/runtime/release_surfaces.py +243 -0
- package/runtime/rollback_manifest.py +136 -0
- package/runtime/router_critics.py +50 -0
- package/runtime/runtime_contracts.py +137 -0
- package/runtime/security_check.py +16 -0
- package/runtime/session_health.py +60 -16
- package/runtime/team_router.py +156 -13
- package/runtime/test_intent_lock.py +102 -0
- package/runtime/tool_plan_gate.py +218 -19
- package/runtime/validate.py +289 -0
- package/runtime/verification_controller.py +52 -2
- package/scripts/omg.py +306 -3
- package/scripts/prepare-release-proof-fixtures.py +191 -7
- package/scripts/print-canonical-version.py +80 -0
- package/scripts/sync-release-identity.py +476 -0
- package/scripts/validate-release-identity.py +246 -0
- package/scripts/verify-standalone.sh +3 -0
- package/settings.json +3 -3
- package/templates/plugins-allowlist.yaml +19 -0
- package/artifacts/release/dist/enterprise/bundle/.gemini/settings.json +0 -11
- package/artifacts/release/dist/enterprise/bundle/.kimi/mcp.json +0 -11
- package/artifacts/release/dist/public/bundle/.gemini/settings.json +0 -11
- package/artifacts/release/dist/public/bundle/.kimi/mcp.json +0 -11
- package/build/lib/yaml.py +0 -321
- package/dist/enterprise/bundle/.gemini/settings.json +0 -11
- package/dist/enterprise/bundle/.kimi/mcp.json +0 -11
- package/dist/public/bundle/.gemini/settings.json +0 -11
- package/dist/public/bundle/.kimi/mcp.json +0 -11
|
@@ -14,7 +14,9 @@ Inspired by earlier OMG routing experiments. Key upgrades:
|
|
|
14
14
|
|
|
15
15
|
No dependency on CLAUDE.md or AGENTS.md.
|
|
16
16
|
"""
|
|
17
|
+
import hashlib
|
|
17
18
|
import json, sys, os, re, time
|
|
19
|
+
from datetime import datetime, timezone
|
|
18
20
|
import importlib
|
|
19
21
|
|
|
20
22
|
HOOKS_DIR = os.path.dirname(__file__)
|
|
@@ -77,6 +79,48 @@ def signal_matches_text(signal, text):
|
|
|
77
79
|
return signal in text
|
|
78
80
|
return re.search(r'\b' + re.escape(signal) + r'\b', text, re.IGNORECASE) is not None
|
|
79
81
|
|
|
82
|
+
|
|
83
|
+
def _hash_prompt(value):
|
|
84
|
+
return hashlib.sha256(value.encode("utf-8")).hexdigest()
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def _single_line(text, max_chars=220):
|
|
88
|
+
line = " ".join(str(text).replace("\r", " ").replace("\n", " ").split())
|
|
89
|
+
if len(line) > max_chars:
|
|
90
|
+
return line[: max_chars - 3] + "..."
|
|
91
|
+
return line
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def _resolve_run_id(payload, prompt_hash):
|
|
95
|
+
if isinstance(payload, dict):
|
|
96
|
+
run_id = payload.get("run_id")
|
|
97
|
+
if isinstance(run_id, str) and run_id.strip():
|
|
98
|
+
return run_id.strip()
|
|
99
|
+
tool_input = payload.get("tool_input")
|
|
100
|
+
if isinstance(tool_input, dict):
|
|
101
|
+
metadata = tool_input.get("metadata")
|
|
102
|
+
if isinstance(metadata, dict):
|
|
103
|
+
metadata_run_id = metadata.get("run_id")
|
|
104
|
+
if isinstance(metadata_run_id, str) and metadata_run_id.strip():
|
|
105
|
+
return metadata_run_id.strip()
|
|
106
|
+
env_run_id = os.environ.get("OMG_RUN_ID", "").strip()
|
|
107
|
+
if env_run_id:
|
|
108
|
+
return env_run_id
|
|
109
|
+
return prompt_hash[:24]
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def _count_signals(signals, text):
|
|
113
|
+
return sum(1 for sig in signals if signal_matches_text(sig, text))
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _write_intent_gate_artifact(state_root, run_id, artifact):
|
|
117
|
+
state_path = os.path.join(state_root, "intent_gate", f"{run_id}.json")
|
|
118
|
+
os.makedirs(os.path.dirname(state_path), exist_ok=True)
|
|
119
|
+
tmp_path = f"{state_path}.tmp"
|
|
120
|
+
with open(tmp_path, "w", encoding="utf-8") as tmp_file:
|
|
121
|
+
json.dump(artifact, tmp_file, indent=2, ensure_ascii=True)
|
|
122
|
+
os.replace(tmp_path, state_path)
|
|
123
|
+
|
|
80
124
|
# ── Zero-injection optimization ──
|
|
81
125
|
# Simple prompts (≤10 words, no coding/mode/routing signals) get zero overhead
|
|
82
126
|
_word_count_early = len(prompt_lower.split())
|
|
@@ -88,6 +132,8 @@ _has_any_signal = any([
|
|
|
88
132
|
"codex","gemini","ccg","screenshot","screen",
|
|
89
133
|
"security","warning","hook error","resume","handoff",
|
|
90
134
|
"continue","domain","scaffold","debug","deploy",
|
|
135
|
+
"setup","credential","credentials","preference",
|
|
136
|
+
"preferences","remember","settings","memory",
|
|
91
137
|
"수정","구현","버그","에러","고쳐","스크린샷","보안"]),
|
|
92
138
|
_word_count_early > 10,
|
|
93
139
|
])
|
|
@@ -127,14 +173,109 @@ INTENT_MAP = {
|
|
|
127
173
|
"구현", "빌드", "생성", "만들", "추가", "기능", "개발"],
|
|
128
174
|
"directive": "IMPLEMENT — Plan → code → test → verify. Follow existing patterns"
|
|
129
175
|
},
|
|
176
|
+
"auth_setup": {
|
|
177
|
+
"signals": ["auth", "login", "credential", "credentials", "oauth", "token", "setup auth",
|
|
178
|
+
"setup credential", "set up credential", "인증", "로그인", "자격 증명", "토큰"],
|
|
179
|
+
"directive": "AUTH_SETUP — Clarify auth target and credential source before changes"
|
|
180
|
+
},
|
|
181
|
+
"preference_memory": {
|
|
182
|
+
"signals": ["remember my settings", "remember settings", "preference", "preferences", "settings",
|
|
183
|
+
"memory style", "save my setup", "기억", "설정", "선호"],
|
|
184
|
+
"directive": "PREFERENCE_MEMORY — Clarify scope and persistence policy before changes"
|
|
185
|
+
},
|
|
186
|
+
"ambiguous_config": {
|
|
187
|
+
"signals": ["setup", "configure", "config", "remember", "save", "setup my", "set up",
|
|
188
|
+
"설정해", "구성", "저장"],
|
|
189
|
+
"directive": "AMBIGUOUS_CONFIG — Ask one-line clarification before any implementation"
|
|
190
|
+
},
|
|
130
191
|
}
|
|
131
192
|
|
|
193
|
+
IMPLEMENTATION_ACTION_SIGNALS = [
|
|
194
|
+
"implement", "build", "create", "add", "fix", "refactor", "update", "write", "code",
|
|
195
|
+
"debug", "test", "migrate", "deploy", "patch", "change", "구현", "추가", "수정", "개발",
|
|
196
|
+
]
|
|
197
|
+
AUTH_PROVIDER_SIGNALS = [
|
|
198
|
+
"codex", "claude", "gemini", "github", "google", "openai", "provider", "service", "cli",
|
|
199
|
+
]
|
|
200
|
+
AUTH_SOURCE_SIGNALS = [
|
|
201
|
+
"env", "token", "key", "secret", "credential", "password", "vault", "profile", "yaml",
|
|
202
|
+
]
|
|
203
|
+
PREFERENCE_SCOPE_SIGNALS = ["session", "project", "global", "default", "always", "workspace", "local"]
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def _build_intent_gate_state(prompt_text, payload):
|
|
207
|
+
has_auth = _count_signals(INTENT_MAP["auth_setup"]["signals"], prompt_text) > 0
|
|
208
|
+
has_pref = _count_signals(INTENT_MAP["preference_memory"]["signals"], prompt_text) > 0
|
|
209
|
+
has_ambiguous_config = _count_signals(INTENT_MAP["ambiguous_config"]["signals"], prompt_text) > 0
|
|
210
|
+
if not (has_auth or has_pref or has_ambiguous_config):
|
|
211
|
+
return None
|
|
212
|
+
|
|
213
|
+
has_specific_action = any(signal_matches_text(sig, prompt_text) for sig in IMPLEMENTATION_ACTION_SIGNALS)
|
|
214
|
+
|
|
215
|
+
if has_auth and has_pref:
|
|
216
|
+
intent_class = "ambiguous_config"
|
|
217
|
+
elif has_auth and has_ambiguous_config and not has_specific_action:
|
|
218
|
+
intent_class = "ambiguous_config"
|
|
219
|
+
elif has_auth:
|
|
220
|
+
intent_class = "auth_setup"
|
|
221
|
+
elif has_pref:
|
|
222
|
+
intent_class = "preference_memory"
|
|
223
|
+
else:
|
|
224
|
+
intent_class = "ambiguous_config"
|
|
225
|
+
|
|
226
|
+
missing_slots = []
|
|
227
|
+
if intent_class in ("auth_setup", "ambiguous_config"):
|
|
228
|
+
if not any(signal_matches_text(sig, prompt_text) for sig in AUTH_PROVIDER_SIGNALS):
|
|
229
|
+
missing_slots.append("provider")
|
|
230
|
+
if not any(signal_matches_text(sig, prompt_text) for sig in AUTH_SOURCE_SIGNALS):
|
|
231
|
+
missing_slots.append("credential_source")
|
|
232
|
+
if intent_class in ("preference_memory", "ambiguous_config"):
|
|
233
|
+
if not any(signal_matches_text(sig, prompt_text) for sig in PREFERENCE_SCOPE_SIGNALS):
|
|
234
|
+
missing_slots.append("scope")
|
|
235
|
+
if not has_specific_action:
|
|
236
|
+
missing_slots.append("desired_action")
|
|
237
|
+
|
|
238
|
+
requires_clarification = intent_class == "ambiguous_config" or bool(missing_slots)
|
|
239
|
+
clarification_prompt = ""
|
|
240
|
+
if requires_clarification:
|
|
241
|
+
prompt_map = {
|
|
242
|
+
"auth_setup": "Clarify auth setup in one line: target service, credential source, and exact action to run.",
|
|
243
|
+
"preference_memory": "Clarify preference memory in one line: settings to save, scope, and when to apply them.",
|
|
244
|
+
"ambiguous_config": "Clarify in one line whether this is auth setup or preference memory, plus the exact action to execute.",
|
|
245
|
+
}
|
|
246
|
+
clarification_prompt = _single_line(prompt_map[intent_class])
|
|
247
|
+
|
|
248
|
+
source_prompt_hash = _hash_prompt(prompt_text)
|
|
249
|
+
run_id = _resolve_run_id(payload, source_prompt_hash)
|
|
250
|
+
signal_hits = _count_signals(INTENT_MAP[intent_class]["signals"], prompt_text)
|
|
251
|
+
confidence = min(0.99, 0.76 + (signal_hits * 0.07) + (0.06 if intent_class == "ambiguous_config" else 0.0))
|
|
252
|
+
|
|
253
|
+
return {
|
|
254
|
+
"schema": "IntentGateClarificationState",
|
|
255
|
+
"schema_version": "1.0.0",
|
|
256
|
+
"run_id": run_id,
|
|
257
|
+
"intent_class": intent_class,
|
|
258
|
+
"confidence": round(confidence, 2),
|
|
259
|
+
"requires_clarification": requires_clarification,
|
|
260
|
+
"missing_slots": missing_slots,
|
|
261
|
+
"clarification_prompt": clarification_prompt,
|
|
262
|
+
"source_prompt_hash": source_prompt_hash,
|
|
263
|
+
"updated_at": datetime.now(timezone.utc).isoformat(),
|
|
264
|
+
}
|
|
265
|
+
|
|
132
266
|
detected_intent = None
|
|
133
267
|
for intent_key, intent_data in INTENT_MAP.items():
|
|
134
268
|
if any(signal_matches_text(sig, prompt) for sig in intent_data["signals"]):
|
|
135
269
|
detected_intent = intent_key
|
|
136
270
|
break
|
|
137
271
|
|
|
272
|
+
intent_gate_state = _build_intent_gate_state(prompt, data)
|
|
273
|
+
if intent_gate_state is not None:
|
|
274
|
+
try:
|
|
275
|
+
_write_intent_gate_artifact(state_dir, intent_gate_state["run_id"], intent_gate_state)
|
|
276
|
+
except Exception:
|
|
277
|
+
pass
|
|
278
|
+
|
|
138
279
|
# ═══════════════════════════════════════════════════════════
|
|
139
280
|
# 2. DISCIPLINE SYSTEM (Sisyphus-grade)
|
|
140
281
|
# ═══════════════════════════════════════════════════════════
|
|
@@ -143,6 +284,11 @@ parts = []
|
|
|
143
284
|
if detected_intent:
|
|
144
285
|
parts.append(f"@intent: {INTENT_MAP[detected_intent]['directive']}")
|
|
145
286
|
|
|
287
|
+
if intent_gate_state and intent_gate_state.get("requires_clarification"):
|
|
288
|
+
clarification_line = _single_line(intent_gate_state.get("clarification_prompt", ""))
|
|
289
|
+
if clarification_line:
|
|
290
|
+
parts.append(f"@intent-clarify: {clarification_line}")
|
|
291
|
+
|
|
146
292
|
parts.append(
|
|
147
293
|
"@discipline: Senior-eng mode. Clean minimal code. "
|
|
148
294
|
"VERIFY changes. NEVER claim done unverified. "
|
|
@@ -9,14 +9,21 @@ Features are implemented in later tasks:
|
|
|
9
9
|
import sys
|
|
10
10
|
import os
|
|
11
11
|
import json
|
|
12
|
+
import glob
|
|
12
13
|
from datetime import datetime
|
|
13
14
|
from typing import Callable, cast
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
import yaml
|
|
17
|
+
|
|
18
|
+
_HOOKS_DIR = os.path.dirname(__file__)
|
|
19
|
+
_PROJECT_ROOT = os.path.dirname(_HOOKS_DIR)
|
|
20
|
+
if _PROJECT_ROOT not in sys.path:
|
|
21
|
+
sys.path.insert(0, _PROJECT_ROOT)
|
|
22
|
+
|
|
23
|
+
from hooks._common import setup_crash_handler as _setup_crash_handler
|
|
24
|
+
from hooks._common import json_input as _json_input
|
|
25
|
+
from hooks._common import get_feature_flag as _get_feature_flag
|
|
26
|
+
from hooks._common import log_hook_error as _log_hook_error
|
|
20
27
|
|
|
21
28
|
setup_crash_handler = cast(Callable[[str, bool], None], _setup_crash_handler)
|
|
22
29
|
json_input = cast(Callable[[], dict[str, str]], _json_input)
|
|
@@ -25,6 +32,362 @@ log_hook_error = cast(Callable[[str, str], None], _log_hook_error)
|
|
|
25
32
|
|
|
26
33
|
setup_crash_handler('session-end-capture', False)
|
|
27
34
|
|
|
35
|
+
_PROFILE_ARCH_REQUEST_MAX = 8
|
|
36
|
+
_PROFILE_TAG_MAX = 12
|
|
37
|
+
_PROFILE_RECENT_UPDATES_MAX = 5
|
|
38
|
+
_MIN_SIGNAL_CONFIDENCE = 0.7
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def _read_json_file(path: str) -> dict[str, object]:
|
|
42
|
+
if not os.path.exists(path):
|
|
43
|
+
return {}
|
|
44
|
+
try:
|
|
45
|
+
with open(path, "r", encoding="utf-8", errors="replace") as file_obj:
|
|
46
|
+
payload = json.load(file_obj)
|
|
47
|
+
except (OSError, json.JSONDecodeError, ValueError):
|
|
48
|
+
return {}
|
|
49
|
+
if isinstance(payload, dict):
|
|
50
|
+
return payload
|
|
51
|
+
return {}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def _read_recent_failure_entries(project_dir: str, limit: int = 20) -> list[dict[str, object]]:
|
|
55
|
+
ledger_dir = os.path.join(project_dir, ".omg", "state", "ledger")
|
|
56
|
+
if not os.path.exists(ledger_dir):
|
|
57
|
+
return []
|
|
58
|
+
|
|
59
|
+
entries: list[dict[str, object]] = []
|
|
60
|
+
try:
|
|
61
|
+
failure_files = sorted(glob.glob(os.path.join(ledger_dir, "failure-*.jsonl")))
|
|
62
|
+
except OSError:
|
|
63
|
+
return []
|
|
64
|
+
|
|
65
|
+
for file_path in failure_files[-5:]:
|
|
66
|
+
try:
|
|
67
|
+
with open(file_path, "r", encoding="utf-8", errors="replace") as file_obj:
|
|
68
|
+
for line in file_obj:
|
|
69
|
+
text = line.strip()
|
|
70
|
+
if not text:
|
|
71
|
+
continue
|
|
72
|
+
try:
|
|
73
|
+
payload = json.loads(text)
|
|
74
|
+
except (TypeError, ValueError, json.JSONDecodeError):
|
|
75
|
+
continue
|
|
76
|
+
if isinstance(payload, dict):
|
|
77
|
+
entries.append(cast(dict[str, object], payload))
|
|
78
|
+
except OSError:
|
|
79
|
+
continue
|
|
80
|
+
return entries[-limit:]
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def _normalize_tag_token(value: str) -> str:
|
|
84
|
+
lowered = value.strip().lower().replace(" ", "_")
|
|
85
|
+
return "".join(ch for ch in lowered if ch.isalnum() or ch in ("_", "-"))
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _normalize_constraint_key(value: str) -> str:
|
|
89
|
+
lowered = value.strip().lower().replace(" ", "_")
|
|
90
|
+
return "".join(ch for ch in lowered if ch.isalnum() or ch == "_")
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def _normalize_constraint_value(value: object) -> str | int | float | bool | None:
|
|
94
|
+
if isinstance(value, bool):
|
|
95
|
+
return value
|
|
96
|
+
if isinstance(value, int):
|
|
97
|
+
return value
|
|
98
|
+
if isinstance(value, float):
|
|
99
|
+
return value
|
|
100
|
+
if value is None:
|
|
101
|
+
return None
|
|
102
|
+
text = " ".join(str(value).strip().split()).lower()
|
|
103
|
+
return text if text else None
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _ensure_profile_baseline(profile: dict[str, object]) -> None:
|
|
107
|
+
preferences_obj = profile.get("preferences")
|
|
108
|
+
preferences = preferences_obj if isinstance(preferences_obj, dict) else {}
|
|
109
|
+
arch_obj = preferences.get("architecture_requests")
|
|
110
|
+
preferences["architecture_requests"] = arch_obj if isinstance(arch_obj, list) else []
|
|
111
|
+
constraints_obj = preferences.get("constraints")
|
|
112
|
+
preferences["constraints"] = constraints_obj if isinstance(constraints_obj, dict) else {}
|
|
113
|
+
profile["preferences"] = preferences
|
|
114
|
+
|
|
115
|
+
user_vector_obj = profile.get("user_vector")
|
|
116
|
+
user_vector = user_vector_obj if isinstance(user_vector_obj, dict) else {}
|
|
117
|
+
tags_obj = user_vector.get("tags")
|
|
118
|
+
user_vector["tags"] = tags_obj if isinstance(tags_obj, list) else []
|
|
119
|
+
profile["user_vector"] = user_vector
|
|
120
|
+
|
|
121
|
+
provenance_obj = profile.get("profile_provenance")
|
|
122
|
+
provenance = provenance_obj if isinstance(provenance_obj, dict) else {}
|
|
123
|
+
updates_obj = provenance.get("recent_updates")
|
|
124
|
+
provenance["recent_updates"] = updates_obj if isinstance(updates_obj, list) else []
|
|
125
|
+
profile["profile_provenance"] = provenance
|
|
126
|
+
|
|
127
|
+
try:
|
|
128
|
+
from runtime.profile_io import ensure_governed_preferences
|
|
129
|
+
ensure_governed_preferences(cast(dict[str, object], profile))
|
|
130
|
+
except Exception:
|
|
131
|
+
profile["governed_preferences"] = {"style": [], "safety": []}
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def _record_provenance(
|
|
135
|
+
profile: dict[str, object],
|
|
136
|
+
*,
|
|
137
|
+
run_id: str,
|
|
138
|
+
source: str,
|
|
139
|
+
field: str,
|
|
140
|
+
updated_at: str,
|
|
141
|
+
) -> None:
|
|
142
|
+
provenance = cast(dict[str, object], profile["profile_provenance"])
|
|
143
|
+
raw_updates = provenance.get("recent_updates", [])
|
|
144
|
+
updates = raw_updates if isinstance(raw_updates, list) else []
|
|
145
|
+
updates.append(
|
|
146
|
+
{
|
|
147
|
+
"run_id": run_id,
|
|
148
|
+
"source": source,
|
|
149
|
+
"field": field,
|
|
150
|
+
"updated_at": updated_at,
|
|
151
|
+
}
|
|
152
|
+
)
|
|
153
|
+
provenance["recent_updates"] = updates[-_PROFILE_RECENT_UPDATES_MAX:]
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def _signal_is_contradicted(
|
|
157
|
+
signal: dict[str, object],
|
|
158
|
+
council_payload: dict[str, object],
|
|
159
|
+
failure_entries: list[dict[str, object]],
|
|
160
|
+
) -> bool:
|
|
161
|
+
if bool(signal.get("contradicted") is True):
|
|
162
|
+
return True
|
|
163
|
+
|
|
164
|
+
field = str(signal.get("field", "")).strip()
|
|
165
|
+
verdicts_obj = council_payload.get("verdicts")
|
|
166
|
+
verdicts = verdicts_obj if isinstance(verdicts_obj, dict) else {}
|
|
167
|
+
for verdict in verdicts.values():
|
|
168
|
+
if not isinstance(verdict, dict):
|
|
169
|
+
continue
|
|
170
|
+
notes = " ".join(
|
|
171
|
+
str(verdict.get(part, ""))
|
|
172
|
+
for part in ("reason", "notes", "message", "detail")
|
|
173
|
+
).lower()
|
|
174
|
+
if "contradict" in notes and (not field or field in notes):
|
|
175
|
+
return True
|
|
176
|
+
|
|
177
|
+
for entry in failure_entries:
|
|
178
|
+
if bool(entry.get("contradicted") is True):
|
|
179
|
+
entry_field = str(entry.get("field", "")).strip()
|
|
180
|
+
if not entry_field or entry_field == field:
|
|
181
|
+
return True
|
|
182
|
+
detail = " ".join(
|
|
183
|
+
str(entry.get(part, ""))
|
|
184
|
+
for part in ("error", "reason", "message", "detail")
|
|
185
|
+
).lower()
|
|
186
|
+
if "contradict" in detail and (not field or field in detail):
|
|
187
|
+
return True
|
|
188
|
+
return False
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
def _promote_preference_learning(project_dir: str, run_id: str) -> None:
|
|
192
|
+
project_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
|
193
|
+
if project_root not in sys.path:
|
|
194
|
+
sys.path.insert(0, project_root)
|
|
195
|
+
try:
|
|
196
|
+
from runtime.memory_store import project_preference_signals
|
|
197
|
+
except Exception:
|
|
198
|
+
return
|
|
199
|
+
|
|
200
|
+
intent_gate_path = os.path.join(project_dir, ".omg", "state", "intent_gate", f"{run_id}.json")
|
|
201
|
+
council_path = os.path.join(project_dir, ".omg", "state", "council_verdicts", f"{run_id}.json")
|
|
202
|
+
health_path = os.path.join(project_dir, ".omg", "state", "session_health", f"{run_id}.json")
|
|
203
|
+
profile_path = os.path.join(project_dir, ".omg", "state", "profile.yaml")
|
|
204
|
+
|
|
205
|
+
intent_gate = _read_json_file(intent_gate_path)
|
|
206
|
+
council_payload = _read_json_file(council_path)
|
|
207
|
+
session_health = _read_json_file(health_path)
|
|
208
|
+
failure_entries = _read_recent_failure_entries(project_dir)
|
|
209
|
+
|
|
210
|
+
candidate_signals = project_preference_signals(project_dir, max_signals=12)
|
|
211
|
+
if not candidate_signals:
|
|
212
|
+
return
|
|
213
|
+
|
|
214
|
+
if not os.path.exists(profile_path):
|
|
215
|
+
return
|
|
216
|
+
|
|
217
|
+
try:
|
|
218
|
+
from runtime.profile_io import load_profile
|
|
219
|
+
profile = cast(dict[str, object], load_profile(profile_path))
|
|
220
|
+
except Exception:
|
|
221
|
+
return
|
|
222
|
+
if not profile:
|
|
223
|
+
return
|
|
224
|
+
had_governed = isinstance(profile.get("governed_preferences"), dict)
|
|
225
|
+
_ensure_profile_baseline(profile)
|
|
226
|
+
baseline_changed = not had_governed
|
|
227
|
+
|
|
228
|
+
health_status = str(session_health.get("status", "")).strip().lower()
|
|
229
|
+
health_action = str(session_health.get("recommended_action", "")).strip().lower()
|
|
230
|
+
council_status = str(council_payload.get("status", "")).strip().lower()
|
|
231
|
+
requires_clarification = bool(intent_gate.get("requires_clarification") is True)
|
|
232
|
+
inferred_blocked = (
|
|
233
|
+
health_status == "blocked"
|
|
234
|
+
or health_action == "block"
|
|
235
|
+
or council_status in ("blocked", "fail")
|
|
236
|
+
or requires_clarification
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
inferred_counts: dict[tuple[str, str], int] = {}
|
|
240
|
+
explicit_to_apply: list[dict[str, object]] = []
|
|
241
|
+
inferred_to_apply: list[dict[str, object]] = []
|
|
242
|
+
|
|
243
|
+
for signal in candidate_signals:
|
|
244
|
+
confidence = signal.get("confidence", 0.0)
|
|
245
|
+
try:
|
|
246
|
+
signal_confidence = float(confidence)
|
|
247
|
+
except (TypeError, ValueError):
|
|
248
|
+
signal_confidence = 0.0
|
|
249
|
+
if signal_confidence < _MIN_SIGNAL_CONFIDENCE:
|
|
250
|
+
continue
|
|
251
|
+
if _signal_is_contradicted(signal, council_payload, failure_entries):
|
|
252
|
+
continue
|
|
253
|
+
|
|
254
|
+
source = str(signal.get("source", "")).strip().lower()
|
|
255
|
+
if source in ("explicit_user", "direct_user", "user_stated"):
|
|
256
|
+
explicit_to_apply.append(signal)
|
|
257
|
+
continue
|
|
258
|
+
|
|
259
|
+
field = str(signal.get("field", "")).strip()
|
|
260
|
+
value = " ".join(str(signal.get("value", "")).strip().split())
|
|
261
|
+
if not field or not value:
|
|
262
|
+
continue
|
|
263
|
+
key = (field, value)
|
|
264
|
+
inferred_counts[key] = inferred_counts.get(key, 0) + 1
|
|
265
|
+
inferred_to_apply.append(signal)
|
|
266
|
+
|
|
267
|
+
pending_writes: list[dict[str, object]] = list(explicit_to_apply)
|
|
268
|
+
if not inferred_blocked:
|
|
269
|
+
for signal in inferred_to_apply:
|
|
270
|
+
field = str(signal.get("field", "")).strip()
|
|
271
|
+
value = " ".join(str(signal.get("value", "")).strip().split())
|
|
272
|
+
if inferred_counts.get((field, value), 0) >= 2:
|
|
273
|
+
pending_writes.append(signal)
|
|
274
|
+
|
|
275
|
+
if not pending_writes:
|
|
276
|
+
if baseline_changed:
|
|
277
|
+
try:
|
|
278
|
+
from runtime.profile_io import save_profile
|
|
279
|
+
save_profile(profile_path, profile)
|
|
280
|
+
except Exception:
|
|
281
|
+
pass
|
|
282
|
+
return
|
|
283
|
+
|
|
284
|
+
updated_at = datetime.utcnow().isoformat() + "Z"
|
|
285
|
+
changed = False
|
|
286
|
+
for signal in pending_writes:
|
|
287
|
+
field = str(signal.get("field", "")).strip()
|
|
288
|
+
value = " ".join(str(signal.get("value", "")).strip().split())
|
|
289
|
+
if not field or not value:
|
|
290
|
+
continue
|
|
291
|
+
|
|
292
|
+
source = str(signal.get("source", "")).strip().lower() or "inferred_observation"
|
|
293
|
+
section = str(signal.get("section", "style")).strip().lower() or "style"
|
|
294
|
+
is_destructive = bool(signal.get("destructive") is True)
|
|
295
|
+
|
|
296
|
+
if section not in ("style", "safety"):
|
|
297
|
+
section = "style"
|
|
298
|
+
|
|
299
|
+
if is_destructive:
|
|
300
|
+
confirmation_state = "pending_confirmation"
|
|
301
|
+
elif source in ("explicit_user", "direct_user", "user_stated"):
|
|
302
|
+
confirmation_state = "confirmed"
|
|
303
|
+
else:
|
|
304
|
+
confirmation_state = "inferred"
|
|
305
|
+
|
|
306
|
+
decay_metadata: dict[str, object] | None = None
|
|
307
|
+
if section == "style" and confirmation_state == "inferred":
|
|
308
|
+
decay_metadata = {
|
|
309
|
+
"decay_score": 0.0,
|
|
310
|
+
"last_seen_at": updated_at,
|
|
311
|
+
"decay_reason": "inferred_signal",
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
try:
|
|
315
|
+
from runtime.profile_io import upsert_governed_preference
|
|
316
|
+
upsert_governed_preference(
|
|
317
|
+
cast(dict[str, object], profile),
|
|
318
|
+
field=field,
|
|
319
|
+
value=value,
|
|
320
|
+
source=source,
|
|
321
|
+
learned_at=updated_at,
|
|
322
|
+
updated_at=updated_at,
|
|
323
|
+
section=section,
|
|
324
|
+
confirmation_state=confirmation_state,
|
|
325
|
+
decay_metadata=decay_metadata,
|
|
326
|
+
)
|
|
327
|
+
changed = True
|
|
328
|
+
except Exception:
|
|
329
|
+
pass
|
|
330
|
+
|
|
331
|
+
if confirmation_state == "pending_confirmation":
|
|
332
|
+
continue
|
|
333
|
+
|
|
334
|
+
preferences = cast(dict[str, object], profile["preferences"])
|
|
335
|
+
user_vector = cast(dict[str, object], profile["user_vector"])
|
|
336
|
+
|
|
337
|
+
if field == "preferences.architecture_requests":
|
|
338
|
+
raw_arch = preferences.get("architecture_requests", [])
|
|
339
|
+
arch = raw_arch if isinstance(raw_arch, list) else []
|
|
340
|
+
if value in arch:
|
|
341
|
+
continue
|
|
342
|
+
arch.append(value)
|
|
343
|
+
preferences["architecture_requests"] = arch[-_PROFILE_ARCH_REQUEST_MAX:]
|
|
344
|
+
_record_provenance(profile, run_id=run_id, source=source, field=field, updated_at=updated_at)
|
|
345
|
+
changed = True
|
|
346
|
+
continue
|
|
347
|
+
|
|
348
|
+
if field.startswith("preferences.constraints."):
|
|
349
|
+
constraint_key = _normalize_constraint_key(field.split("preferences.constraints.", 1)[1])
|
|
350
|
+
constraint_value = _normalize_constraint_value(value)
|
|
351
|
+
if not constraint_key or constraint_value is None:
|
|
352
|
+
continue
|
|
353
|
+
raw_constraints = preferences.get("constraints", {})
|
|
354
|
+
constraints = raw_constraints if isinstance(raw_constraints, dict) else {}
|
|
355
|
+
if constraints.get(constraint_key) == constraint_value:
|
|
356
|
+
continue
|
|
357
|
+
constraints[constraint_key] = constraint_value
|
|
358
|
+
preferences["constraints"] = constraints
|
|
359
|
+
_record_provenance(profile, run_id=run_id, source=source, field=field, updated_at=updated_at)
|
|
360
|
+
changed = True
|
|
361
|
+
continue
|
|
362
|
+
|
|
363
|
+
if field == "user_vector.tags":
|
|
364
|
+
token = _normalize_tag_token(value)
|
|
365
|
+
if not token:
|
|
366
|
+
continue
|
|
367
|
+
raw_tags = user_vector.get("tags", [])
|
|
368
|
+
tags = raw_tags if isinstance(raw_tags, list) else []
|
|
369
|
+
if token in tags:
|
|
370
|
+
continue
|
|
371
|
+
tags.append(token)
|
|
372
|
+
user_vector["tags"] = tags[-_PROFILE_TAG_MAX:]
|
|
373
|
+
_record_provenance(profile, run_id=run_id, source=source, field=field, updated_at=updated_at)
|
|
374
|
+
changed = True
|
|
375
|
+
|
|
376
|
+
if not changed:
|
|
377
|
+
if baseline_changed:
|
|
378
|
+
try:
|
|
379
|
+
from runtime.profile_io import save_profile
|
|
380
|
+
save_profile(profile_path, profile)
|
|
381
|
+
except Exception:
|
|
382
|
+
pass
|
|
383
|
+
return
|
|
384
|
+
|
|
385
|
+
try:
|
|
386
|
+
from runtime.profile_io import save_profile
|
|
387
|
+
save_profile(profile_path, profile)
|
|
388
|
+
except Exception:
|
|
389
|
+
return
|
|
390
|
+
|
|
28
391
|
data = json_input()
|
|
29
392
|
session_id = data.get('session_id', 'unknown')
|
|
30
393
|
cwd = data.get('cwd', os.getcwd())
|
|
@@ -32,7 +395,7 @@ cwd = data.get('cwd', os.getcwd())
|
|
|
32
395
|
# Capture A: Memory (implemented in Task 19)
|
|
33
396
|
if get_feature_flag('memory'):
|
|
34
397
|
try:
|
|
35
|
-
from _memory import save_memory, rotate_memories
|
|
398
|
+
from hooks._memory import save_memory, rotate_memories
|
|
36
399
|
|
|
37
400
|
summary_parts = [f"# Session: {datetime.now().strftime('%Y-%m-%d')} ({session_id[:8]})"]
|
|
38
401
|
|
|
@@ -134,4 +497,9 @@ if get_feature_flag('compound_learning'):
|
|
|
134
497
|
except Exception as e:
|
|
135
498
|
log_hook_error('session-end-capture', str(e))
|
|
136
499
|
|
|
500
|
+
try:
|
|
501
|
+
_promote_preference_learning(cwd, session_id)
|
|
502
|
+
except Exception as e:
|
|
503
|
+
log_hook_error('session-end-capture', str(e))
|
|
504
|
+
|
|
137
505
|
sys.exit(0)
|
|
@@ -11,12 +11,16 @@ import time as _time
|
|
|
11
11
|
import re as _re
|
|
12
12
|
|
|
13
13
|
HOOKS_DIR = os.path.dirname(__file__)
|
|
14
|
+
PROJECT_ROOT = os.path.dirname(HOOKS_DIR)
|
|
15
|
+
if PROJECT_ROOT not in sys.path:
|
|
16
|
+
sys.path.insert(0, PROJECT_ROOT)
|
|
14
17
|
if HOOKS_DIR not in sys.path:
|
|
15
18
|
sys.path.insert(0, HOOKS_DIR)
|
|
16
19
|
|
|
17
|
-
from _common import setup_crash_handler, json_input, get_feature_flag, _resolve_project_dir
|
|
18
|
-
from state_migration import resolve_state_file, resolve_state_dir
|
|
19
|
-
from _budget import BUDGET_SESSION_TOTAL, BUDGET_SESSION_IDLE
|
|
20
|
+
from hooks._common import setup_crash_handler, json_input, get_feature_flag, _resolve_project_dir
|
|
21
|
+
from hooks.state_migration import resolve_state_file, resolve_state_dir
|
|
22
|
+
from hooks._budget import BUDGET_SESSION_TOTAL, BUDGET_SESSION_IDLE
|
|
23
|
+
from runtime.context_engine import render_profile_digest_text
|
|
20
24
|
|
|
21
25
|
setup_crash_handler("session-start", fail_closed=False)
|
|
22
26
|
|
|
@@ -43,37 +47,11 @@ project_path = resolve_state_file(project_dir, "state/project.md", "project.md")
|
|
|
43
47
|
|
|
44
48
|
profile = _read_file(profile_path, 3000)
|
|
45
49
|
if profile:
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
continue
|
|
52
|
-
k, v = l.split(":", 1)
|
|
53
|
-
k = k.strip().lower()
|
|
54
|
-
v = v.strip().strip('"').strip("'")
|
|
55
|
-
if k in ("conventions", "ai_behavior"):
|
|
56
|
-
current_section = k
|
|
57
|
-
continue
|
|
58
|
-
if current_section:
|
|
59
|
-
kv[f"{current_section}.{k}"] = v
|
|
60
|
-
else:
|
|
61
|
-
kv[k] = v
|
|
62
|
-
|
|
63
|
-
name = kv.get("name", "")
|
|
64
|
-
conv_parts = []
|
|
65
|
-
for ck in ["conventions.naming", "conventions.test_cmd", "conventions.lint_cmd"]:
|
|
66
|
-
if kv.get(ck):
|
|
67
|
-
conv_parts.append(f"{ck.split('.')[-1]}={kv[ck]}")
|
|
68
|
-
comm = kv.get("ai_behavior.communication", "")
|
|
69
|
-
|
|
70
|
-
summary_parts = [name] if name else []
|
|
71
|
-
if conv_parts:
|
|
72
|
-
summary_parts.append(" ".join(conv_parts))
|
|
73
|
-
if comm:
|
|
74
|
-
summary_parts.append(f"lang:{comm}")
|
|
75
|
-
if summary_parts:
|
|
76
|
-
sections.append(f"@project: {' | '.join(summary_parts)}")
|
|
50
|
+
# Inject bounded profile digest — skips discoverable info (conventions, ai_behavior)
|
|
51
|
+
# and surfaces only non-discoverable preferences via render_profile_digest_text.
|
|
52
|
+
digest = render_profile_digest_text(project_dir, max_chars=240)
|
|
53
|
+
if digest:
|
|
54
|
+
sections.append(f"@project: profile_digest={digest}")
|
|
77
55
|
else:
|
|
78
56
|
project = _read_file(project_path, 1000)
|
|
79
57
|
if project:
|
|
@@ -243,7 +221,7 @@ if os.path.exists(tracker_path):
|
|
|
243
221
|
# 6) Recent memory (on-demand)
|
|
244
222
|
if get_feature_flag('memory'):
|
|
245
223
|
try:
|
|
246
|
-
from _memory import get_recent_memories
|
|
224
|
+
from hooks._memory import get_recent_memories
|
|
247
225
|
recent = get_recent_memories(project_dir, max_files=3, max_chars_total=150)
|
|
248
226
|
if recent:
|
|
249
227
|
sections.append(f'@recent-memory: {recent}')
|