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