@trac3er/oh-my-god 2.0.3 → 2.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (259) hide show
  1. package/.agents/skills/omg/AGENTS.fragment.md +5 -0
  2. package/.agents/skills/omg/algorithms/SKILL.md +11 -0
  3. package/.agents/skills/omg/algorithms/openai.yaml +11 -0
  4. package/.agents/skills/omg/api-twin/SKILL.md +11 -0
  5. package/.agents/skills/omg/api-twin/openai.yaml +12 -0
  6. package/.agents/skills/omg/codex-mcp.toml +4 -0
  7. package/.agents/skills/omg/control-plane/SKILL.md +11 -0
  8. package/.agents/skills/omg/control-plane/openai.yaml +14 -0
  9. package/.agents/skills/omg/data-lineage/SKILL.md +11 -0
  10. package/.agents/skills/omg/data-lineage/openai.yaml +12 -0
  11. package/.agents/skills/omg/delta-classifier/SKILL.md +11 -0
  12. package/.agents/skills/omg/delta-classifier/openai.yaml +12 -0
  13. package/.agents/skills/omg/eval-gate/SKILL.md +11 -0
  14. package/.agents/skills/omg/eval-gate/openai.yaml +12 -0
  15. package/.agents/skills/omg/health/SKILL.md +11 -0
  16. package/.agents/skills/omg/health/openai.yaml +11 -0
  17. package/.agents/skills/omg/hook-governor/SKILL.md +11 -0
  18. package/.agents/skills/omg/hook-governor/openai.yaml +11 -0
  19. package/.agents/skills/omg/incident-replay/SKILL.md +11 -0
  20. package/.agents/skills/omg/incident-replay/openai.yaml +12 -0
  21. package/.agents/skills/omg/lsp-pack/SKILL.md +11 -0
  22. package/.agents/skills/omg/lsp-pack/openai.yaml +11 -0
  23. package/.agents/skills/omg/mcp-fabric/SKILL.md +11 -0
  24. package/.agents/skills/omg/mcp-fabric/openai.yaml +13 -0
  25. package/.agents/skills/omg/preflight/SKILL.md +11 -0
  26. package/.agents/skills/omg/preflight/openai.yaml +12 -0
  27. package/.agents/skills/omg/remote-supervisor/SKILL.md +11 -0
  28. package/.agents/skills/omg/remote-supervisor/openai.yaml +12 -0
  29. package/.agents/skills/omg/robotics/SKILL.md +11 -0
  30. package/.agents/skills/omg/robotics/openai.yaml +11 -0
  31. package/.agents/skills/omg/secure-worktree-pipeline/SKILL.md +11 -0
  32. package/.agents/skills/omg/secure-worktree-pipeline/openai.yaml +12 -0
  33. package/.agents/skills/omg/security-check/SKILL.md +11 -0
  34. package/.agents/skills/omg/security-check/openai.yaml +13 -0
  35. package/.agents/skills/omg/tracebank/SKILL.md +11 -0
  36. package/.agents/skills/omg/tracebank/openai.yaml +12 -0
  37. package/.agents/skills/omg/vision/SKILL.md +11 -0
  38. package/.agents/skills/omg/vision/openai.yaml +11 -0
  39. package/.claude-plugin/marketplace.json +3 -3
  40. package/.claude-plugin/plugin.json +1 -1
  41. package/.claude-plugin/scripts/uninstall.sh +2 -2
  42. package/.mcp.json +20 -4
  43. package/CHANGELOG.md +10 -0
  44. package/OMG-setup.sh +9 -3
  45. package/OMG_COMPAT_CONTRACT.md +92 -0
  46. package/README.md +24 -4
  47. package/SECURITY.md +6 -0
  48. package/commands/OMG:api-twin.md +22 -0
  49. package/commands/OMG:preflight.md +26 -0
  50. package/commands/OMG:security-check.md +28 -0
  51. package/commands/__init__.py +1 -0
  52. package/control_plane/__init__.py +2 -0
  53. package/control_plane/openapi.yaml +228 -0
  54. package/control_plane/server.py +123 -0
  55. package/control_plane/service.py +185 -0
  56. package/dist/enterprise/bundle/.agents/skills/omg/AGENTS.fragment.md +5 -0
  57. package/dist/enterprise/bundle/.agents/skills/omg/algorithms/SKILL.md +11 -0
  58. package/dist/enterprise/bundle/.agents/skills/omg/algorithms/openai.yaml +11 -0
  59. package/dist/enterprise/bundle/.agents/skills/omg/api-twin/SKILL.md +11 -0
  60. package/dist/enterprise/bundle/.agents/skills/omg/api-twin/openai.yaml +12 -0
  61. package/dist/enterprise/bundle/.agents/skills/omg/codex-mcp.toml +4 -0
  62. package/dist/enterprise/bundle/.agents/skills/omg/control-plane/SKILL.md +11 -0
  63. package/dist/enterprise/bundle/.agents/skills/omg/control-plane/openai.yaml +14 -0
  64. package/dist/enterprise/bundle/.agents/skills/omg/data-lineage/SKILL.md +11 -0
  65. package/dist/enterprise/bundle/.agents/skills/omg/data-lineage/openai.yaml +12 -0
  66. package/dist/enterprise/bundle/.agents/skills/omg/delta-classifier/SKILL.md +11 -0
  67. package/dist/enterprise/bundle/.agents/skills/omg/delta-classifier/openai.yaml +12 -0
  68. package/dist/enterprise/bundle/.agents/skills/omg/eval-gate/SKILL.md +11 -0
  69. package/dist/enterprise/bundle/.agents/skills/omg/eval-gate/openai.yaml +12 -0
  70. package/dist/enterprise/bundle/.agents/skills/omg/health/SKILL.md +11 -0
  71. package/dist/enterprise/bundle/.agents/skills/omg/health/openai.yaml +11 -0
  72. package/dist/enterprise/bundle/.agents/skills/omg/hook-governor/SKILL.md +11 -0
  73. package/dist/enterprise/bundle/.agents/skills/omg/hook-governor/openai.yaml +11 -0
  74. package/dist/enterprise/bundle/.agents/skills/omg/incident-replay/SKILL.md +11 -0
  75. package/dist/enterprise/bundle/.agents/skills/omg/incident-replay/openai.yaml +12 -0
  76. package/dist/enterprise/bundle/.agents/skills/omg/lsp-pack/SKILL.md +11 -0
  77. package/dist/enterprise/bundle/.agents/skills/omg/lsp-pack/openai.yaml +11 -0
  78. package/dist/enterprise/bundle/.agents/skills/omg/mcp-fabric/SKILL.md +11 -0
  79. package/dist/enterprise/bundle/.agents/skills/omg/mcp-fabric/openai.yaml +13 -0
  80. package/dist/enterprise/bundle/.agents/skills/omg/preflight/SKILL.md +11 -0
  81. package/dist/enterprise/bundle/.agents/skills/omg/preflight/openai.yaml +12 -0
  82. package/dist/enterprise/bundle/.agents/skills/omg/remote-supervisor/SKILL.md +11 -0
  83. package/dist/enterprise/bundle/.agents/skills/omg/remote-supervisor/openai.yaml +12 -0
  84. package/dist/enterprise/bundle/.agents/skills/omg/robotics/SKILL.md +11 -0
  85. package/dist/enterprise/bundle/.agents/skills/omg/robotics/openai.yaml +11 -0
  86. package/dist/enterprise/bundle/.agents/skills/omg/secure-worktree-pipeline/SKILL.md +11 -0
  87. package/dist/enterprise/bundle/.agents/skills/omg/secure-worktree-pipeline/openai.yaml +12 -0
  88. package/dist/enterprise/bundle/.agents/skills/omg/security-check/SKILL.md +11 -0
  89. package/dist/enterprise/bundle/.agents/skills/omg/security-check/openai.yaml +13 -0
  90. package/dist/enterprise/bundle/.agents/skills/omg/tracebank/SKILL.md +11 -0
  91. package/dist/enterprise/bundle/.agents/skills/omg/tracebank/openai.yaml +12 -0
  92. package/dist/enterprise/bundle/.agents/skills/omg/vision/SKILL.md +11 -0
  93. package/dist/enterprise/bundle/.agents/skills/omg/vision/openai.yaml +11 -0
  94. package/dist/enterprise/bundle/.claude-plugin/marketplace.json +36 -0
  95. package/dist/enterprise/bundle/.claude-plugin/plugin.json +23 -0
  96. package/dist/enterprise/bundle/.mcp.json +40 -0
  97. package/dist/enterprise/bundle/OMG_COMPAT_CONTRACT.md +92 -0
  98. package/dist/enterprise/bundle/registry/bundles/algorithms.yaml +45 -0
  99. package/dist/enterprise/bundle/registry/bundles/api-twin.yaml +48 -0
  100. package/dist/enterprise/bundle/registry/bundles/control-plane.yaml +61 -0
  101. package/dist/enterprise/bundle/registry/bundles/data-lineage.yaml +47 -0
  102. package/dist/enterprise/bundle/registry/bundles/delta-classifier.yaml +47 -0
  103. package/dist/enterprise/bundle/registry/bundles/eval-gate.yaml +47 -0
  104. package/dist/enterprise/bundle/registry/bundles/health.yaml +45 -0
  105. package/dist/enterprise/bundle/registry/bundles/hook-governor.yaml +97 -0
  106. package/dist/enterprise/bundle/registry/bundles/incident-replay.yaml +47 -0
  107. package/dist/enterprise/bundle/registry/bundles/lsp-pack.yaml +48 -0
  108. package/dist/enterprise/bundle/registry/bundles/mcp-fabric.yaml +53 -0
  109. package/dist/enterprise/bundle/registry/bundles/preflight.yaml +48 -0
  110. package/dist/enterprise/bundle/registry/bundles/remote-supervisor.yaml +49 -0
  111. package/dist/enterprise/bundle/registry/bundles/robotics.yaml +45 -0
  112. package/dist/enterprise/bundle/registry/bundles/secure-worktree-pipeline.yaml +54 -0
  113. package/dist/enterprise/bundle/registry/bundles/security-check.yaml +50 -0
  114. package/dist/enterprise/bundle/registry/bundles/tracebank.yaml +47 -0
  115. package/dist/enterprise/bundle/registry/bundles/vision.yaml +45 -0
  116. package/dist/enterprise/bundle/registry/omg-capability.schema.json +80 -0
  117. package/dist/enterprise/bundle/settings.json +381 -0
  118. package/dist/enterprise/manifest.json +255 -0
  119. package/dist/public/bundle/.agents/skills/omg/AGENTS.fragment.md +5 -0
  120. package/dist/public/bundle/.agents/skills/omg/algorithms/SKILL.md +11 -0
  121. package/dist/public/bundle/.agents/skills/omg/algorithms/openai.yaml +11 -0
  122. package/dist/public/bundle/.agents/skills/omg/api-twin/SKILL.md +11 -0
  123. package/dist/public/bundle/.agents/skills/omg/api-twin/openai.yaml +12 -0
  124. package/dist/public/bundle/.agents/skills/omg/codex-mcp.toml +4 -0
  125. package/dist/public/bundle/.agents/skills/omg/control-plane/SKILL.md +11 -0
  126. package/dist/public/bundle/.agents/skills/omg/control-plane/openai.yaml +14 -0
  127. package/dist/public/bundle/.agents/skills/omg/data-lineage/SKILL.md +11 -0
  128. package/dist/public/bundle/.agents/skills/omg/data-lineage/openai.yaml +12 -0
  129. package/dist/public/bundle/.agents/skills/omg/delta-classifier/SKILL.md +11 -0
  130. package/dist/public/bundle/.agents/skills/omg/delta-classifier/openai.yaml +12 -0
  131. package/dist/public/bundle/.agents/skills/omg/eval-gate/SKILL.md +11 -0
  132. package/dist/public/bundle/.agents/skills/omg/eval-gate/openai.yaml +12 -0
  133. package/dist/public/bundle/.agents/skills/omg/health/SKILL.md +11 -0
  134. package/dist/public/bundle/.agents/skills/omg/health/openai.yaml +11 -0
  135. package/dist/public/bundle/.agents/skills/omg/hook-governor/SKILL.md +11 -0
  136. package/dist/public/bundle/.agents/skills/omg/hook-governor/openai.yaml +11 -0
  137. package/dist/public/bundle/.agents/skills/omg/incident-replay/SKILL.md +11 -0
  138. package/dist/public/bundle/.agents/skills/omg/incident-replay/openai.yaml +12 -0
  139. package/dist/public/bundle/.agents/skills/omg/lsp-pack/SKILL.md +11 -0
  140. package/dist/public/bundle/.agents/skills/omg/lsp-pack/openai.yaml +11 -0
  141. package/dist/public/bundle/.agents/skills/omg/mcp-fabric/SKILL.md +11 -0
  142. package/dist/public/bundle/.agents/skills/omg/mcp-fabric/openai.yaml +13 -0
  143. package/dist/public/bundle/.agents/skills/omg/preflight/SKILL.md +11 -0
  144. package/dist/public/bundle/.agents/skills/omg/preflight/openai.yaml +12 -0
  145. package/dist/public/bundle/.agents/skills/omg/remote-supervisor/SKILL.md +11 -0
  146. package/dist/public/bundle/.agents/skills/omg/remote-supervisor/openai.yaml +12 -0
  147. package/dist/public/bundle/.agents/skills/omg/robotics/SKILL.md +11 -0
  148. package/dist/public/bundle/.agents/skills/omg/robotics/openai.yaml +11 -0
  149. package/dist/public/bundle/.agents/skills/omg/secure-worktree-pipeline/SKILL.md +11 -0
  150. package/dist/public/bundle/.agents/skills/omg/secure-worktree-pipeline/openai.yaml +12 -0
  151. package/dist/public/bundle/.agents/skills/omg/security-check/SKILL.md +11 -0
  152. package/dist/public/bundle/.agents/skills/omg/security-check/openai.yaml +13 -0
  153. package/dist/public/bundle/.agents/skills/omg/tracebank/SKILL.md +11 -0
  154. package/dist/public/bundle/.agents/skills/omg/tracebank/openai.yaml +12 -0
  155. package/dist/public/bundle/.agents/skills/omg/vision/SKILL.md +11 -0
  156. package/dist/public/bundle/.agents/skills/omg/vision/openai.yaml +11 -0
  157. package/dist/public/bundle/.claude-plugin/marketplace.json +36 -0
  158. package/dist/public/bundle/.claude-plugin/plugin.json +23 -0
  159. package/dist/public/bundle/.mcp.json +40 -0
  160. package/dist/public/bundle/OMG_COMPAT_CONTRACT.md +92 -0
  161. package/dist/public/bundle/registry/bundles/algorithms.yaml +45 -0
  162. package/dist/public/bundle/registry/bundles/api-twin.yaml +48 -0
  163. package/dist/public/bundle/registry/bundles/control-plane.yaml +61 -0
  164. package/dist/public/bundle/registry/bundles/data-lineage.yaml +47 -0
  165. package/dist/public/bundle/registry/bundles/delta-classifier.yaml +47 -0
  166. package/dist/public/bundle/registry/bundles/eval-gate.yaml +47 -0
  167. package/dist/public/bundle/registry/bundles/health.yaml +45 -0
  168. package/dist/public/bundle/registry/bundles/hook-governor.yaml +97 -0
  169. package/dist/public/bundle/registry/bundles/incident-replay.yaml +47 -0
  170. package/dist/public/bundle/registry/bundles/lsp-pack.yaml +48 -0
  171. package/dist/public/bundle/registry/bundles/mcp-fabric.yaml +53 -0
  172. package/dist/public/bundle/registry/bundles/preflight.yaml +48 -0
  173. package/dist/public/bundle/registry/bundles/remote-supervisor.yaml +49 -0
  174. package/dist/public/bundle/registry/bundles/robotics.yaml +45 -0
  175. package/dist/public/bundle/registry/bundles/secure-worktree-pipeline.yaml +54 -0
  176. package/dist/public/bundle/registry/bundles/security-check.yaml +50 -0
  177. package/dist/public/bundle/registry/bundles/tracebank.yaml +47 -0
  178. package/dist/public/bundle/registry/bundles/vision.yaml +45 -0
  179. package/dist/public/bundle/registry/omg-capability.schema.json +80 -0
  180. package/dist/public/bundle/settings.json +379 -0
  181. package/dist/public/manifest.json +255 -0
  182. package/docs/assets/omg-hud.svg +32 -0
  183. package/docs/install/claude-code.md +31 -0
  184. package/docs/install/codex.md +29 -0
  185. package/docs/migration/native-adoption.md +57 -0
  186. package/docs/proof.md +55 -0
  187. package/docs/release-checklist.md +38 -0
  188. package/docs/transcripts/crazy.md +17 -0
  189. package/docs/transcripts/setup.md +25 -0
  190. package/hooks/policy_engine.py +38 -7
  191. package/hooks/post-write.py +1 -1
  192. package/hooks/prompt-enhancer.py +1 -1
  193. package/hooks/security_validators.py +75 -0
  194. package/hooks/setup_wizard.py +43 -8
  195. package/hooks/shadow_manager.py +28 -2
  196. package/package.json +1 -1
  197. package/plugins/README.md +3 -1
  198. package/plugins/__init__.py +1 -0
  199. package/plugins/advanced/commands/OMG:deep-plan.md +1 -1
  200. package/plugins/advanced/commands/OMG:security-review.md +10 -113
  201. package/plugins/advanced/commands/OMG:ship.md +1 -1
  202. package/plugins/advanced/plugin.json +1 -10
  203. package/plugins/core/plugin.json +25 -2
  204. package/pyproject.toml +38 -2
  205. package/registry/__init__.py +1 -0
  206. package/registry/bundles/algorithms.yaml +45 -0
  207. package/registry/bundles/api-twin.yaml +48 -0
  208. package/registry/bundles/control-plane.yaml +61 -0
  209. package/registry/bundles/data-lineage.yaml +47 -0
  210. package/registry/bundles/delta-classifier.yaml +47 -0
  211. package/registry/bundles/eval-gate.yaml +47 -0
  212. package/registry/bundles/health.yaml +45 -0
  213. package/registry/bundles/hook-governor.yaml +97 -0
  214. package/registry/bundles/incident-replay.yaml +47 -0
  215. package/registry/bundles/lsp-pack.yaml +48 -0
  216. package/registry/bundles/mcp-fabric.yaml +53 -0
  217. package/registry/bundles/preflight.yaml +48 -0
  218. package/registry/bundles/remote-supervisor.yaml +49 -0
  219. package/registry/bundles/robotics.yaml +45 -0
  220. package/registry/bundles/secure-worktree-pipeline.yaml +54 -0
  221. package/registry/bundles/security-check.yaml +50 -0
  222. package/registry/bundles/tracebank.yaml +47 -0
  223. package/registry/bundles/vision.yaml +45 -0
  224. package/registry/omg-capability.schema.json +80 -0
  225. package/registry/verify_artifact.py +90 -0
  226. package/runtime/adapters/claude.py +3 -0
  227. package/runtime/adapters/gpt.py +3 -0
  228. package/runtime/adapters/local.py +3 -0
  229. package/runtime/adoption.py +1 -1
  230. package/runtime/api_twin.py +179 -0
  231. package/runtime/asset_loader.py +62 -0
  232. package/runtime/compat.py +24 -3
  233. package/runtime/contract_compiler.py +847 -0
  234. package/runtime/data_lineage.py +73 -0
  235. package/runtime/delta_classifier.py +81 -0
  236. package/runtime/domain_packs.py +46 -0
  237. package/runtime/ecosystem.py +1 -1
  238. package/runtime/eval_gate.py +50 -0
  239. package/runtime/guide_assert.py +45 -0
  240. package/runtime/incident_replay.py +47 -0
  241. package/runtime/mcp_config_writers.py +147 -30
  242. package/runtime/mcp_memory_server.py +1 -1
  243. package/runtime/omg_compat_contract_snapshot.json +9 -8
  244. package/runtime/omg_contract_snapshot.json +9 -8
  245. package/runtime/omg_mcp_server.py +207 -0
  246. package/runtime/preflight.py +73 -0
  247. package/runtime/providers/codex_provider.py +2 -12
  248. package/runtime/providers/gemini_provider.py +2 -21
  249. package/runtime/providers/kimi_provider.py +2 -21
  250. package/runtime/remote_supervisor.py +64 -0
  251. package/runtime/runtime_profile.py +61 -0
  252. package/runtime/security_check.py +464 -0
  253. package/runtime/subagent_dispatcher.py +117 -10
  254. package/runtime/team_router.py +3 -1
  255. package/runtime/tracebank.py +53 -0
  256. package/runtime/untrusted_content.py +102 -0
  257. package/scripts/omg.py +360 -2
  258. package/settings.json +81 -18
  259. package/tools/python_repl.py +33 -3
