@trac3r/oh-my-god 2.2.11

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 (638) hide show
  1. package/CHANGELOG.md +188 -0
  2. package/INSTALL-VERIFICATION-INDEX.md +51 -0
  3. package/LICENSE +21 -0
  4. package/OMG-setup.sh +2549 -0
  5. package/QUICK-REFERENCE.md +58 -0
  6. package/README.md +207 -0
  7. package/agents/__init__.py +1 -0
  8. package/agents/__pycache__/model_roles.cpython-313.pyc +0 -0
  9. package/agents/_model_roles.yaml +26 -0
  10. package/agents/designer.md +67 -0
  11. package/agents/explore.md +60 -0
  12. package/agents/model_roles.py +196 -0
  13. package/agents/omg-api-builder.md +23 -0
  14. package/agents/omg-architect-mode.md +41 -0
  15. package/agents/omg-architect.md +13 -0
  16. package/agents/omg-backend-engineer.md +41 -0
  17. package/agents/omg-critic.md +16 -0
  18. package/agents/omg-database-engineer.md +41 -0
  19. package/agents/omg-escalation-router.md +17 -0
  20. package/agents/omg-executor.md +12 -0
  21. package/agents/omg-frontend-designer.md +41 -0
  22. package/agents/omg-implement-mode.md +49 -0
  23. package/agents/omg-infra-engineer.md +41 -0
  24. package/agents/omg-qa-tester.md +16 -0
  25. package/agents/omg-research-mode.md +41 -0
  26. package/agents/omg-security-auditor.md +41 -0
  27. package/agents/omg-testing-engineer.md +41 -0
  28. package/agents/plan.md +80 -0
  29. package/agents/quick_task.md +64 -0
  30. package/agents/reviewer.md +83 -0
  31. package/agents/task.md +71 -0
  32. package/bin/omg +41 -0
  33. package/commands/OMG:ai-commit.md +113 -0
  34. package/commands/OMG:api-twin.md +22 -0
  35. package/commands/OMG:arch.md +313 -0
  36. package/commands/OMG:browser.md +29 -0
  37. package/commands/OMG:ccg.md +22 -0
  38. package/commands/OMG:compat.md +57 -0
  39. package/commands/OMG:cost.md +181 -0
  40. package/commands/OMG:crazy.md +125 -0
  41. package/commands/OMG:create-agent.md +183 -0
  42. package/commands/OMG:deep-plan.md +18 -0
  43. package/commands/OMG:deps.md +248 -0
  44. package/commands/OMG:diagnose-plugins.md +33 -0
  45. package/commands/OMG:doctor.md +37 -0
  46. package/commands/OMG:domain-init.md +11 -0
  47. package/commands/OMG:escalate.md +52 -0
  48. package/commands/OMG:forge.md +103 -0
  49. package/commands/OMG:health-check.md +48 -0
  50. package/commands/OMG:init.md +134 -0
  51. package/commands/OMG:issue.md +56 -0
  52. package/commands/OMG:mode.md +44 -0
  53. package/commands/OMG:playwright.md +17 -0
  54. package/commands/OMG:preflight.md +26 -0
  55. package/commands/OMG:preset.md +49 -0
  56. package/commands/OMG:profile-review.md +58 -0
  57. package/commands/OMG:project-init.md +11 -0
  58. package/commands/OMG:ralph-start.md +43 -0
  59. package/commands/OMG:ralph-stop.md +23 -0
  60. package/commands/OMG:security-check.md +28 -0
  61. package/commands/OMG:session-branch.md +101 -0
  62. package/commands/OMG:session-fork.md +57 -0
  63. package/commands/OMG:session-merge.md +138 -0
  64. package/commands/OMG:setup.md +82 -0
  65. package/commands/OMG:ship.md +18 -0
  66. package/commands/OMG:stats.md +225 -0
  67. package/commands/OMG:teams.md +54 -0
  68. package/commands/OMG:theme.md +44 -0
  69. package/commands/OMG:validate.md +59 -0
  70. package/commands/__init__.py +1 -0
  71. package/docs/command-surface.md +55 -0
  72. package/docs/install/claude-code.md +53 -0
  73. package/docs/install/codex.md +45 -0
  74. package/docs/install/gemini.md +43 -0
  75. package/docs/install/github-action.md +81 -0
  76. package/docs/install/github-app-required-checks.md +107 -0
  77. package/docs/install/github-app.md +161 -0
  78. package/docs/install/kimi.md +43 -0
  79. package/docs/install/opencode.md +38 -0
  80. package/docs/proof.md +182 -0
  81. package/hooks/__init__.py +0 -0
  82. package/hooks/__pycache__/__init__.cpython-313.pyc +0 -0
  83. package/hooks/__pycache__/_agent_registry.cpython-313.pyc +0 -0
  84. package/hooks/__pycache__/_analytics.cpython-313.pyc +0 -0
  85. package/hooks/__pycache__/_budget.cpython-313.pyc +0 -0
  86. package/hooks/__pycache__/_common.cpython-313.pyc +0 -0
  87. package/hooks/__pycache__/_compression_optimizer.cpython-313.pyc +0 -0
  88. package/hooks/__pycache__/_cost_ledger.cpython-313.pyc +0 -0
  89. package/hooks/__pycache__/_learnings.cpython-313.pyc +0 -0
  90. package/hooks/__pycache__/_memory.cpython-313.pyc +0 -0
  91. package/hooks/__pycache__/_post_write.cpython-313.pyc +0 -0
  92. package/hooks/__pycache__/_protected_context.cpython-313.pyc +0 -0
  93. package/hooks/__pycache__/_token_counter.cpython-313.pyc +0 -0
  94. package/hooks/__pycache__/branch_manager.cpython-313.pyc +0 -0
  95. package/hooks/__pycache__/budget_governor.cpython-313.pyc +0 -0
  96. package/hooks/__pycache__/circuit-breaker.cpython-313.pyc +0 -0
  97. package/hooks/__pycache__/compression_feedback.cpython-313.pyc +0 -0
  98. package/hooks/__pycache__/config-guard.cpython-313.pyc +0 -0
  99. package/hooks/__pycache__/context_pressure.cpython-313.pyc +0 -0
  100. package/hooks/__pycache__/credential_store.cpython-313.pyc +0 -0
  101. package/hooks/__pycache__/fetch-rate-limits.cpython-313.pyc +0 -0
  102. package/hooks/__pycache__/firewall.cpython-313.pyc +0 -0
  103. package/hooks/__pycache__/hashline-formatter-bridge.cpython-313.pyc +0 -0
  104. package/hooks/__pycache__/hashline-injector.cpython-313.pyc +0 -0
  105. package/hooks/__pycache__/hashline-validator.cpython-313.pyc +0 -0
  106. package/hooks/__pycache__/idle-detector.cpython-313.pyc +0 -0
  107. package/hooks/__pycache__/instructions-loaded.cpython-313.pyc +0 -0
  108. package/hooks/__pycache__/intentgate-keyword-detector.cpython-313.pyc +0 -0
  109. package/hooks/__pycache__/magic-keyword-router.cpython-313.pyc +0 -0
  110. package/hooks/__pycache__/policy_engine.cpython-313.pyc +0 -0
  111. package/hooks/__pycache__/post-tool-failure.cpython-313.pyc +0 -0
  112. package/hooks/__pycache__/post-write.cpython-313.pyc +0 -0
  113. package/hooks/__pycache__/post_write.cpython-313.pyc +0 -0
  114. package/hooks/__pycache__/pre-compact.cpython-313.pyc +0 -0
  115. package/hooks/__pycache__/pre-tool-inject.cpython-313.pyc +0 -0
  116. package/hooks/__pycache__/prompt-enhancer.cpython-313.pyc +0 -0
  117. package/hooks/__pycache__/quality-runner.cpython-313.pyc +0 -0
  118. package/hooks/__pycache__/query.cpython-313.pyc +0 -0
  119. package/hooks/__pycache__/secret-guard.cpython-313.pyc +0 -0
  120. package/hooks/__pycache__/secret_audit.cpython-313.pyc +0 -0
  121. package/hooks/__pycache__/security_validators.cpython-313.pyc +0 -0
  122. package/hooks/__pycache__/session-end-capture.cpython-313.pyc +0 -0
  123. package/hooks/__pycache__/session-start.cpython-313.pyc +0 -0
  124. package/hooks/__pycache__/setup_wizard.cpython-313.pyc +0 -0
  125. package/hooks/__pycache__/shadow_manager.cpython-313.pyc +0 -0
  126. package/hooks/__pycache__/state_migration.cpython-313.pyc +0 -0
  127. package/hooks/__pycache__/stop-gate.cpython-313.pyc +0 -0
  128. package/hooks/__pycache__/stop_dispatcher.cpython-313.pyc +0 -0
  129. package/hooks/__pycache__/tdd-gate.cpython-313.pyc +0 -0
  130. package/hooks/__pycache__/terms-guard.cpython-313.pyc +0 -0
  131. package/hooks/__pycache__/test-validator.cpython-313.pyc +0 -0
  132. package/hooks/__pycache__/test_generator_hook.cpython-313.pyc +0 -0
  133. package/hooks/__pycache__/todo-state-tracker.cpython-313.pyc +0 -0
  134. package/hooks/__pycache__/tool-ledger.cpython-313.pyc +0 -0
  135. package/hooks/__pycache__/trust_review.cpython-313.pyc +0 -0
  136. package/hooks/__pycache__/user-prompt-submit.cpython-313.pyc +0 -0
  137. package/hooks/_agent_registry.py +481 -0
  138. package/hooks/_analytics.py +291 -0
  139. package/hooks/_budget.py +31 -0
  140. package/hooks/_common.py +761 -0
  141. package/hooks/_compression_optimizer.py +119 -0
  142. package/hooks/_cost_ledger.py +176 -0
  143. package/hooks/_learnings.py +126 -0
  144. package/hooks/_memory.py +103 -0
  145. package/hooks/_post_write.py +46 -0
  146. package/hooks/_protected_context.py +150 -0
  147. package/hooks/_token_counter.py +221 -0
  148. package/hooks/branch_manager.py +255 -0
  149. package/hooks/budget_governor.py +326 -0
  150. package/hooks/circuit-breaker.py +270 -0
  151. package/hooks/compression_feedback.py +254 -0
  152. package/hooks/config-guard.py +193 -0
  153. package/hooks/context_pressure.py +119 -0
  154. package/hooks/credential_store.py +970 -0
  155. package/hooks/fetch-rate-limits.py +212 -0
  156. package/hooks/firewall.py +323 -0
  157. package/hooks/hashline-formatter-bridge.py +224 -0
  158. package/hooks/hashline-injector.py +273 -0
  159. package/hooks/hashline-validator.py +216 -0
  160. package/hooks/idle-detector.py +97 -0
  161. package/hooks/instructions-loaded.py +26 -0
  162. package/hooks/intentgate-keyword-detector.py +200 -0
  163. package/hooks/magic-keyword-router.py +195 -0
  164. package/hooks/policy_engine.py +767 -0
  165. package/hooks/post-tool-failure.py +19 -0
  166. package/hooks/post-write.py +233 -0
  167. package/hooks/pre-compact.py +470 -0
  168. package/hooks/pre-tool-inject.py +98 -0
  169. package/hooks/prompt-enhancer.py +879 -0
  170. package/hooks/quality-runner.py +191 -0
  171. package/hooks/query.py +512 -0
  172. package/hooks/secret-guard.py +120 -0
  173. package/hooks/secret_audit.py +144 -0
  174. package/hooks/security_validators.py +93 -0
  175. package/hooks/session-end-capture.py +505 -0
  176. package/hooks/session-start.py +261 -0
  177. package/hooks/setup_wizard.py +1101 -0
  178. package/hooks/shadow_manager.py +476 -0
  179. package/hooks/state_migration.py +228 -0
  180. package/hooks/stop-gate.py +7 -0
  181. package/hooks/stop_dispatcher.py +1259 -0
  182. package/hooks/tdd-gate.py +10 -0
  183. package/hooks/terms-guard.py +98 -0
  184. package/hooks/test-validator.py +462 -0
  185. package/hooks/test_generator_hook.py +123 -0
  186. package/hooks/todo-state-tracker.py +114 -0
  187. package/hooks/tool-ledger.py +165 -0
  188. package/hooks/trust_review.py +662 -0
  189. package/hooks/user-prompt-submit.py +12 -0
  190. package/hud/omg-hud.mjs +1571 -0
  191. package/lab/__init__.py +1 -0
  192. package/lab/__pycache__/__init__.cpython-313.pyc +0 -0
  193. package/lab/__pycache__/axolotl_adapter.cpython-313.pyc +0 -0
  194. package/lab/__pycache__/forge_runner.cpython-313.pyc +0 -0
  195. package/lab/__pycache__/gazebo_adapter.cpython-313.pyc +0 -0
  196. package/lab/__pycache__/isaac_gym_adapter.cpython-313.pyc +0 -0
  197. package/lab/__pycache__/mock_isaac_env.cpython-313.pyc +0 -0
  198. package/lab/__pycache__/pipeline.cpython-313.pyc +0 -0
  199. package/lab/__pycache__/policies.cpython-313.pyc +0 -0
  200. package/lab/__pycache__/pybullet_adapter.cpython-313.pyc +0 -0
  201. package/lab/axolotl_adapter.py +531 -0
  202. package/lab/forge_runner.py +103 -0
  203. package/lab/gazebo_adapter.py +168 -0
  204. package/lab/isaac_gym_adapter.py +190 -0
  205. package/lab/mock_isaac_env.py +47 -0
  206. package/lab/pipeline.py +712 -0
  207. package/lab/policies.py +52 -0
  208. package/lab/pybullet_adapter.py +192 -0
  209. package/package.json +61 -0
  210. package/plugins/README.md +78 -0
  211. package/plugins/__init__.py +1 -0
  212. package/plugins/__pycache__/__init__.cpython-313.pyc +0 -0
  213. package/plugins/advanced/commands/OMG-code-review.md +114 -0
  214. package/plugins/advanced/commands/OMG-deep-plan.md +266 -0
  215. package/plugins/advanced/commands/OMG-handoff.md +115 -0
  216. package/plugins/advanced/commands/OMG-learn.md +110 -0
  217. package/plugins/advanced/commands/OMG-maintainer.md +31 -0
  218. package/plugins/advanced/commands/OMG-ralph-start.md +43 -0
  219. package/plugins/advanced/commands/OMG-ralph-stop.md +23 -0
  220. package/plugins/advanced/commands/OMG-security-review.md +16 -0
  221. package/plugins/advanced/commands/OMG-sequential-thinking.md +20 -0
  222. package/plugins/advanced/commands/OMG-ship.md +46 -0
  223. package/plugins/advanced/commands/OMG:code-review.md +114 -0
  224. package/plugins/advanced/commands/OMG:deep-plan.md +266 -0
  225. package/plugins/advanced/commands/OMG:handoff.md +115 -0
  226. package/plugins/advanced/commands/OMG:learn.md +110 -0
  227. package/plugins/advanced/commands/OMG:maintainer.md +31 -0
  228. package/plugins/advanced/commands/OMG:ralph-start.md +43 -0
  229. package/plugins/advanced/commands/OMG:ralph-stop.md +23 -0
  230. package/plugins/advanced/commands/OMG:security-review.md +16 -0
  231. package/plugins/advanced/commands/OMG:sequential-thinking.md +20 -0
  232. package/plugins/advanced/commands/OMG:ship.md +46 -0
  233. package/plugins/advanced/plugin.json +104 -0
  234. package/plugins/core/plugin.json +204 -0
  235. package/plugins/dephealth/__init__.py +0 -0
  236. package/plugins/dephealth/__pycache__/__init__.cpython-313.pyc +0 -0
  237. package/plugins/dephealth/__pycache__/cve_scanner.cpython-313.pyc +0 -0
  238. package/plugins/dephealth/__pycache__/license_checker.cpython-313.pyc +0 -0
  239. package/plugins/dephealth/__pycache__/manifest_detector.cpython-313.pyc +0 -0
  240. package/plugins/dephealth/__pycache__/vuln_analyzer.cpython-313.pyc +0 -0
  241. package/plugins/dephealth/cve_scanner.py +279 -0
  242. package/plugins/dephealth/license_checker.py +135 -0
  243. package/plugins/dephealth/manifest_detector.py +423 -0
  244. package/plugins/dephealth/vuln_analyzer.py +176 -0
  245. package/plugins/testgen/__init__.py +0 -0
  246. package/plugins/testgen/__pycache__/__init__.cpython-313.pyc +0 -0
  247. package/plugins/testgen/__pycache__/codamosa_engine.cpython-313.pyc +0 -0
  248. package/plugins/testgen/__pycache__/edge_case_synthesizer.cpython-313.pyc +0 -0
  249. package/plugins/testgen/__pycache__/framework_detector.cpython-313.pyc +0 -0
  250. package/plugins/testgen/__pycache__/skeleton_generator.cpython-313.pyc +0 -0
  251. package/plugins/testgen/codamosa_engine.py +402 -0
  252. package/plugins/testgen/edge_case_synthesizer.py +184 -0
  253. package/plugins/testgen/framework_detector.py +271 -0
  254. package/plugins/testgen/skeleton_generator.py +219 -0
  255. package/plugins/viz/__init__.py +0 -0
  256. package/plugins/viz/__pycache__/__init__.cpython-313.pyc +0 -0
  257. package/plugins/viz/__pycache__/ast_parser.cpython-313.pyc +0 -0
  258. package/plugins/viz/__pycache__/diagram_generator.cpython-313.pyc +0 -0
  259. package/plugins/viz/__pycache__/graph_builder.cpython-313.pyc +0 -0
  260. package/plugins/viz/__pycache__/native_parsers.cpython-313.pyc +0 -0
  261. package/plugins/viz/__pycache__/regex_parser.cpython-313.pyc +0 -0
  262. package/plugins/viz/ast_parser.py +139 -0
  263. package/plugins/viz/diagram_generator.py +192 -0
  264. package/plugins/viz/graph_builder.py +444 -0
  265. package/plugins/viz/native_parsers.py +259 -0
  266. package/plugins/viz/regex_parser.py +112 -0
  267. package/pyproject.toml +143 -0
  268. package/registry/__init__.py +1 -0
  269. package/registry/__pycache__/__init__.cpython-313.pyc +0 -0
  270. package/registry/__pycache__/approval_artifact.cpython-313.pyc +0 -0
  271. package/registry/__pycache__/verify_artifact.cpython-313.pyc +0 -0
  272. package/registry/approval_artifact.py +236 -0
  273. package/registry/bundles/algorithms.yaml +45 -0
  274. package/registry/bundles/api-twin.yaml +48 -0
  275. package/registry/bundles/ast-pack.yaml +80 -0
  276. package/registry/bundles/claim-judge.yaml +49 -0
  277. package/registry/bundles/control-plane.yaml +192 -0
  278. package/registry/bundles/data-lineage.yaml +47 -0
  279. package/registry/bundles/delta-classifier.yaml +47 -0
  280. package/registry/bundles/eval-gate.yaml +47 -0
  281. package/registry/bundles/hash-edit.yaml +73 -0
  282. package/registry/bundles/health.yaml +45 -0
  283. package/registry/bundles/hook-governor.yaml +101 -0
  284. package/registry/bundles/incident-replay.yaml +47 -0
  285. package/registry/bundles/lsp-pack.yaml +80 -0
  286. package/registry/bundles/mcp-fabric.yaml +53 -0
  287. package/registry/bundles/plan-council.yaml +56 -0
  288. package/registry/bundles/preflight.yaml +48 -0
  289. package/registry/bundles/proof-gate.yaml +49 -0
  290. package/registry/bundles/remote-supervisor.yaml +49 -0
  291. package/registry/bundles/robotics.yaml +45 -0
  292. package/registry/bundles/secure-worktree-pipeline.yaml +69 -0
  293. package/registry/bundles/security-check.yaml +50 -0
  294. package/registry/bundles/terminal-lane.yaml +61 -0
  295. package/registry/bundles/test-intent-lock.yaml +49 -0
  296. package/registry/bundles/tracebank.yaml +47 -0
  297. package/registry/bundles/vision.yaml +45 -0
  298. package/registry/omg-capability.schema.json +378 -0
  299. package/registry/policy-packs/airgapped.lock.json +11 -0
  300. package/registry/policy-packs/airgapped.signature.json +10 -0
  301. package/registry/policy-packs/airgapped.yaml +16 -0
  302. package/registry/policy-packs/fintech.lock.json +11 -0
  303. package/registry/policy-packs/fintech.signature.json +10 -0
  304. package/registry/policy-packs/fintech.yaml +15 -0
  305. package/registry/policy-packs/locked-prod.lock.json +11 -0
  306. package/registry/policy-packs/locked-prod.signature.json +10 -0
  307. package/registry/policy-packs/locked-prod.yaml +18 -0
  308. package/registry/trusted_signers.json +44 -0
  309. package/registry/verify_artifact.py +493 -0
  310. package/runtime/__init__.py +36 -0
  311. package/runtime/__pycache__/__init__.cpython-313.pyc +0 -0
  312. package/runtime/__pycache__/adoption.cpython-313.pyc +0 -0
  313. package/runtime/__pycache__/agent_selector.cpython-313.pyc +0 -0
  314. package/runtime/__pycache__/api_twin.cpython-313.pyc +0 -0
  315. package/runtime/__pycache__/architecture_signal.cpython-313.pyc +0 -0
  316. package/runtime/__pycache__/artifact_parsers.cpython-313.pyc +0 -0
  317. package/runtime/__pycache__/asset_loader.cpython-313.pyc +0 -0
  318. package/runtime/__pycache__/background_verification.cpython-313.pyc +0 -0
  319. package/runtime/__pycache__/budget_envelopes.cpython-313.pyc +0 -0
  320. package/runtime/__pycache__/business_workflow.cpython-313.pyc +0 -0
  321. package/runtime/__pycache__/canonical_surface.cpython-313.pyc +0 -0
  322. package/runtime/__pycache__/canonical_taxonomy.cpython-313.pyc +0 -0
  323. package/runtime/__pycache__/claim_judge.cpython-313.pyc +0 -0
  324. package/runtime/__pycache__/cli_provider.cpython-313.pyc +0 -0
  325. package/runtime/__pycache__/compat.cpython-313.pyc +0 -0
  326. package/runtime/__pycache__/complexity_scorer.cpython-313.pyc +0 -0
  327. package/runtime/__pycache__/compliance_governor.cpython-313.pyc +0 -0
  328. package/runtime/__pycache__/config_transaction.cpython-313.pyc +0 -0
  329. package/runtime/__pycache__/context_compiler.cpython-313.pyc +0 -0
  330. package/runtime/__pycache__/context_engine.cpython-313.pyc +0 -0
  331. package/runtime/__pycache__/context_limits.cpython-313.pyc +0 -0
  332. package/runtime/__pycache__/contract_compiler.cpython-313.pyc +0 -0
  333. package/runtime/__pycache__/custom_agent_loader.cpython-313.pyc +0 -0
  334. package/runtime/__pycache__/data_lineage.cpython-313.pyc +0 -0
  335. package/runtime/__pycache__/defense_state.cpython-313.pyc +0 -0
  336. package/runtime/__pycache__/delta_classifier.cpython-313.pyc +0 -0
  337. package/runtime/__pycache__/dispatcher.cpython-313.pyc +0 -0
  338. package/runtime/__pycache__/doc_generator.cpython-313.pyc +0 -0
  339. package/runtime/__pycache__/domain_packs.cpython-313.pyc +0 -0
  340. package/runtime/__pycache__/ecosystem.cpython-313.pyc +0 -0
  341. package/runtime/__pycache__/equalizer.cpython-313.pyc +0 -0
  342. package/runtime/__pycache__/eval_gate.cpython-313.pyc +0 -0
  343. package/runtime/__pycache__/evidence_narrator.cpython-313.pyc +0 -0
  344. package/runtime/__pycache__/evidence_query.cpython-313.pyc +0 -0
  345. package/runtime/__pycache__/evidence_registry.cpython-313.pyc +0 -0
  346. package/runtime/__pycache__/evidence_requirements.cpython-313.pyc +0 -0
  347. package/runtime/__pycache__/exec_kernel.cpython-313.pyc +0 -0
  348. package/runtime/__pycache__/explainer_formatter.cpython-313.pyc +0 -0
  349. package/runtime/__pycache__/feature_registry.cpython-313.pyc +0 -0
  350. package/runtime/__pycache__/forge_agents.cpython-313.pyc +0 -0
  351. package/runtime/__pycache__/forge_contracts.cpython-313.pyc +0 -0
  352. package/runtime/__pycache__/forge_domains.cpython-313.pyc +0 -0
  353. package/runtime/__pycache__/forge_run_id.cpython-313.pyc +0 -0
  354. package/runtime/__pycache__/github_integration.cpython-313.pyc +0 -0
  355. package/runtime/__pycache__/github_review_bot.cpython-313.pyc +0 -0
  356. package/runtime/__pycache__/github_review_contract.cpython-313.pyc +0 -0
  357. package/runtime/__pycache__/github_review_formatter.cpython-313.pyc +0 -0
  358. package/runtime/__pycache__/guide_assert.cpython-313.pyc +0 -0
  359. package/runtime/__pycache__/hook_governor.cpython-313.pyc +0 -0
  360. package/runtime/__pycache__/host_parity.cpython-313.pyc +0 -0
  361. package/runtime/__pycache__/incident_replay.cpython-313.pyc +0 -0
  362. package/runtime/__pycache__/install_planner.cpython-313.pyc +0 -0
  363. package/runtime/__pycache__/interaction_journal.cpython-313.pyc +0 -0
  364. package/runtime/__pycache__/issue_surface.cpython-313.pyc +0 -0
  365. package/runtime/__pycache__/legacy_compat.cpython-313.pyc +0 -0
  366. package/runtime/__pycache__/mcp_config_writers.cpython-313.pyc +0 -0
  367. package/runtime/__pycache__/mcp_lifecycle.cpython-313.pyc +0 -0
  368. package/runtime/__pycache__/mcp_memory_server.cpython-313.pyc +0 -0
  369. package/runtime/__pycache__/memory_store.cpython-313.pyc +0 -0
  370. package/runtime/__pycache__/merge_writer.cpython-313.pyc +0 -0
  371. package/runtime/__pycache__/music_omr_testbed.cpython-313.pyc +0 -0
  372. package/runtime/__pycache__/mutation_gate.cpython-313.pyc +0 -0
  373. package/runtime/__pycache__/omc_compat.cpython-313.pyc +0 -0
  374. package/runtime/__pycache__/omg_browser_cli.cpython-313.pyc +0 -0
  375. package/runtime/__pycache__/omg_mcp_server.cpython-313.pyc +0 -0
  376. package/runtime/__pycache__/opus_plan.cpython-313.pyc +0 -0
  377. package/runtime/__pycache__/playwright_adapter.cpython-313.pyc +0 -0
  378. package/runtime/__pycache__/playwright_pack.cpython-313.pyc +0 -0
  379. package/runtime/__pycache__/plugin_diagnostics.cpython-313.pyc +0 -0
  380. package/runtime/__pycache__/plugin_interop.cpython-313.pyc +0 -0
  381. package/runtime/__pycache__/policy_pack_loader.cpython-313.pyc +0 -0
  382. package/runtime/__pycache__/preflight.cpython-313.pyc +0 -0
  383. package/runtime/__pycache__/profile_io.cpython-313.pyc +0 -0
  384. package/runtime/__pycache__/prompt_compiler.cpython-313.pyc +0 -0
  385. package/runtime/__pycache__/proof_chain.cpython-313.pyc +0 -0
  386. package/runtime/__pycache__/proof_gate.cpython-313.pyc +0 -0
  387. package/runtime/__pycache__/provider_parity_eval.cpython-313.pyc +0 -0
  388. package/runtime/__pycache__/release_artifact_audit.cpython-313.pyc +0 -0
  389. package/runtime/__pycache__/release_run_coordinator.cpython-313.pyc +0 -0
  390. package/runtime/__pycache__/release_surface_compiler.cpython-313.pyc +0 -0
  391. package/runtime/__pycache__/release_surface_registry.cpython-313.pyc +0 -0
  392. package/runtime/__pycache__/release_surfaces.cpython-313.pyc +0 -0
  393. package/runtime/__pycache__/remote_supervisor.cpython-313.pyc +0 -0
  394. package/runtime/__pycache__/repro_pack.cpython-313.pyc +0 -0
  395. package/runtime/__pycache__/rollback_manifest.cpython-313.pyc +0 -0
  396. package/runtime/__pycache__/router_critics.cpython-313.pyc +0 -0
  397. package/runtime/__pycache__/router_executor.cpython-313.pyc +0 -0
  398. package/runtime/__pycache__/router_selector.cpython-313.pyc +0 -0
  399. package/runtime/__pycache__/runtime_contracts.cpython-313.pyc +0 -0
  400. package/runtime/__pycache__/runtime_profile.cpython-313.pyc +0 -0
  401. package/runtime/__pycache__/security_check.cpython-313.pyc +0 -0
  402. package/runtime/__pycache__/session_health.cpython-313.pyc +0 -0
  403. package/runtime/__pycache__/skill_evolution.cpython-313.pyc +0 -0
  404. package/runtime/__pycache__/skill_registry.cpython-313.pyc +0 -0
  405. package/runtime/__pycache__/subagent_dispatcher.cpython-313.pyc +0 -0
  406. package/runtime/__pycache__/subscription_tiers.cpython-313.pyc +0 -0
  407. package/runtime/__pycache__/team_router.cpython-313.pyc +0 -0
  408. package/runtime/__pycache__/test_intent_lock.cpython-313-pytest-9.0.2.pyc +0 -0
  409. package/runtime/__pycache__/test_intent_lock.cpython-313.pyc +0 -0
  410. package/runtime/__pycache__/tmux_session_manager.cpython-313.pyc +0 -0
  411. package/runtime/__pycache__/tool_fabric.cpython-313.pyc +0 -0
  412. package/runtime/__pycache__/tool_plan_gate.cpython-313.pyc +0 -0
  413. package/runtime/__pycache__/tool_relevance.cpython-313.pyc +0 -0
  414. package/runtime/__pycache__/tracebank.cpython-313.pyc +0 -0
  415. package/runtime/__pycache__/untrusted_content.cpython-313.pyc +0 -0
  416. package/runtime/__pycache__/validate.cpython-313.pyc +0 -0
  417. package/runtime/__pycache__/verdict_schema.cpython-313.pyc +0 -0
  418. package/runtime/__pycache__/verification_controller.cpython-313.pyc +0 -0
  419. package/runtime/__pycache__/verification_loop.cpython-313.pyc +0 -0
  420. package/runtime/__pycache__/vision_artifacts.cpython-313.pyc +0 -0
  421. package/runtime/__pycache__/vision_cache.cpython-313.pyc +0 -0
  422. package/runtime/__pycache__/vision_jobs.cpython-313.pyc +0 -0
  423. package/runtime/__pycache__/worker_watchdog.cpython-313.pyc +0 -0
  424. package/runtime/adapters/__init__.py +13 -0
  425. package/runtime/adapters/__pycache__/__init__.cpython-313.pyc +0 -0
  426. package/runtime/adapters/__pycache__/claude.cpython-313.pyc +0 -0
  427. package/runtime/adapters/__pycache__/gpt.cpython-313.pyc +0 -0
  428. package/runtime/adapters/__pycache__/local.cpython-313.pyc +0 -0
  429. package/runtime/adapters/claude.py +63 -0
  430. package/runtime/adapters/gpt.py +56 -0
  431. package/runtime/adapters/local.py +56 -0
  432. package/runtime/adoption.py +280 -0
  433. package/runtime/api_twin.py +450 -0
  434. package/runtime/architecture_signal.py +226 -0
  435. package/runtime/artifact_parsers.py +161 -0
  436. package/runtime/asset_loader.py +62 -0
  437. package/runtime/background_verification.py +178 -0
  438. package/runtime/budget_envelopes.py +398 -0
  439. package/runtime/business_workflow.py +234 -0
  440. package/runtime/canonical_surface.py +53 -0
  441. package/runtime/canonical_taxonomy.py +27 -0
  442. package/runtime/claim_judge.py +648 -0
  443. package/runtime/cli_provider.py +105 -0
  444. package/runtime/compat.py +2222 -0
  445. package/runtime/complexity_scorer.py +148 -0
  446. package/runtime/compliance_governor.py +505 -0
  447. package/runtime/config_transaction.py +304 -0
  448. package/runtime/context_compiler.py +131 -0
  449. package/runtime/context_engine.py +708 -0
  450. package/runtime/context_limits.py +363 -0
  451. package/runtime/contract_compiler.py +3664 -0
  452. package/runtime/custom_agent_loader.py +366 -0
  453. package/runtime/data_lineage.py +244 -0
  454. package/runtime/defense_state.py +261 -0
  455. package/runtime/delta_classifier.py +231 -0
  456. package/runtime/dispatcher.py +47 -0
  457. package/runtime/doc_generator.py +319 -0
  458. package/runtime/domain_packs.py +75 -0
  459. package/runtime/ecosystem.py +371 -0
  460. package/runtime/equalizer.py +268 -0
  461. package/runtime/eval_gate.py +96 -0
  462. package/runtime/evidence_narrator.py +147 -0
  463. package/runtime/evidence_query.py +303 -0
  464. package/runtime/evidence_registry.py +16 -0
  465. package/runtime/evidence_requirements.py +157 -0
  466. package/runtime/exec_kernel.py +267 -0
  467. package/runtime/explainer_formatter.py +82 -0
  468. package/runtime/feature_registry.py +109 -0
  469. package/runtime/forge_agents.py +915 -0
  470. package/runtime/forge_contracts.py +519 -0
  471. package/runtime/forge_domains.py +68 -0
  472. package/runtime/forge_run_id.py +86 -0
  473. package/runtime/guide_assert.py +135 -0
  474. package/runtime/hook_governor.py +156 -0
  475. package/runtime/host_parity.py +373 -0
  476. package/runtime/incident_replay.py +310 -0
  477. package/runtime/install_planner.py +617 -0
  478. package/runtime/interaction_journal.py +566 -0
  479. package/runtime/issue_surface.py +472 -0
  480. package/runtime/legacy_compat.py +7 -0
  481. package/runtime/mcp_config_writers.py +360 -0
  482. package/runtime/mcp_lifecycle.py +175 -0
  483. package/runtime/mcp_memory_server.py +220 -0
  484. package/runtime/memory_parsers/__init__.py +0 -0
  485. package/runtime/memory_parsers/__pycache__/__init__.cpython-313.pyc +0 -0
  486. package/runtime/memory_parsers/__pycache__/chatgpt_parser.cpython-313.pyc +0 -0
  487. package/runtime/memory_parsers/__pycache__/claude_import.cpython-313.pyc +0 -0
  488. package/runtime/memory_parsers/__pycache__/export.cpython-313.pyc +0 -0
  489. package/runtime/memory_parsers/__pycache__/gemini_import.cpython-313.pyc +0 -0
  490. package/runtime/memory_parsers/__pycache__/kimi_import.cpython-313.pyc +0 -0
  491. package/runtime/memory_parsers/chatgpt_parser.py +257 -0
  492. package/runtime/memory_parsers/claude_import.py +107 -0
  493. package/runtime/memory_parsers/export.py +97 -0
  494. package/runtime/memory_parsers/gemini_import.py +91 -0
  495. package/runtime/memory_parsers/kimi_import.py +91 -0
  496. package/runtime/memory_store.py +1182 -0
  497. package/runtime/merge_writer.py +445 -0
  498. package/runtime/music_omr_testbed.py +336 -0
  499. package/runtime/mutation_gate.py +320 -0
  500. package/runtime/omc_compat.py +7 -0
  501. package/runtime/omg_browser_cli.py +95 -0
  502. package/runtime/omg_compat_contract_snapshot.json +936 -0
  503. package/runtime/omg_contract_snapshot.json +936 -0
  504. package/runtime/omg_mcp_server.py +306 -0
  505. package/runtime/playwright_adapter.py +39 -0
  506. package/runtime/playwright_pack.py +253 -0
  507. package/runtime/plugin_diagnostics.py +308 -0
  508. package/runtime/plugin_interop.py +1060 -0
  509. package/runtime/policy_pack_loader.py +147 -0
  510. package/runtime/preflight.py +135 -0
  511. package/runtime/profile_io.py +328 -0
  512. package/runtime/proof_chain.py +472 -0
  513. package/runtime/proof_gate.py +442 -0
  514. package/runtime/provider_parity_eval.py +109 -0
  515. package/runtime/providers/__init__.py +0 -0
  516. package/runtime/providers/__pycache__/__init__.cpython-313.pyc +0 -0
  517. package/runtime/providers/__pycache__/codex_provider.cpython-313.pyc +0 -0
  518. package/runtime/providers/__pycache__/gemini_provider.cpython-313.pyc +0 -0
  519. package/runtime/providers/__pycache__/kimi_provider.cpython-313.pyc +0 -0
  520. package/runtime/providers/__pycache__/opencode_provider.cpython-313.pyc +0 -0
  521. package/runtime/providers/codex_provider.py +129 -0
  522. package/runtime/providers/gemini_provider.py +143 -0
  523. package/runtime/providers/kimi_provider.py +167 -0
  524. package/runtime/providers/opencode_provider.py +99 -0
  525. package/runtime/release_artifact_audit.py +556 -0
  526. package/runtime/release_run_coordinator.py +574 -0
  527. package/runtime/release_surface_compiler.py +643 -0
  528. package/runtime/release_surface_registry.py +283 -0
  529. package/runtime/release_surfaces.py +320 -0
  530. package/runtime/remote_supervisor.py +79 -0
  531. package/runtime/repro_pack.py +398 -0
  532. package/runtime/rollback_manifest.py +143 -0
  533. package/runtime/router_critics.py +229 -0
  534. package/runtime/router_executor.py +142 -0
  535. package/runtime/router_selector.py +99 -0
  536. package/runtime/runtime_contracts.py +292 -0
  537. package/runtime/runtime_profile.py +133 -0
  538. package/runtime/security_check.py +1094 -0
  539. package/runtime/session_health.py +546 -0
  540. package/runtime/skill_evolution.py +221 -0
  541. package/runtime/skill_registry.py +53 -0
  542. package/runtime/subagent_dispatcher.py +604 -0
  543. package/runtime/subscription_tiers.py +258 -0
  544. package/runtime/team_router.py +1399 -0
  545. package/runtime/test_intent_lock.py +543 -0
  546. package/runtime/tmux_session_manager.py +172 -0
  547. package/runtime/tool_fabric.py +570 -0
  548. package/runtime/tool_plan_gate.py +460 -0
  549. package/runtime/tracebank.py +125 -0
  550. package/runtime/untrusted_content.py +360 -0
  551. package/runtime/validate.py +293 -0
  552. package/runtime/verdict_schema.py +198 -0
  553. package/runtime/verification_controller.py +235 -0
  554. package/runtime/verification_loop.py +73 -0
  555. package/runtime/vision_artifacts.py +31 -0
  556. package/runtime/vision_cache.py +38 -0
  557. package/runtime/vision_jobs.py +92 -0
  558. package/runtime/worker_watchdog.py +526 -0
  559. package/scripts/__pycache__/audit-published-artifact.cpython-313.pyc +0 -0
  560. package/scripts/__pycache__/check-doc-parity.cpython-313.pyc +0 -0
  561. package/scripts/__pycache__/check-omg-standalone-clean.cpython-313.pyc +0 -0
  562. package/scripts/__pycache__/github_review_helpers.cpython-313.pyc +0 -0
  563. package/scripts/__pycache__/omg.cpython-313.pyc +0 -0
  564. package/scripts/__pycache__/prepare-release-proof-fixtures.cpython-313.pyc +0 -0
  565. package/scripts/__pycache__/sync-release-identity.cpython-313.pyc +0 -0
  566. package/scripts/__pycache__/validate-release-identity.cpython-313.pyc +0 -0
  567. package/scripts/audit-published-artifact.py +59 -0
  568. package/scripts/check-omg-compat-contract-snapshot.py +137 -0
  569. package/scripts/check-omg-contract-snapshot.py +12 -0
  570. package/scripts/check-omg-public-ready.py +273 -0
  571. package/scripts/check-omg-standalone-clean.py +133 -0
  572. package/scripts/emit_host_parity.py +72 -0
  573. package/scripts/legacy_to_omg_migrate.py +29 -0
  574. package/scripts/migrate-legacy.py +464 -0
  575. package/scripts/omc_to_omg_migrate.py +12 -0
  576. package/scripts/omg.py +2962 -0
  577. package/scripts/pre-release-check.sh +38 -0
  578. package/scripts/prepare-release-proof-fixtures.py +602 -0
  579. package/scripts/print-canonical-version.py +80 -0
  580. package/scripts/settings-merge.py +289 -0
  581. package/scripts/sync-release-identity.py +481 -0
  582. package/scripts/validate-release-identity.py +632 -0
  583. package/scripts/verify-no-omc.sh +5 -0
  584. package/scripts/verify-standalone.sh +35 -0
  585. package/settings.json +751 -0
  586. package/tools/__init__.py +2 -0
  587. package/tools/__pycache__/__init__.cpython-313.pyc +0 -0
  588. package/tools/__pycache__/browser_consent.cpython-313.pyc +0 -0
  589. package/tools/__pycache__/browser_stealth.cpython-313.pyc +0 -0
  590. package/tools/__pycache__/browser_tool.cpython-313.pyc +0 -0
  591. package/tools/__pycache__/changelog_generator.cpython-313.pyc +0 -0
  592. package/tools/__pycache__/commit_splitter.cpython-313.pyc +0 -0
  593. package/tools/__pycache__/config_discovery.cpython-313.pyc +0 -0
  594. package/tools/__pycache__/config_merger.cpython-313.pyc +0 -0
  595. package/tools/__pycache__/dashboard_generator.cpython-313.pyc +0 -0
  596. package/tools/__pycache__/git_inspector.cpython-313.pyc +0 -0
  597. package/tools/__pycache__/lsp_client.cpython-313.pyc +0 -0
  598. package/tools/__pycache__/lsp_operations.cpython-313.pyc +0 -0
  599. package/tools/__pycache__/pr_generator.cpython-313.pyc +0 -0
  600. package/tools/__pycache__/python_repl.cpython-313.pyc +0 -0
  601. package/tools/__pycache__/python_sandbox.cpython-313.pyc +0 -0
  602. package/tools/__pycache__/session_snapshot.cpython-313.pyc +0 -0
  603. package/tools/__pycache__/ssh_manager.cpython-313.pyc +0 -0
  604. package/tools/__pycache__/theme_engine.cpython-313.pyc +0 -0
  605. package/tools/__pycache__/theme_selector.cpython-313.pyc +0 -0
  606. package/tools/__pycache__/web_search.cpython-313.pyc +0 -0
  607. package/tools/browser_consent.py +289 -0
  608. package/tools/browser_stealth.py +481 -0
  609. package/tools/browser_tool.py +448 -0
  610. package/tools/changelog_generator.py +347 -0
  611. package/tools/commit_splitter.py +749 -0
  612. package/tools/config_discovery.py +151 -0
  613. package/tools/config_merger.py +449 -0
  614. package/tools/dashboard_generator.py +300 -0
  615. package/tools/git_inspector.py +298 -0
  616. package/tools/lsp_client.py +275 -0
  617. package/tools/lsp_discovery.py +231 -0
  618. package/tools/lsp_operations.py +392 -0
  619. package/tools/pr_generator.py +404 -0
  620. package/tools/python_repl.py +712 -0
  621. package/tools/python_sandbox.py +768 -0
  622. package/tools/search_providers/__init__.py +77 -0
  623. package/tools/search_providers/__pycache__/__init__.cpython-313.pyc +0 -0
  624. package/tools/search_providers/__pycache__/brave.cpython-313.pyc +0 -0
  625. package/tools/search_providers/__pycache__/exa.cpython-313.pyc +0 -0
  626. package/tools/search_providers/__pycache__/jina.cpython-313.pyc +0 -0
  627. package/tools/search_providers/__pycache__/perplexity.cpython-313.pyc +0 -0
  628. package/tools/search_providers/__pycache__/synthetic.cpython-313.pyc +0 -0
  629. package/tools/search_providers/brave.py +115 -0
  630. package/tools/search_providers/exa.py +116 -0
  631. package/tools/search_providers/jina.py +104 -0
  632. package/tools/search_providers/perplexity.py +139 -0
  633. package/tools/search_providers/synthetic.py +74 -0
  634. package/tools/session_snapshot.py +851 -0
  635. package/tools/ssh_manager.py +912 -0
  636. package/tools/theme_engine.py +296 -0
  637. package/tools/theme_selector.py +137 -0
  638. package/tools/web_search.py +675 -0