@@ -0,0 +1,847 @@
1
+ """Canonical OMG contract registry, compiler, and release-readiness checks."""
2
+ from __future__ import annotations
3
+
4
+ import hashlib
5
+ import asyncio
6
+ import json
7
+ import os
8
+ from pathlib import Path
9
+ import shutil
10
+ import subprocess
11
+ import sys
12
+ import tempfile
13
+ from typing import Any, Iterable
14
+ import zipfile
15
+
16
+ import yaml
17
+
18
+ from runtime.asset_loader import resolve_asset, resolve_assets
19
+ from runtime.adoption import (
20
+ CANONICAL_MARKETPLACE_ID,
21
+ CANONICAL_PACKAGE_NAME,
22
+ CANONICAL_PLUGIN_ID,
23
+ CANONICAL_REPO_URL,
24
+ CANONICAL_VERSION,
25
+ )
26
+
27
+
28
+ CONTRACT_DOC_PATH = Path("OMG_COMPAT_CONTRACT.md")
29
+ SCHEMA_PATH = Path("registry") / "omg-capability.schema.json"
30
+ BUNDLES_DIR = Path("registry") / "bundles"
31
+ SUPPORTED_HOSTS = ("claude", "codex")
32
+ SUPPORTED_CHANNELS = ("public", "enterprise")
33
+ DEFAULT_REQUIRED_BUNDLES = (
34
+ "control-plane",
35
+ "hook-governor",
36
+ "mcp-fabric",
37
+ "lsp-pack",
38
+ "secure-worktree-pipeline",
39
+ "security-check",
40
+ "api-twin",
41
+ "preflight",
42
+ "robotics",
43
+ "vision",
44
+ "algorithms",
45
+ "health",
46
+ "tracebank",
47
+ "eval-gate",
48
+ "delta-classifier",
49
+ "incident-replay",
50
+ "data-lineage",
51
+ "remote-supervisor",
52
+ )
53
+ REQUIRED_DOC_TOKENS = (
54
+ "execution_contract",
55
+ "tool_policy",
56
+ "invocation_policy",
57
+ "host_compilation_rules",
58
+ "local_supervisor",
59
+ )
60
+ REQUIRED_BUNDLE_FIELDS = (
61
+ "id",
62
+ "kind",
63
+ "version",
64
+ "title",
65
+ "description",
66
+ "hosts",
67
+ "assets",
68
+ "invocation_policy",
69
+ "tool_policy",
70
+ "lifecycle_hooks",
71
+ "mcp_contract",
72
+ "lsp_contract",
73
+ "evidence_outputs",
74
+ "execution_contract",
75
+ "channel_overrides",
76
+ )
77
+
78
+
79
+ def _resolve_root(root_dir: str | Path | None) -> Path:
80
+ if root_dir is None:
81
+ return Path(__file__).resolve().parents[1]
82
+ return Path(root_dir).resolve()
83
+
84
+
85
+ def _resolve_output_root(root_dir: Path, output_root: str | Path | None) -> Path:
86
+ if output_root is None or str(output_root).strip() == "":
87
+ return root_dir
88
+ return Path(output_root).resolve()
89
+
90
+
91
+ def _load_json(path: Path) -> dict[str, Any]:
92
+ parsed = json.loads(path.read_text(encoding="utf-8"))
93
+ if not isinstance(parsed, dict):
94
+ raise ValueError(f"Expected JSON object in {path}")
95
+ return parsed
96
+
97
+
98
+ def _write_json(path: Path, payload: dict[str, Any]) -> None:
99
+ path.parent.mkdir(parents=True, exist_ok=True)
100
+ path.write_text(json.dumps(payload, indent=2, ensure_ascii=True) + "\n", encoding="utf-8")
101
+
102
+
103
+ def _write_text(path: Path, content: str) -> None:
104
+ path.parent.mkdir(parents=True, exist_ok=True)
105
+ path.write_text(content, encoding="utf-8")
106
+
107
+
108
+ def _sha256_file(path: Path) -> str:
109
+ digest = hashlib.sha256()
110
+ with path.open("rb") as handle:
111
+ for chunk in iter(lambda: handle.read(65536), b""):
112
+ digest.update(chunk)
113
+ return digest.hexdigest()
114
+
115
+
116
+ def load_contract_doc(root_dir: str | Path | None = None) -> str:
117
+ if root_dir is not None:
118
+ root = _resolve_root(root_dir)
119
+ candidate = root / CONTRACT_DOC_PATH
120
+ if candidate.exists():
121
+ return candidate.read_text(encoding="utf-8")
122
+ return resolve_asset(CONTRACT_DOC_PATH).read_text(encoding="utf-8")
123
+
124
+
125
+ def load_contract_schema(root_dir: str | Path | None = None) -> dict[str, Any]:
126
+ if root_dir is not None:
127
+ root = _resolve_root(root_dir)
128
+ candidate = root / SCHEMA_PATH
129
+ if candidate.exists():
130
+ return _load_json(candidate)
131
+ return _load_json(resolve_asset(SCHEMA_PATH))
132
+
133
+
134
+ def load_contract_bundles(root_dir: str | Path | None = None) -> list[dict[str, Any]]:
135
+ root = _resolve_root(root_dir)
136
+ bundles: list[dict[str, Any]] = []
137
+ paths = sorted((root / BUNDLES_DIR).glob("*.yaml")) if (root / BUNDLES_DIR).exists() else resolve_assets(BUNDLES_DIR, suffix=".yaml")
138
+ for path in paths:
139
+ parsed = yaml.safe_load(path.read_text(encoding="utf-8"))
140
+ if not isinstance(parsed, dict):
141
+ raise ValueError(f"Expected mapping bundle manifest in {path}")
142
+ bundle = dict(parsed)
143
+ try:
144
+ bundle["_path"] = str(path.relative_to(root))
145
+ except ValueError:
146
+ bundle["_path"] = str(Path(BUNDLES_DIR) / path.name)
147
+ bundles.append(bundle)
148
+ return bundles
149
+
150
+
151
+ def _bundle_summary(bundle: dict[str, Any]) -> dict[str, Any]:
152
+ return {
153
+ "id": bundle.get("id", ""),
154
+ "kind": bundle.get("kind", ""),
155
+ "version": bundle.get("version", ""),
156
+ "title": bundle.get("title", ""),
157
+ "hosts": list(bundle.get("hosts", [])),
158
+ "path": bundle.get("_path", ""),
159
+ }
160
+
161
+
162
+ def validate_contract_registry(root_dir: str | Path | None = None) -> dict[str, Any]:
163
+ root = _resolve_root(root_dir)
164
+ errors: list[str] = []
165
+
166
+ try:
167
+ doc_text = load_contract_doc(root)
168
+ except FileNotFoundError:
169
+ errors.append(f"missing contract doc: {CONTRACT_DOC_PATH}")
170
+ doc_text = ""
171
+ else:
172
+ for token in REQUIRED_DOC_TOKENS:
173
+ if token not in doc_text:
174
+ errors.append(f"contract doc missing token: {token}")
175
+ if CANONICAL_VERSION not in doc_text:
176
+ errors.append(f"contract doc missing version: {CANONICAL_VERSION}")
177
+
178
+ try:
179
+ schema_payload = load_contract_schema(root)
180
+ except FileNotFoundError:
181
+ errors.append(f"missing contract schema: {SCHEMA_PATH}")
182
+ schema_payload: dict[str, Any] = {}
183
+ else:
184
+ if str(schema_payload.get("version", "")) != CANONICAL_VERSION:
185
+ errors.append(f"contract schema version drift: {schema_payload.get('version')!r}")
186
+
187
+ bundles = load_contract_bundles(root)
188
+ if not bundles:
189
+ errors.append(f"missing bundles directory: {BUNDLES_DIR}")
190
+
191
+ bundle_ids = set()
192
+ bundle_summaries: list[dict[str, Any]] = []
193
+ for bundle in bundles:
194
+ bundle_summaries.append(_bundle_summary(bundle))
195
+ bundle_id = str(bundle.get("id", "")).strip()
196
+ if not bundle_id:
197
+ errors.append(f"bundle missing id: {bundle.get('_path', '<unknown>')}")
198
+ continue
199
+ if bundle_id in bundle_ids:
200
+ errors.append(f"duplicate bundle id: {bundle_id}")
201
+ bundle_ids.add(bundle_id)
202
+ for field in REQUIRED_BUNDLE_FIELDS:
203
+ if field not in bundle:
204
+ errors.append(f"{bundle_id}: missing field {field}")
205
+ if bundle.get("version") != CANONICAL_VERSION:
206
+ errors.append(f"{bundle_id}: version drift {bundle.get('version')!r}")
207
+ hosts = bundle.get("hosts", [])
208
+ if not isinstance(hosts, list) or not hosts:
209
+ errors.append(f"{bundle_id}: hosts must be a non-empty list")
210
+ else:
211
+ bad_hosts = [host for host in hosts if host not in SUPPORTED_HOSTS]
212
+ if bad_hosts:
213
+ errors.append(f"{bundle_id}: unsupported hosts {bad_hosts}")
214
+
215
+ missing_bundles = [bundle_id for bundle_id in DEFAULT_REQUIRED_BUNDLES if bundle_id not in bundle_ids]
216
+ for bundle_id in missing_bundles:
217
+ errors.append(f"missing required bundle: {bundle_id}")
218
+
219
+ contract = {
220
+ "path": str(CONTRACT_DOC_PATH),
221
+ "schema_path": str(SCHEMA_PATH),
222
+ "version": CANONICAL_VERSION,
223
+ "bundle_count": len(bundle_summaries),
224
+ }
225
+ return {
226
+ "schema": "OmgContractValidationResult",
227
+ "status": "ok" if not errors else "error",
228
+ "contract": contract,
229
+ "bundles": bundle_summaries,
230
+ "errors": errors,
231
+ }
232
+
233
+
234
+ def _copy_contract_inputs(root: Path, output_root: Path) -> list[Path]:
235
+ copied: list[Path] = []
236
+ for rel_path in [CONTRACT_DOC_PATH, SCHEMA_PATH]:
237
+ src = resolve_asset(rel_path)
238
+ dst = output_root / rel_path
239
+ _write_text(dst, src.read_text(encoding="utf-8"))
240
+ copied.append(dst)
241
+ for bundle in load_contract_bundles(root):
242
+ rel_path = Path(str(bundle["_path"]))
243
+ src = resolve_asset(rel_path)
244
+ dst = output_root / rel_path
245
+ _write_text(dst, src.read_text(encoding="utf-8"))
246
+ copied.append(dst)
247
+ return copied
248
+
249
+
250
+ def _base_mcp_servers() -> dict[str, Any]:
251
+ return {
252
+ "context7": {
253
+ "command": "npx",
254
+ "args": ["@upstash/context7-mcp@2.1.3"],
255
+ },
256
+ "filesystem": {
257
+ "command": "npx",
258
+ "args": ["@modelcontextprotocol/server-filesystem@2026.1.14", "."],
259
+ },
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
+ "omg-control": {
273
+ "command": "python3",
274
+ "args": ["-m", "runtime.omg_mcp_server"],
275
+ },
276
+ }
277
+
278
+
279
+ def _build_claude_plugin() -> dict[str, Any]:
280
+ return {
281
+ "name": CANONICAL_PLUGIN_ID,
282
+ "version": CANONICAL_VERSION,
283
+ "description": "OMG plugin layer for Claude Code with native setup, orchestration, and interop.",
284
+ "author": {"name": "trac3er00"},
285
+ "repository": CANONICAL_REPO_URL,
286
+ "homepage": CANONICAL_REPO_URL,
287
+ "license": "MIT",
288
+ "keywords": [
289
+ "claude-code",
290
+ "plugin",
291
+ "orchestration",
292
+ "multi-agent",
293
+ "omg",
294
+ "codex",
295
+ "gemini",
296
+ "crazy-mode",
297
+ "escalation",
298
+ ],
299
+ "mcpServers": "./.mcp.json",
300
+ }
301
+
302
+
303
+ def _build_claude_marketplace() -> dict[str, Any]:
304
+ return {
305
+ "name": CANONICAL_MARKETPLACE_ID,
306
+ "description": "Marketplace metadata for the OMG Claude plugin",
307
+ "owner": {"name": "trac3er00"},
308
+ "metadata": {
309
+ "description": "OMG - Oh-My-God for Claude Code",
310
+ "version": CANONICAL_VERSION,
311
+ "homepage": CANONICAL_REPO_URL,
312
+ "repository": CANONICAL_REPO_URL,
313
+ },
314
+ "plugins": [
315
+ {
316
+ "name": CANONICAL_PLUGIN_ID,
317
+ "description": "OMG plugin layer for Claude Code with native setup, orchestration, and interop.",
318
+ "version": CANONICAL_VERSION,
319
+ "source": "./",
320
+ "author": {"name": "trac3er00"},
321
+ "license": "MIT",
322
+ "category": "productivity",
323
+ "tags": [
324
+ "orchestration",
325
+ "automation",
326
+ "multi-agent",
327
+ "omg",
328
+ "codex",
329
+ "gemini",
330
+ "crazy-mode",
331
+ ],
332
+ }
333
+ ],
334
+ "version": CANONICAL_VERSION,
335
+ }
336
+
337
+
338
+ def _bundle_map(bundles: Iterable[dict[str, Any]]) -> dict[str, dict[str, Any]]:
339
+ return {str(bundle["id"]): bundle for bundle in bundles}
340
+
341
+
342
+ def _compile_hook_settings(bundle: dict[str, Any]) -> dict[str, Any]:
343
+ events = bundle.get("compiled_hooks", {})
344
+ if not isinstance(events, dict):
345
+ return {}
346
+
347
+ compiled: dict[str, Any] = {}
348
+ for event_name, items in events.items():
349
+ if not isinstance(items, list):
350
+ continue
351
+ compiled_entries: list[dict[str, Any]] = []
352
+ for item in items:
353
+ if not isinstance(item, dict):
354
+ continue
355
+ command = str(item.get("command", "")).strip()
356
+ if not command:
357
+ continue
358
+ hook_payload: dict[str, Any] = {"type": "command", "command": command}
359
+ timeout = item.get("timeout")
360
+ if isinstance(timeout, int):
361
+ hook_payload["timeout"] = timeout
362
+ entry: dict[str, Any] = {"hooks": [hook_payload]}
363
+ if "matcher" in item:
364
+ entry["matcher"] = str(item.get("matcher", ""))
365
+ compiled_entries.append(entry)
366
+ if compiled_entries:
367
+ compiled[str(event_name)] = compiled_entries
368
+ return compiled
369
+
370
+
371
+ def _protected_paths_for_channel(channel: str) -> list[str]:
372
+ paths = [".omg/**", ".agents/**", ".codex/**", ".claude/**"]
373
+ if channel == "enterprise":
374
+ paths.extend(["registry/**", "dist/**"])
375
+ return paths
376
+
377
+
378
+ def _compile_claude_outputs(
379
+ *,
380
+ root: Path,
381
+ output_root: Path,
382
+ bundles: list[dict[str, Any]],
383
+ channel: str,
384
+ ) -> list[Path]:
385
+ artifacts: list[Path] = []
386
+
387
+ _write_json(output_root / ".claude-plugin" / "plugin.json", _build_claude_plugin())
388
+ artifacts.append(output_root / ".claude-plugin" / "plugin.json")
389
+
390
+ _write_json(output_root / ".claude-plugin" / "marketplace.json", _build_claude_marketplace())
391
+ artifacts.append(output_root / ".claude-plugin" / "marketplace.json")
392
+
393
+ mcp_payload = {"mcpServers": _base_mcp_servers()}
394
+ _write_json(output_root / ".mcp.json", mcp_payload)
395
+ artifacts.append(output_root / ".mcp.json")
396
+
397
+ settings_path = root / "settings.json"
398
+ if not settings_path.exists():
399
+ settings_path = resolve_asset("settings.json")
400
+ settings = _load_json(settings_path)
401
+ hook_bundle = _bundle_map(bundles)["hook-governor"]
402
+ settings["hooks"] = _compile_hook_settings(hook_bundle)
403
+ omg_settings = dict(settings.get("_omg", {}))
404
+ omg_settings["_version"] = CANONICAL_VERSION
405
+ omg_settings["generated"] = {
406
+ "contract_version": CANONICAL_VERSION,
407
+ "channel": channel,
408
+ "required_bundles": list(DEFAULT_REQUIRED_BUNDLES),
409
+ "protected_paths": _protected_paths_for_channel(channel),
410
+ "emulated_events": list(hook_bundle.get("lifecycle_hooks", {}).get("emulated", [])),
411
+ }
412
+ settings["_omg"] = omg_settings
413
+ _write_json(output_root / "settings.json", settings)
414
+ artifacts.append(output_root / "settings.json")
415
+
416
+ return artifacts
417
+
418
+
419
+ def _yaml_string(value: str) -> str:
420
+ return json.dumps(value, ensure_ascii=True)
421
+
422
+
423
+ def _render_codex_skill(bundle: dict[str, Any], channel: str) -> str:
424
+ execution_modes = ", ".join(str(mode) for mode in bundle.get("execution_contract", {}).get("modes", []))
425
+ mcp_servers = ", ".join(str(name) for name in bundle.get("mcp_contract", {}).get("servers", []))
426
+ return (
427
+ f"---\n"
428
+ f"name: omg-{bundle['id']}\n"
429
+ f"description: {_yaml_string(str(bundle['description']))}\n"
430
+ f"---\n\n"
431
+ f"# {bundle['title']}\n\n"
432
+ f"- Channel: `{channel}`\n"
433
+ f"- Execution modes: `{execution_modes}`\n"
434
+ f"- MCP servers: `{mcp_servers}`\n"
435
+ f"- Evidence outputs: `{', '.join(bundle.get('evidence_outputs', {}).get('artifacts', []))}`\n"
436
+ )
437
+
438
+
439
+ def _render_openai_yaml(bundle: dict[str, Any], channel: str) -> str:
440
+ invocation = bundle.get("invocation_policy", {})
441
+ servers = bundle.get("mcp_contract", {}).get("servers", [])
442
+ tools = bundle.get("tool_policy", {}).get("allowed_tools", {}).get("codex", [])
443
+ lines = [
444
+ f"name: omg-{bundle['id']}",
445
+ f"description: {_yaml_string(str(bundle['description']))}",
446
+ f"allow_implicit_invocation: {'true' if invocation.get('allow_implicit_invocation') else 'false'}",
447
+ "metadata:",
448
+ f" channel: {channel}",
449
+ f" bundle_id: {bundle['id']}",
450
+ f" title: {_yaml_string(str(bundle['title']))}",
451
+ "mcp_servers:",
452
+ ]
453
+ for server in servers:
454
+ lines.append(f" - {server}")
455
+ lines.append("allowed_tools:")
456
+ for tool in tools:
457
+ lines.append(f" - {_yaml_string(str(tool))}")
458
+ return "\n".join(lines) + "\n"
459
+
460
+
461
+ def _compile_codex_outputs(
462
+ *,
463
+ output_root: Path,
464
+ bundles: list[dict[str, Any]],
465
+ channel: str,
466
+ ) -> list[Path]:
467
+ artifacts: list[Path] = []
468
+ shared_dir = output_root / ".agents" / "skills" / "omg"
469
+ shared_dir.mkdir(parents=True, exist_ok=True)
470
+
471
+ rules_fragment = (
472
+ "# OMG Codex Protection Rules\n\n"
473
+ f"- Channel: `{channel}`\n"
474
+ "- Protect `.omg/`, `.agents/`, `.codex/`, and `.claude/` from unreviewed mutation.\n"
475
+ "- Require explicit invocation for production-control-plane skills.\n"
476
+ )
477
+ _write_text(shared_dir / "AGENTS.fragment.md", rules_fragment)
478
+ artifacts.append(shared_dir / "AGENTS.fragment.md")
479
+
480
+ from runtime.mcp_config_writers import write_codex_mcp_stdio_config
481
+
482
+ codex_mcp_path = shared_dir / "codex-mcp.toml"
483
+ write_codex_mcp_stdio_config(
484
+ command="python3",
485
+ args=["-m", "runtime.omg_mcp_server"],
486
+ server_name="omg-control",
487
+ config_path=codex_mcp_path,
488
+ )
489
+ artifacts.append(codex_mcp_path)
490
+
491
+ for bundle in bundles:
492
+ if "codex" not in bundle.get("hosts", []):
493
+ continue
494
+ skill_dir = shared_dir / str(bundle["id"])
495
+ _write_text(skill_dir / "SKILL.md", _render_codex_skill(bundle, channel))
496
+ _write_text(skill_dir / "openai.yaml", _render_openai_yaml(bundle, channel))
497
+ artifacts.extend([skill_dir / "SKILL.md", skill_dir / "openai.yaml"])
498
+
499
+ return artifacts
500
+
501
+
502
+ def _copy_release_bundle(
503
+ *,
504
+ output_root: Path,
505
+ channel: str,
506
+ artifacts: list[Path],
507
+ ) -> list[Path]:
508
+ bundle_root = output_root / "dist" / channel / "bundle"
509
+ if bundle_root.exists():
510
+ shutil.rmtree(bundle_root)
511
+ copied: list[Path] = []
512
+ for path in sorted(set(artifacts)):
513
+ rel_path = path.relative_to(output_root)
514
+ dst = bundle_root / rel_path
515
+ dst.parent.mkdir(parents=True, exist_ok=True)
516
+ shutil.copy2(path, dst)
517
+ copied.append(dst)
518
+ return copied
519
+
520
+
521
+ def _build_dist_manifest(output_root: Path, *, channel: str, artifacts: list[Path]) -> Path:
522
+ dist_root = output_root / "dist" / channel
523
+ payload = {
524
+ "schema": "OmgCompiledArtifactManifest",
525
+ "channel": channel,
526
+ "contract_version": CANONICAL_VERSION,
527
+ "artifacts": [
528
+ {
529
+ "path": str(path.relative_to(dist_root)),
530
+ "sha256": _sha256_file(path),
531
+ }
532
+ for path in sorted(set(artifacts))
533
+ ],
534
+ }
535
+ out_path = dist_root / "manifest.json"
536
+ _write_json(out_path, payload)
537
+ return out_path
538
+
539
+
540
+ def compile_contract_outputs(
541
+ *,
542
+ root_dir: str | Path | None = None,
543
+ output_root: str | Path | None = None,
544
+ hosts: list[str] | tuple[str, ...] | None = None,
545
+ channel: str = "public",
546
+ ) -> dict[str, Any]:
547
+ root = _resolve_root(root_dir)
548
+ output = _resolve_output_root(root, output_root)
549
+ validation = validate_contract_registry(root)
550
+ if validation["status"] != "ok":
551
+ return {
552
+ "schema": "OmgContractCompileResult",
553
+ "status": "error",
554
+ "channel": channel,
555
+ "hosts": list(hosts or SUPPORTED_HOSTS),
556
+ "errors": validation["errors"],
557
+ "artifacts": [],
558
+ }
559
+
560
+ if channel not in SUPPORTED_CHANNELS:
561
+ return {
562
+ "schema": "OmgContractCompileResult",
563
+ "status": "error",
564
+ "channel": channel,
565
+ "hosts": list(hosts or SUPPORTED_HOSTS),
566
+ "errors": [f"unsupported channel: {channel}"],
567
+ "artifacts": [],
568
+ }
569
+
570
+ selected_hosts = list(hosts or SUPPORTED_HOSTS)
571
+ bad_hosts = [host for host in selected_hosts if host not in SUPPORTED_HOSTS]
572
+ if bad_hosts:
573
+ return {
574
+ "schema": "OmgContractCompileResult",
575
+ "status": "error",
576
+ "channel": channel,
577
+ "hosts": selected_hosts,
578
+ "errors": [f"unsupported hosts: {bad_hosts}"],
579
+ "artifacts": [],
580
+ }
581
+
582
+ bundles = load_contract_bundles(root)
583
+ artifacts = _copy_contract_inputs(root, output)
584
+
585
+ if "claude" in selected_hosts:
586
+ artifacts.extend(_compile_claude_outputs(root=root, output_root=output, bundles=bundles, channel=channel))
587
+ if "codex" in selected_hosts:
588
+ artifacts.extend(_compile_codex_outputs(output_root=output, bundles=bundles, channel=channel))
589
+
590
+ bundled_artifacts = _copy_release_bundle(output_root=output, channel=channel, artifacts=artifacts)
591
+ manifest_path = _build_dist_manifest(output, channel=channel, artifacts=bundled_artifacts)
592
+ artifacts.append(manifest_path)
593
+
594
+ return {
595
+ "schema": "OmgContractCompileResult",
596
+ "status": "ok",
597
+ "channel": channel,
598
+ "hosts": selected_hosts,
599
+ "artifacts": [str(path.relative_to(output)) for path in artifacts],
600
+ "manifest": str(manifest_path.relative_to(output)),
601
+ }
602
+
603
+
604
+ def _provider_statuses() -> dict[str, dict[str, Any]]:
605
+ ready_override = {
606
+ item.strip()
607
+ for item in os.environ.get("OMG_RELEASE_READY_PROVIDERS", "").split(",")
608
+ if item.strip()
609
+ }
610
+ statuses: dict[str, dict[str, Any]] = {}
611
+
612
+ for provider_name in ("claude", "codex"):
613
+ if provider_name in ready_override:
614
+ statuses[provider_name] = {"ready": True, "source": "env"}
615
+ continue
616
+
617
+ if provider_name == "claude":
618
+ claude_bin = os.environ.get("OMG_CLAUDE_BIN", "claude")
619
+ cmd = os.environ.get("OMG_CLAUDE_WORKER_CMD", "").strip()
620
+ ready = bool(cmd) or shutil.which(claude_bin) is not None
621
+ statuses[provider_name] = {
622
+ "ready": ready,
623
+ "source": "env-cmd" if cmd else "path",
624
+ "detail": cmd or claude_bin,
625
+ }
626
+ continue
627
+
628
+ import runtime.providers.codex_provider # noqa: F401
629
+ from runtime.cli_provider import get_provider
630
+
631
+ provider = get_provider("codex")
632
+ ready = bool(provider and provider.detect())
633
+ statuses[provider_name] = {"ready": ready, "source": "provider"}
634
+
635
+ return statuses
636
+
637
+
638
+ def _check_mcp_fabric() -> dict[str, Any]:
639
+ import runtime.omg_mcp_server as omg_mcp_server
640
+
641
+ prompts = asyncio.run(omg_mcp_server.mcp.list_prompts())
642
+ resources = asyncio.run(omg_mcp_server.mcp.list_resources())
643
+ instructions = getattr(omg_mcp_server.mcp, "instructions", "")
644
+ return {
645
+ "ready": isinstance(instructions, str) and bool(instructions.strip()) and len(prompts) >= 1 and len(resources) >= 1,
646
+ "prompt_count": len(prompts),
647
+ "resource_count": len(resources),
648
+ }
649
+
650
+
651
+ def build_release_readiness(
652
+ *,
653
+ root_dir: str | Path | None = None,
654
+ output_root: str | Path | None = None,
655
+ channel: str = "dual",
656
+ ) -> dict[str, Any]:
657
+ root = _resolve_root(root_dir)
658
+ output = _resolve_output_root(root, output_root)
659
+ blockers: list[str] = []
660
+ checks: dict[str, Any] = {}
661
+
662
+ validation = validate_contract_registry(root)
663
+ checks["contract_validation"] = validation
664
+ if validation["status"] != "ok":
665
+ blockers.extend(validation["errors"])
666
+
667
+ required_channels = ["public", "enterprise"] if channel == "dual" else [channel]
668
+ for required_channel in required_channels:
669
+ dist_root = output / "dist" / required_channel
670
+ manifest_path = dist_root / "manifest.json"
671
+ if not manifest_path.exists():
672
+ blockers.append(f"missing compiled manifest: dist/{required_channel}/manifest.json")
673
+ continue
674
+ manifest = _load_json(manifest_path)
675
+ manifest_errors: list[str] = []
676
+ for artifact in manifest.get("artifacts", []):
677
+ if not isinstance(artifact, dict):
678
+ continue
679
+ rel_path = str(artifact.get("path", ""))
680
+ expected_sha = str(artifact.get("sha256", ""))
681
+ artifact_path = dist_root / rel_path
682
+ if not artifact_path.exists():
683
+ manifest_errors.append(f"{required_channel}: missing bundled artifact {rel_path}")
684
+ continue
685
+ if _sha256_file(artifact_path) != expected_sha:
686
+ manifest_errors.append(f"{required_channel}: sha mismatch for {rel_path}")
687
+ if manifest_errors:
688
+ blockers.extend(manifest_errors)
689
+ manifest["integrity_errors"] = manifest_errors
690
+ checks[f"dist_{required_channel}"] = manifest
691
+
692
+ required_outputs = [
693
+ output / ".claude-plugin" / "plugin.json",
694
+ output / ".claude-plugin" / "marketplace.json",
695
+ output / ".mcp.json",
696
+ output / "settings.json",
697
+ output / ".agents" / "skills" / "omg" / "control-plane" / "SKILL.md",
698
+ output / ".agents" / "skills" / "omg" / "control-plane" / "openai.yaml",
699
+ ]
700
+ missing_outputs = [str(path.relative_to(output)) for path in required_outputs if not path.exists()]
701
+ if missing_outputs:
702
+ blockers.append(f"missing compiled outputs: {', '.join(missing_outputs)}")
703
+ checks["compiled_outputs"] = {"missing": missing_outputs}
704
+
705
+ required_bundle_outputs: list[Path] = []
706
+ for bundle_id in DEFAULT_REQUIRED_BUNDLES:
707
+ required_bundle_outputs.extend(
708
+ [
709
+ output / ".agents" / "skills" / "omg" / bundle_id / "SKILL.md",
710
+ output / ".agents" / "skills" / "omg" / bundle_id / "openai.yaml",
711
+ ]
712
+ )
713
+ missing_bundle_outputs = [str(path.relative_to(output)) for path in required_bundle_outputs if not path.exists()]
714
+ if missing_bundle_outputs:
715
+ blockers.append(f"missing bundle outputs: {', '.join(missing_bundle_outputs)}")
716
+ checks["bundle_outputs"] = {"missing": missing_bundle_outputs}
717
+
718
+ evidence_check = _check_recent_evidence(output)
719
+ checks["evidence"] = evidence_check
720
+ blockers.extend(evidence_check.get("blockers", []))
721
+
722
+ eval_check = _check_eval_gate(output)
723
+ checks["eval_gate"] = eval_check
724
+ blockers.extend(eval_check.get("blockers", []))
725
+
726
+ package_check = _check_packaged_install_smoke(root)
727
+ checks["package_smoke"] = package_check
728
+ blockers.extend(package_check.get("blockers", []))
729
+
730
+ providers = _provider_statuses()
731
+ checks["providers"] = providers
732
+ for provider_name, status in providers.items():
733
+ if not status.get("ready"):
734
+ blockers.append(f"provider not ready: {provider_name}")
735
+
736
+ worktree_ready = shutil.which("git") is not None and (root / ".git").exists()
737
+ checks["worktree"] = {"ready": worktree_ready}
738
+ if not worktree_ready:
739
+ blockers.append("git worktree support not available")
740
+
741
+ mcp_status = _check_mcp_fabric()
742
+ checks["mcp_fabric"] = mcp_status
743
+ if not mcp_status.get("ready"):
744
+ blockers.append("mcp fabric incomplete")
745
+
746
+ return {
747
+ "schema": "OmgReleaseReadinessResult",
748
+ "status": "ok" if not blockers else "error",
749
+ "channel": channel,
750
+ "blockers": blockers,
751
+ "checks": checks,
752
+ }
753
+
754
+
755
+ def _check_recent_evidence(output_root: Path) -> dict[str, Any]:
756
+ evidence_dir = output_root / ".omg" / "evidence"
757
+ if not evidence_dir.exists():
758
+ return {"status": "missing", "blockers": []}
759
+
760
+ evidence_files = sorted(path for path in evidence_dir.glob("*.json") if path.is_file())
761
+ if not evidence_files:
762
+ return {"status": "missing", "blockers": []}
763
+
764
+ evidence_payloads: list[tuple[Path, dict[str, Any]]] = []
765
+ for path in evidence_files:
766
+ try:
767
+ payload = _load_json(path)
768
+ except Exception:
769
+ continue
770
+ if payload.get("schema") == "EvidencePack":
771
+ evidence_payloads.append((path, payload))
772
+
773
+ if not evidence_payloads:
774
+ return {"status": "missing", "blockers": []}
775
+
776
+ evidence_path, payload = evidence_payloads[-1]
777
+ blockers: list[str] = []
778
+ if not payload.get("security_scans"):
779
+ blockers.append("cosmetic evidence: security_scans is empty")
780
+ if not payload.get("provenance"):
781
+ blockers.append("cosmetic evidence: provenance is empty")
782
+ if not payload.get("trace_ids"):
783
+ blockers.append("missing trace ids in evidence")
784
+ if not payload.get("lineage"):
785
+ blockers.append("missing lineage in evidence")
786
+ tests = payload.get("tests", [])
787
+ if isinstance(tests, list):
788
+ for item in tests:
789
+ if isinstance(item, dict) and item.get("name") == "worker_implementation" and not item.get("passed", False):
790
+ blockers.append("simulated worker evidence detected")
791
+ break
792
+ return {
793
+ "status": "ok" if not blockers else "error",
794
+ "evidence_file": str(evidence_path.relative_to(output_root)),
795
+ "blockers": blockers,
796
+ }
797
+
798
+
799
+ def _check_eval_gate(output_root: Path) -> dict[str, Any]:
800
+ latest_path = output_root / ".omg" / "evals" / "latest.json"
801
+ if not latest_path.exists():
802
+ return {"status": "missing", "blockers": []}
803
+ payload = _load_json(latest_path)
804
+ blockers: list[str] = []
805
+ if payload.get("status") != "ok" or bool(payload.get("summary", {}).get("regressed")):
806
+ blockers.append("eval regression detected")
807
+ return {
808
+ "status": "ok" if not blockers else "error",
809
+ "path": str(latest_path.relative_to(output_root)),
810
+ "blockers": blockers,
811
+ }
812
+
813
+
814
+ def _check_packaged_install_smoke(root: Path) -> dict[str, Any]:
815
+ blockers: list[str] = []
816
+ with tempfile.TemporaryDirectory(prefix="omg-wheel-") as tmp_dir:
817
+ proc = subprocess.run(
818
+ [sys.executable, "-m", "pip", "wheel", ".", "--no-deps", "-w", tmp_dir],
819
+ cwd=str(root),
820
+ capture_output=True,
821
+ text=True,
822
+ check=False,
823
+ timeout=120,
824
+ )
825
+ if proc.returncode != 0:
826
+ return {
827
+ "status": "error",
828
+ "blockers": ["package smoke failed to build wheel"],
829
+ "stdout": proc.stdout,
830
+ "stderr": proc.stderr,
831
+ }
832
+ wheels = sorted(Path(tmp_dir).glob("*.whl"))
833
+ if not wheels:
834
+ return {"status": "error", "blockers": ["package smoke did not produce a wheel"]}
835
+ with zipfile.ZipFile(wheels[-1]) as archive:
836
+ names = set(archive.namelist())
837
+ required_suffixes = (
838
+ "control_plane/service.py",
839
+ "registry/verify_artifact.py",
840
+ "plugins/dephealth/cve_scanner.py",
841
+ "OMG_COMPAT_CONTRACT.md",
842
+ ".agents/skills/omg/security-check/SKILL.md",
843
+ )
844
+ for suffix in required_suffixes:
845
+ if not any(name.endswith(suffix) for name in names):
846
+ blockers.append(f"package parity missing {suffix}")
847
+ return {"status": "ok" if not blockers else "error", "blockers": blockers}