@@ -0,0 +1,135 @@
1
+ """Rule-based output assertions for OMG guide checks."""
2
+ from __future__ import annotations
3
+
4
+ import re
5
+ from typing import Any
6
+
7
+
8
+ def guide_assert(candidate: str, rules: dict[str, Any]) -> dict[str, Any]:
9
+ text = candidate or ""
10
+ lowered = text.lower()
11
+ violations: list[dict[str, str]] = []
12
+
13
+ terms_rules = rules.get("terms_guard") if isinstance(rules, dict) else {}
14
+ terms_verdict = terms_guard(text, terms_rules if isinstance(terms_rules, dict) else {})
15
+ if terms_verdict.get("status") != "ok":
16
+ violations.append(
17
+ {
18
+ "rule_type": "terms_guard",
19
+ "rule": "terms_guard",
20
+ "reason": str(terms_verdict.get("reason", "terms_guard_rejected")),
21
+ }
22
+ )
23
+
24
+ for goal in _as_list(rules.get("goals")):
25
+ if "todo" in goal.lower() and "todo" in lowered:
26
+ violations.append({"rule_type": "goal", "rule": goal, "reason": "candidate still includes TODO markers"})
27
+
28
+ for non_goal in _as_list(rules.get("non_goals")):
29
+ if _mentions(lowered, non_goal):
30
+ violations.append({"rule_type": "non_goal", "rule": non_goal, "reason": "candidate mentions an explicit non-goal"})
31
+
32
+ for criterion in _as_list(rules.get("acceptance_criteria")):
33
+ if "production-ready" in criterion.lower() and any(token in lowered for token in ("todo", "insecure", "placeholder")):
34
+ violations.append({"rule_type": "acceptance_criteria", "rule": criterion, "reason": "candidate contains non-production wording"})
35
+
36
+ return {
37
+ "schema": "GuideAssertionResult",
38
+ "verdict": "fail" if violations else "pass",
39
+ "violations": violations,
40
+ "terms_guard": terms_verdict,
41
+ "summary": {
42
+ "rule_count": sum(len(_as_list(rules.get(key))) for key in ("goals", "non_goals", "acceptance_criteria", "architecture_constraints", "style_rules", "risk_appetite")),
43
+ "violation_count": len(violations),
44
+ },
45
+ }
46
+
47
+
48
+ def terms_guard(input_text: str, rules: dict[str, Any]) -> dict[str, Any]:
49
+ text = str(input_text or "")
50
+ config = rules if isinstance(rules, dict) else {}
51
+
52
+ min_length = _as_int(config.get("min_length"))
53
+ max_length = _as_int(config.get("max_length"))
54
+ if min_length is not None and min_length < 0:
55
+ return {"status": "rejected", "reason": "terms_guard_invalid_min_length"}
56
+ if max_length is not None and max_length < 0:
57
+ return {"status": "rejected", "reason": "terms_guard_invalid_max_length"}
58
+ if min_length is not None and max_length is not None and min_length > max_length:
59
+ return {"status": "rejected", "reason": "terms_guard_invalid_length_bounds"}
60
+
61
+ allowlist = _as_exact_terms(config.get("allowlist"))
62
+ if config.get("allowlist") is not None and allowlist is None:
63
+ return {"status": "rejected", "reason": "terms_guard_invalid_allowlist"}
64
+
65
+ pattern = config.get("pattern")
66
+ if pattern is not None and not isinstance(pattern, str):
67
+ return {"status": "rejected", "reason": "terms_guard_invalid_pattern"}
68
+
69
+ deny_patterns = _as_exact_terms(config.get("deny_patterns"))
70
+ if config.get("deny_patterns") is not None and deny_patterns is None:
71
+ return {"status": "rejected", "reason": "terms_guard_invalid_deny_patterns"}
72
+
73
+ if min_length is not None and len(text) < min_length:
74
+ return {"status": "rejected", "reason": "terms_guard_too_short"}
75
+ if max_length is not None and len(text) > max_length:
76
+ return {"status": "rejected", "reason": "terms_guard_too_long"}
77
+
78
+ if allowlist is not None and text not in allowlist:
79
+ return {"status": "rejected", "reason": "terms_guard_not_in_allowlist"}
80
+
81
+ if isinstance(pattern, str) and pattern:
82
+ try:
83
+ if re.fullmatch(pattern, text) is None:
84
+ return {"status": "rejected", "reason": "terms_guard_pattern_mismatch"}
85
+ except re.error:
86
+ return {"status": "rejected", "reason": "terms_guard_invalid_pattern"}
87
+
88
+ if deny_patterns:
89
+ for blocked in deny_patterns:
90
+ try:
91
+ if re.search(blocked, text):
92
+ return {"status": "rejected", "reason": "terms_guard_disallowed_pattern"}
93
+ except re.error:
94
+ return {"status": "rejected", "reason": "terms_guard_invalid_deny_pattern"}
95
+
96
+ return {"status": "ok"}
97
+
98
+
99
+ def _as_list(value: Any) -> list[str]:
100
+ if not isinstance(value, list):
101
+ return []
102
+ return [str(item) for item in value if str(item).strip()]
103
+
104
+
105
+ def _mentions(lowered_candidate: str, rule: str) -> bool:
106
+ tokens = [token.lower() for token in rule.split() if len(token) >= 4]
107
+ if not tokens:
108
+ return False
109
+ return all(token in lowered_candidate for token in tokens)
110
+
111
+
112
+ def _as_int(value: Any) -> int | None:
113
+ if value is None:
114
+ return None
115
+ if isinstance(value, bool):
116
+ return None
117
+ if isinstance(value, int):
118
+ return value
119
+ if isinstance(value, str) and value.strip().isdigit():
120
+ return int(value.strip())
121
+ return None
122
+
123
+
124
+ def _as_exact_terms(value: Any) -> list[str] | None:
125
+ if not isinstance(value, list):
126
+ return None
127
+ output: list[str] = []
128
+ for item in value:
129
+ if not isinstance(item, str):
130
+ return None
131
+ token = item.strip()
132
+ if not token:
133
+ return None
134
+ output.append(token)
135
+ return output
@@ -0,0 +1,156 @@
1
+ """Hook-order validation using the canonical hook-governor bundle."""
2
+ from __future__ import annotations
3
+
4
+ import json
5
+ import os
6
+ from pathlib import Path
7
+ import re
8
+ from typing import Literal, TypedDict, cast
9
+
10
+ try:
11
+ import yaml
12
+ except Exception: # pragma: no cover - json fallback path
13
+ yaml = None
14
+
15
+
16
+ DEFAULT_BUNDLE_PATH = Path("registry") / "bundles" / "hook-governor.yaml"
17
+ _MODULE_DIR = Path(__file__).resolve().parent.parent # project root (runtime/ → project root)
18
+ SECURITY_REQUIRED_BY_EVENT: dict[str, tuple[str, ...]] = {
19
+ "PreToolUse": ("firewall", "secret-guard"),
20
+ }
21
+
22
+
23
+ class ValidationResult(TypedDict):
24
+ status: Literal["ok", "blocked"]
25
+ blockers: list[str]
26
+
27
+
28
+ def _resolve_project_dir(project_dir: str | None) -> Path:
29
+ if project_dir:
30
+ return Path(project_dir)
31
+ env_project_dir = os.environ.get("CLAUDE_PROJECT_DIR")
32
+ if env_project_dir:
33
+ return Path(env_project_dir)
34
+ return Path.cwd()
35
+
36
+
37
+ def _extract_hook_name(command: str) -> str:
38
+ matches = cast(list[str], re.findall(r"([A-Za-z0-9_.-]+\.py)", command))
39
+ if matches:
40
+ return Path(matches[-1]).stem
41
+ tokens = command.strip().split()
42
+ if not tokens:
43
+ return ""
44
+ return Path(tokens[-1].strip("\"'")).stem
45
+
46
+
47
+ def _load_compiled_hooks(
48
+ project_dir: str | None = None,
49
+ bundle_path: str | None = None,
50
+ ) -> tuple[dict[str, list[str]], str | None]:
51
+ root = _resolve_project_dir(project_dir)
52
+ candidate = Path(bundle_path) if bundle_path else (root / DEFAULT_BUNDLE_PATH)
53
+ if not bundle_path and not candidate.exists():
54
+ # Fallback: resolve relative to this module's installed location (robust to cwd changes
55
+ # and CLAUDE_PROJECT_DIR pointing to temp dirs in parallel test runs).
56
+ module_relative = _MODULE_DIR / DEFAULT_BUNDLE_PATH
57
+ if module_relative.exists():
58
+ candidate = module_relative
59
+ try:
60
+ raw = candidate.read_text(encoding="utf-8")
61
+ except FileNotFoundError:
62
+ return {}, f"canonical hook bundle missing: {candidate}"
63
+ except Exception as exc:
64
+ return {}, f"failed reading canonical hook bundle: {exc}"
65
+
66
+ try:
67
+ parsed_obj: object
68
+ if yaml is not None:
69
+ parsed_obj = cast(object, yaml.safe_load(raw))
70
+ if parsed_obj is None:
71
+ parsed_obj = {}
72
+ else:
73
+ parsed_obj = cast(object, json.loads(raw))
74
+ except Exception as exc:
75
+ return {}, f"failed parsing canonical hook bundle: {exc}"
76
+
77
+ if not isinstance(parsed_obj, dict):
78
+ return {}, "invalid canonical hook bundle payload"
79
+
80
+ payload = cast(dict[object, object], parsed_obj)
81
+ compiled_hooks_obj = payload.get("compiled_hooks")
82
+ if not isinstance(compiled_hooks_obj, dict):
83
+ return {}, "compiled_hooks missing from canonical hook bundle"
84
+
85
+ compiled_hooks = cast(dict[object, object], compiled_hooks_obj)
86
+ canonical: dict[str, list[str]] = {}
87
+ for event_key, hooks_obj in compiled_hooks.items():
88
+ if not isinstance(event_key, str) or not isinstance(hooks_obj, list):
89
+ continue
90
+ names: list[str] = []
91
+ for hook_entry in cast(list[object], hooks_obj):
92
+ if not isinstance(hook_entry, dict):
93
+ continue
94
+ hook_map = cast(dict[object, object], hook_entry)
95
+ command_obj = hook_map.get("command")
96
+ if not isinstance(command_obj, str):
97
+ continue
98
+ hook_name = _extract_hook_name(command_obj)
99
+ if hook_name:
100
+ names.append(hook_name)
101
+ canonical[event_key] = names
102
+ return canonical, None
103
+
104
+
105
+ def get_canonical_order(
106
+ event: str,
107
+ *,
108
+ project_dir: str | None = None,
109
+ bundle_path: str | None = None,
110
+ ) -> list[str]:
111
+ compiled_hooks, _ = _load_compiled_hooks(project_dir=project_dir, bundle_path=bundle_path)
112
+ return list(compiled_hooks.get(event, ()))
113
+
114
+
115
+ def validate_order(
116
+ event: str,
117
+ hooks_list: list[str],
118
+ *,
119
+ project_dir: str | None = None,
120
+ bundle_path: str | None = None,
121
+ ) -> ValidationResult:
122
+ compiled_hooks, load_error = _load_compiled_hooks(project_dir=project_dir, bundle_path=bundle_path)
123
+ if load_error:
124
+ return {"status": "blocked", "blockers": [load_error]}
125
+
126
+ canonical = compiled_hooks.get(event, [])
127
+ if not canonical:
128
+ return {"status": "blocked", "blockers": [f"no canonical hook order for event {event}"]}
129
+
130
+ blockers: list[str] = []
131
+ expected_positions = {name: idx for idx, name in enumerate(canonical)}
132
+
133
+ required_security_hooks = SECURITY_REQUIRED_BY_EVENT.get(event, ())
134
+ for required in required_security_hooks:
135
+ if required not in hooks_list:
136
+ blockers.append(f"missing required security hook: {required}")
137
+
138
+ if required_security_hooks:
139
+ for expected_index, required in enumerate(required_security_hooks):
140
+ if required not in hooks_list:
141
+ continue
142
+ actual_index = hooks_list.index(required)
143
+ if actual_index != expected_index:
144
+ blockers.append(
145
+ f"hook order violation for {event}: {required} must run before non-security hooks"
146
+ )
147
+
148
+ filtered_hooks = [hook for hook in hooks_list if hook in expected_positions]
149
+ for left, right in zip(filtered_hooks, filtered_hooks[1:]):
150
+ if expected_positions[left] > expected_positions[right]:
151
+ blockers.append(
152
+ f"hook order violation for {event}: {left} must run after {right} in canonical order"
153
+ )
154
+
155
+ status: Literal["ok", "blocked"] = "blocked" if blockers else "ok"
156
+ return {"status": status, "blockers": blockers}
@@ -0,0 +1,373 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ import re
6
+ from dataclasses import asdict, dataclass
7
+ from datetime import datetime, timezone
8
+ from pathlib import Path
9
+ from typing import Any
10
+
11
+ from runtime.canonical_surface import get_canonical_hosts
12
+
13
+
14
+ _IGNORED_SEMANTIC_KEYS = {
15
+ "host",
16
+ "model",
17
+ "model_name",
18
+ "provider",
19
+ "timestamp",
20
+ "run_id",
21
+ "id",
22
+ "latency_ms",
23
+ "duration_ms",
24
+ "token_usage",
25
+ "usage",
26
+ "raw",
27
+ }
28
+
29
+ _TOKEN_RE = re.compile(r"[a-z0-9_\-]+")
30
+ _KV_LINE_RE = re.compile(r"^\s*([A-Za-z0-9_\- ]+):\s*(.+?)\s*$")
31
+ _REAL_PARITY_SOURCE_KINDS = {
32
+ "compiled_artifact",
33
+ "compiled_output",
34
+ "replayed_output",
35
+ "replayed_artifact",
36
+ }
37
+
38
+
39
+ @dataclass
40
+ class ParityCheckResult:
41
+ passed: bool
42
+ host_results: dict[str, dict[str, Any]]
43
+ drift_detected: bool
44
+ drift_details: list[str]
45
+
46
+
47
+ @dataclass
48
+ class HostParityReport:
49
+ run_id: str
50
+ timestamp: str
51
+ canonical_hosts: list[str]
52
+ parity_results: dict[str, Any]
53
+ overall_status: str
54
+
55
+
56
+ def _now_iso() -> str:
57
+ return datetime.now(timezone.utc).isoformat()
58
+
59
+
60
+ def _normalize_host(host: str) -> str:
61
+ return str(host).strip().lower()
62
+
63
+
64
+ def _source_metadata(payload: dict[str, Any]) -> tuple[str, str]:
65
+ raw_source = payload.get("source")
66
+ if not isinstance(raw_source, dict):
67
+ return "", ""
68
+
69
+ source: dict[str, Any] = raw_source
70
+ source_kind = str(source.get("kind", "")).strip().lower()
71
+ source_path = ""
72
+ for key in ("artifact_path", "replay_path", "compiled_path", "output_path", "path"):
73
+ value = str(source.get(key, "")).strip()
74
+ if value:
75
+ source_path = value
76
+ break
77
+ return source_kind, source_path
78
+
79
+
80
+ def is_synthetic(payload: dict[str, Any]) -> bool:
81
+ source_kind, source_path = _source_metadata(payload)
82
+ if not source_kind:
83
+ return True
84
+ if source_kind not in _REAL_PARITY_SOURCE_KINDS:
85
+ return True
86
+ if not source_path:
87
+ return True
88
+ return False
89
+
90
+
91
+ def _canonicalize(value: Any) -> Any:
92
+ if isinstance(value, dict):
93
+ out: dict[str, Any] = {}
94
+ for key in sorted(value.keys()):
95
+ key_str = str(key)
96
+ if key_str in _IGNORED_SEMANTIC_KEYS:
97
+ continue
98
+ out[key_str] = _canonicalize(value[key])
99
+ return out
100
+ if isinstance(value, list):
101
+ canonical_items = [_canonicalize(item) for item in value]
102
+ if all(isinstance(item, (str, int, float, bool, type(None))) for item in canonical_items):
103
+ return sorted(canonical_items, key=lambda item: repr(item))
104
+ return canonical_items
105
+ if isinstance(value, str):
106
+ return value.strip()
107
+ return value
108
+
109
+
110
+ def _tokenize(text: str) -> list[str]:
111
+ return sorted(set(_TOKEN_RE.findall(text.lower())))
112
+
113
+
114
+ def _parse_json_blob(text: str) -> Any | None:
115
+ stripped = text.strip()
116
+ if not stripped:
117
+ return None
118
+ try:
119
+ return json.loads(stripped)
120
+ except json.JSONDecodeError:
121
+ pass
122
+
123
+ fence = re.search(r"```(?:json)?\s*(\{[\s\S]*\}|\[[\s\S]*\])\s*```", stripped, flags=re.IGNORECASE)
124
+ if fence:
125
+ candidate = fence.group(1)
126
+ try:
127
+ return json.loads(candidate)
128
+ except json.JSONDecodeError:
129
+ pass
130
+
131
+ decoder = json.JSONDecoder()
132
+ for start in range(len(stripped)):
133
+ if stripped[start] not in "[{":
134
+ continue
135
+ try:
136
+ parsed, _ = decoder.raw_decode(stripped[start:])
137
+ return parsed
138
+ except json.JSONDecodeError:
139
+ continue
140
+ return None
141
+
142
+
143
+ def _coerce_scalar(value: str) -> Any:
144
+ lowered = value.strip().lower()
145
+ if lowered in {"true", "false"}:
146
+ return lowered == "true"
147
+ if lowered in {"null", "none"}:
148
+ return None
149
+ if re.fullmatch(r"-?\d+", value.strip()):
150
+ return int(value.strip())
151
+ if re.fullmatch(r"-?\d+\.\d+", value.strip()):
152
+ return float(value.strip())
153
+ return value.strip()
154
+
155
+
156
+ def _parse_structured_text(text: str) -> dict[str, Any]:
157
+ structured: dict[str, Any] = {}
158
+ for line in text.splitlines():
159
+ match = _KV_LINE_RE.match(line)
160
+ if not match:
161
+ continue
162
+ key = match.group(1).strip().lower().replace(" ", "_")
163
+ value = match.group(2).strip()
164
+ if "," in value:
165
+ structured[key] = [_coerce_scalar(part) for part in value.split(",") if part.strip()]
166
+ else:
167
+ structured[key] = _coerce_scalar(value)
168
+ return structured
169
+
170
+
171
+ def _build_semantic_content(host: str, output_value: Any) -> dict[str, Any]:
172
+ if isinstance(output_value, (dict, list)):
173
+ return {"structured": _canonicalize(output_value)}
174
+
175
+ output_text = str(output_value or "").strip()
176
+ parsed = _parse_json_blob(output_text)
177
+ if parsed is not None:
178
+ return {"structured": _canonicalize(parsed)}
179
+
180
+ if host == "gemini":
181
+ structured = _parse_structured_text(output_text)
182
+ if structured:
183
+ return {"structured": _canonicalize(structured)}
184
+
185
+ tokens = _tokenize(output_text)
186
+ return {
187
+ "text": {
188
+ "tokens": tokens[:64],
189
+ "token_count": len(tokens),
190
+ }
191
+ }
192
+
193
+
194
+ def _jaccard_similarity(a_tokens: list[str], b_tokens: list[str]) -> float:
195
+ a_set = set(a_tokens)
196
+ b_set = set(b_tokens)
197
+ if not a_set and not b_set:
198
+ return 1.0
199
+ if not a_set or not b_set:
200
+ return 0.0
201
+ return len(a_set & b_set) / len(a_set | b_set)
202
+
203
+
204
+ class HostParityNormalizer:
205
+ def __init__(self, canonical_hosts: list[str] | None = None, text_similarity_threshold: float = 0.55):
206
+ self.canonical_hosts = [_normalize_host(host) for host in (canonical_hosts or get_canonical_hosts())]
207
+ self.text_similarity_threshold = max(0.0, min(1.0, float(text_similarity_threshold)))
208
+
209
+ def normalize_output(self, host: str, raw_output: Any, context: dict[str, Any] | None = None) -> dict[str, Any]:
210
+ _ = context
211
+ host_name = _normalize_host(host)
212
+ payload = raw_output if isinstance(raw_output, dict) else {"output": raw_output}
213
+ source_kind, source_path = _source_metadata(payload)
214
+
215
+ exit_code_raw = payload.get("exit_code", 0)
216
+ try:
217
+ exit_code = int(exit_code_raw)
218
+ except Exception:
219
+ exit_code = 0
220
+
221
+ error = str(payload.get("error", "")).strip()
222
+ status = "error" if error or exit_code != 0 else "ok"
223
+ fallback = str(payload.get("fallback", "")).strip()
224
+ semantic_content = _build_semantic_content(host_name, payload.get("output", ""))
225
+
226
+ normalized = {
227
+ "host": host_name,
228
+ "status": status,
229
+ "exit_code": exit_code,
230
+ "exit_code_class": "success" if exit_code == 0 else "error",
231
+ "fallback": fallback,
232
+ "error": error,
233
+ "error_class": "none" if not error else "provider-error",
234
+ "source_kind": source_kind or "synthetic",
235
+ "source_path": source_path,
236
+ "source_class": "compiled_or_replayed" if not is_synthetic(payload) else "synthetic",
237
+ "semantic": semantic_content,
238
+ }
239
+ return normalized
240
+
241
+ def _is_semantically_equivalent(self, left: dict[str, Any], right: dict[str, Any]) -> tuple[bool, str]:
242
+ if left.get("status") != right.get("status"):
243
+ return False, "status mismatch"
244
+
245
+ left_semantic = left.get("semantic", {}) if isinstance(left.get("semantic"), dict) else {}
246
+ right_semantic = right.get("semantic", {}) if isinstance(right.get("semantic"), dict) else {}
247
+
248
+ left_structured = left_semantic.get("structured")
249
+ right_structured = right_semantic.get("structured")
250
+ if left_structured is not None and right_structured is not None:
251
+ if left_structured == right_structured:
252
+ return True, "structured-equivalent"
253
+ return False, "structured content mismatch"
254
+
255
+ left_tokens = left_semantic.get("text", {}).get("tokens", [])
256
+ right_tokens = right_semantic.get("text", {}).get("tokens", [])
257
+ if isinstance(left_tokens, list) and isinstance(right_tokens, list):
258
+ score = _jaccard_similarity(left_tokens, right_tokens)
259
+ if score >= self.text_similarity_threshold:
260
+ return True, f"text-equivalent score={score:.2f}"
261
+ return False, f"text drift score={score:.2f}"
262
+ return False, "semantic payload mismatch"
263
+
264
+ def check_parity(self, outputs_by_host: dict[str, Any], context: dict[str, Any] | None = None) -> ParityCheckResult:
265
+ host_results: dict[str, dict[str, Any]] = {}
266
+ drift_details: list[str] = []
267
+
268
+ baseline_host = ""
269
+ baseline_output: dict[str, Any] | None = None
270
+
271
+ for host in self.canonical_hosts:
272
+ if host not in outputs_by_host:
273
+ host_results[host] = {
274
+ "present": False,
275
+ "passed": False,
276
+ "reason": "missing host output",
277
+ "normalized": {},
278
+ }
279
+ drift_details.append(f"missing host output: {host}")
280
+ continue
281
+
282
+ raw_payload = outputs_by_host[host]
283
+ payload = raw_payload if isinstance(raw_payload, dict) else {"output": raw_payload}
284
+ normalized = self.normalize_output(host, payload, context)
285
+ if is_synthetic(payload):
286
+ host_results[host] = {
287
+ "present": True,
288
+ "passed": False,
289
+ "reason": "synthetic payload rejected",
290
+ "normalized": normalized,
291
+ }
292
+ drift_details.append(f"synthetic payload rejected: {host}")
293
+ continue
294
+
295
+ host_results[host] = {
296
+ "present": True,
297
+ "passed": True,
298
+ "reason": "baseline",
299
+ "normalized": normalized,
300
+ }
301
+ if baseline_output is None:
302
+ baseline_host = host
303
+ baseline_output = normalized
304
+
305
+ if baseline_output is not None:
306
+ for host in self.canonical_hosts:
307
+ current = host_results.get(host, {})
308
+ if not current.get("present"):
309
+ continue
310
+ if current.get("reason") == "synthetic payload rejected":
311
+ continue
312
+ normalized = current.get("normalized")
313
+ if not isinstance(normalized, dict):
314
+ continue
315
+ equivalent, reason = self._is_semantically_equivalent(baseline_output, normalized)
316
+ current["passed"] = equivalent
317
+ current["reason"] = reason if host != baseline_host else "baseline"
318
+ if not equivalent:
319
+ drift_details.append(f"semantic drift: {host} vs {baseline_host} ({reason})")
320
+
321
+ drift_detected = bool(drift_details)
322
+ passed = not drift_detected and all(
323
+ isinstance(host_results.get(host), dict)
324
+ and bool(host_results[host].get("present"))
325
+ and bool(host_results[host].get("passed"))
326
+ for host in self.canonical_hosts
327
+ )
328
+ return ParityCheckResult(
329
+ passed=passed,
330
+ host_results=host_results,
331
+ drift_detected=drift_detected,
332
+ drift_details=drift_details,
333
+ )
334
+
335
+
336
+ def normalize_output(host: str, raw_output: Any, context: dict[str, Any] | None = None) -> dict[str, Any]:
337
+ return HostParityNormalizer().normalize_output(host, raw_output, context)
338
+
339
+
340
+ def check_parity(outputs_by_host: dict[str, Any], context: dict[str, Any] | None = None) -> ParityCheckResult:
341
+ return HostParityNormalizer().check_parity(outputs_by_host, context)
342
+
343
+
344
+ def emit_parity_report(
345
+ run_id: str,
346
+ results: ParityCheckResult,
347
+ *,
348
+ project_dir: str | None = None,
349
+ ) -> str:
350
+ base_dir = Path(project_dir or os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd()))
351
+ out_path = base_dir / ".omg" / "evidence" / f"host-parity-{run_id}.json"
352
+ out_path.parent.mkdir(parents=True, exist_ok=True)
353
+
354
+ report = HostParityReport(
355
+ run_id=str(run_id),
356
+ timestamp=_now_iso(),
357
+ canonical_hosts=get_canonical_hosts(),
358
+ parity_results=asdict(results),
359
+ overall_status="ok" if results.passed else "drift",
360
+ )
361
+ out_path.write_text(json.dumps(asdict(report), indent=2, ensure_ascii=True) + "\n", encoding="utf-8")
362
+ return str(out_path)
363
+
364
+
365
+ __all__ = [
366
+ "HostParityNormalizer",
367
+ "ParityCheckResult",
368
+ "HostParityReport",
369
+ "is_synthetic",
370
+ "normalize_output",
371
+ "check_parity",
372
+ "emit_parity_report",
373
+ ]