@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,192 @@
1
+ """Mermaid and D2 diagram generator for dependency graphs.
2
+
3
+ Converts adjacency-list dependency graphs (from graph_builder.py) into
4
+ Mermaid and D2 diagram text, with optional PNG rendering via mermaid.ink.
5
+
6
+ All functions are crash-isolated: they return empty strings or False on error,
7
+ never raise exceptions to the caller.
8
+
9
+ Feature-gated behind CODEBASE_VIZ for hook integration, but library functions
10
+ work independently of the flag.
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ import base64
16
+ import urllib.request
17
+ from typing import Any
18
+
19
+ # ---------------------------------------------------------------------------
20
+ # Language → color mapping for Mermaid style directives
21
+ # ---------------------------------------------------------------------------
22
+
23
+ _LANG_COLORS: dict[str, str] = {
24
+ "python": "#4B8BBE",
25
+ "py": "#4B8BBE",
26
+ "js": "#F7DF1E",
27
+ "javascript": "#F7DF1E",
28
+ "ts": "#F7DF1E",
29
+ "typescript": "#F7DF1E",
30
+ "go": "#00ADD8",
31
+ "golang": "#00ADD8",
32
+ }
33
+
34
+
35
+ def _sanitize_node_id(name: str) -> str:
36
+ """Convert a module name to a valid Mermaid/D2 node identifier.
37
+
38
+ Replaces dots and hyphens with underscores to avoid syntax issues.
39
+ """
40
+ return name.replace(".", "_").replace("-", "_")
41
+
42
+
43
+ # ---------------------------------------------------------------------------
44
+ # Mermaid generation
45
+ # ---------------------------------------------------------------------------
46
+
47
+
48
+ def generate_mermaid(
49
+ graph: dict[str, list[str]] | None,
50
+ *,
51
+ zoom: str | None = None,
52
+ language_map: dict[str, str] | None = None,
53
+ ) -> str:
54
+ """Generate Mermaid ``graph TD`` text from an adjacency-list graph.
55
+
56
+ Args:
57
+ graph: Adjacency list ``{module: [dep1, dep2, ...]}``.
58
+ zoom: If provided, return a focused subgraph showing only this
59
+ module and its direct dependencies.
60
+ language_map: Optional mapping of ``{module_name: language}`` for
61
+ color-coding nodes by language.
62
+
63
+ Returns:
64
+ Mermaid diagram text, or empty string on error/empty input.
65
+ """
66
+ try:
67
+ if not isinstance(graph, dict) or not graph:
68
+ return ""
69
+
70
+ # Zoom: filter to only the target module + its direct deps
71
+ if zoom is not None:
72
+ if zoom not in graph:
73
+ return ""
74
+ deps = graph[zoom]
75
+ filtered: dict[str, list[str]] = {zoom: deps}
76
+ for dep in deps:
77
+ if dep in graph:
78
+ # Include dep node but only edges within the zoom scope
79
+ filtered[dep] = []
80
+ else:
81
+ filtered[dep] = []
82
+ graph = filtered
83
+
84
+ lines: list[str] = ["graph TD"]
85
+
86
+ # Collect all unique nodes (both sources and targets)
87
+ all_nodes: set[str] = set()
88
+ for module, deps in graph.items():
89
+ all_nodes.add(module)
90
+ for dep in deps:
91
+ all_nodes.add(dep)
92
+
93
+ # Emit node definitions
94
+ for node in sorted(all_nodes):
95
+ node_id = _sanitize_node_id(node)
96
+ lines.append(f' {node_id}["{node}"]')
97
+
98
+ # Emit edges
99
+ for module in sorted(graph):
100
+ src_id = _sanitize_node_id(module)
101
+ for dep in graph[module]:
102
+ dst_id = _sanitize_node_id(dep)
103
+ lines.append(f" {src_id} --> {dst_id}")
104
+
105
+ # Emit style directives for language color-coding
106
+ if language_map:
107
+ for node in sorted(all_nodes):
108
+ lang = language_map.get(node)
109
+ if lang:
110
+ color = _LANG_COLORS.get(lang.lower())
111
+ if color:
112
+ node_id = _sanitize_node_id(node)
113
+ lines.append(f" style {node_id} fill:{color}")
114
+
115
+ return "\n".join(lines)
116
+
117
+ except Exception:
118
+ return ""
119
+
120
+
121
+ # ---------------------------------------------------------------------------
122
+ # D2 generation
123
+ # ---------------------------------------------------------------------------
124
+
125
+
126
+ def generate_d2(graph: dict[str, list[str]] | None) -> str:
127
+ """Generate D2 diagram text from an adjacency-list graph.
128
+
129
+ Args:
130
+ graph: Adjacency list ``{module: [dep1, dep2, ...]}``.
131
+
132
+ Returns:
133
+ D2 diagram text, or empty string on error/empty input.
134
+ """
135
+ try:
136
+ if not isinstance(graph, dict) or not graph:
137
+ return ""
138
+
139
+ lines: list[str] = []
140
+ emitted_nodes: set[str] = set()
141
+
142
+ for module in sorted(graph):
143
+ deps = graph[module]
144
+ if deps:
145
+ for dep in deps:
146
+ lines.append(f"{module} -> {dep}")
147
+ emitted_nodes.add(module)
148
+ emitted_nodes.add(dep)
149
+ else:
150
+ # Isolated node with no dependencies
151
+ if module not in emitted_nodes:
152
+ lines.append(module)
153
+ emitted_nodes.add(module)
154
+
155
+ return "\n".join(lines)
156
+
157
+ except Exception:
158
+ return ""
159
+
160
+
161
+ # ---------------------------------------------------------------------------
162
+ # PNG rendering via mermaid.ink
163
+ # ---------------------------------------------------------------------------
164
+
165
+
166
+ def render_to_png(
167
+ mermaid_text: str | None,
168
+ output_path: str,
169
+ ) -> bool:
170
+ """Render Mermaid text to a PNG file via the mermaid.ink public API.
171
+
172
+ Constructs URL: ``https://mermaid.ink/img/{base64_encoded}``
173
+ Downloads the PNG using ``urllib.request.urlretrieve``.
174
+
175
+ Args:
176
+ mermaid_text: Valid Mermaid diagram text.
177
+ output_path: File path where the PNG will be saved.
178
+
179
+ Returns:
180
+ True on success, False on any failure (never raises).
181
+ """
182
+ try:
183
+ if not mermaid_text or not isinstance(mermaid_text, str):
184
+ return False
185
+
186
+ encoded = base64.urlsafe_b64encode(mermaid_text.encode()).decode()
187
+ url = f"https://mermaid.ink/img/{encoded}"
188
+ urllib.request.urlretrieve(url, output_path)
189
+ return True
190
+
191
+ except Exception:
192
+ return False
@@ -0,0 +1,444 @@
1
+ """Unified multi-language dependency graph builder.
2
+
3
+ Combines Python AST parser and JS/TS/Go regex parsers into
4
+ a single project-wide dependency graph with metrics and persistence.
5
+
6
+ Feature-gated behind CODEBASE_VIZ (default: off).
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import importlib
12
+ import json
13
+ import os
14
+ import sys
15
+ from pathlib import Path
16
+ from typing import Any
17
+
18
+ # ---------------------------------------------------------------------------
19
+ # Language extension mapping
20
+ # ---------------------------------------------------------------------------
21
+ _PYTHON_EXTS: frozenset[str] = frozenset({".py"})
22
+ _JS_EXTS: frozenset[str] = frozenset({".js", ".jsx", ".ts", ".tsx", ".mjs", ".cjs"})
23
+ _GO_EXTS: frozenset[str] = frozenset({".go"})
24
+
25
+ # ---------------------------------------------------------------------------
26
+ # Lazy parser imports — crash-safe
27
+ # ---------------------------------------------------------------------------
28
+
29
+ _project_root = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
30
+ if _project_root not in sys.path:
31
+ sys.path.insert(0, _project_root)
32
+
33
+
34
+ def _import_parsers() -> tuple[Any, Any]:
35
+ """Import ast_parser and regex_parser lazily. Returns (ast_mod, regex_mod)."""
36
+ try:
37
+ ast_mod = importlib.import_module("plugins.viz.ast_parser")
38
+ except Exception:
39
+ ast_mod = None
40
+ try:
41
+ regex_mod = importlib.import_module("plugins.viz.regex_parser")
42
+ except Exception:
43
+ regex_mod = None
44
+ return ast_mod, regex_mod
45
+
46
+
47
+ def _get_feature_flag(name: str, default: bool = False) -> bool:
48
+ """Get feature flag value, importing hooks._common if available."""
49
+ # Environment variable always takes precedence
50
+ env_key = f"OMG_{name.upper()}_ENABLED"
51
+ env_val = os.environ.get(env_key, "").lower()
52
+ if env_val in ("1", "true", "yes"):
53
+ return True
54
+ if env_val in ("0", "false", "no"):
55
+ return False
56
+ # Try hooks._common
57
+ try:
58
+ _common = importlib.import_module("hooks._common")
59
+ return _common.get_feature_flag(name, default)
60
+ except Exception:
61
+ return default
62
+
63
+
64
+ # ---------------------------------------------------------------------------
65
+ # Module naming
66
+ # ---------------------------------------------------------------------------
67
+
68
+ def _module_name_for_path(root: Path, file_path: Path) -> str:
69
+ """Convert a file path to a dotted module name relative to root."""
70
+ rel = file_path.relative_to(root).with_suffix("")
71
+ parts = list(rel.parts)
72
+ if parts and parts[-1] == "__init__":
73
+ parts = parts[:-1]
74
+ return ".".join(parts) if parts else "__init__"
75
+
76
+
77
+ def _dedupe_preserve_order(values: list[str]) -> list[str]:
78
+ """Deduplicate list while preserving insertion order."""
79
+ seen: set[str] = set()
80
+ ordered: list[str] = []
81
+ for v in values:
82
+ if v not in seen:
83
+ seen.add(v)
84
+ ordered.append(v)
85
+ return ordered
86
+
87
+
88
+ # ---------------------------------------------------------------------------
89
+ # File collection
90
+ # ---------------------------------------------------------------------------
91
+
92
+ def _collect_files(root: Path) -> dict[str, list[Path]]:
93
+ """Collect project files by language category, excluding hidden/venv dirs."""
94
+ result: dict[str, list[Path]] = {"python": [], "js": [], "go": []}
95
+ if not root.is_dir():
96
+ return result
97
+
98
+ skip_dirs = {".omg", ".git", ".venv", "venv", "node_modules", "__pycache__", ".tox"}
99
+
100
+ for item in sorted(root.rglob("*")):
101
+ if not item.is_file():
102
+ continue
103
+ # Skip hidden/venv directories
104
+ rel_parts = item.relative_to(root).parts
105
+ if any(p in skip_dirs or p.startswith(".") for p in rel_parts[:-1]):
106
+ continue
107
+
108
+ ext = item.suffix
109
+ if ext in _PYTHON_EXTS:
110
+ result["python"].append(item)
111
+ elif ext in _JS_EXTS:
112
+ result["js"].append(item)
113
+ elif ext in _GO_EXTS:
114
+ result["go"].append(item)
115
+
116
+ return result
117
+
118
+
119
+ # ---------------------------------------------------------------------------
120
+ # Per-language parsing
121
+ # ---------------------------------------------------------------------------
122
+
123
+ def _parse_python_files(
124
+ root: Path,
125
+ files: list[Path],
126
+ ast_mod: Any,
127
+ cached_graph: dict[str, list[str]],
128
+ cached_mtimes: dict[str, float],
129
+ new_mtimes: dict[str, float],
130
+ ) -> dict[str, list[str]]:
131
+ """Parse Python files into adjacency list entries."""
132
+ graph: dict[str, list[str]] = {}
133
+ if ast_mod is None:
134
+ return graph
135
+
136
+ parse_fn = getattr(ast_mod, "parse_python_imports", None)
137
+ if parse_fn is None:
138
+ return graph
139
+
140
+ for py_file in files:
141
+ module_name = _module_name_for_path(root, py_file)
142
+ rel_key = str(py_file.relative_to(root))
143
+ current_mtime = py_file.stat().st_mtime
144
+
145
+ # Incremental: reuse cached result if mtime unchanged
146
+ if (
147
+ rel_key in cached_mtimes
148
+ and cached_mtimes[rel_key] == current_mtime
149
+ and module_name in cached_graph
150
+ ):
151
+ graph[module_name] = cached_graph[module_name]
152
+ else:
153
+ try:
154
+ imports = parse_fn(str(py_file))
155
+ graph[module_name] = _dedupe_preserve_order(imports)
156
+ except Exception:
157
+ graph[module_name] = []
158
+
159
+ new_mtimes[rel_key] = current_mtime
160
+
161
+ return graph
162
+
163
+
164
+ def _parse_js_files(
165
+ root: Path,
166
+ files: list[Path],
167
+ regex_mod: Any,
168
+ cached_graph: dict[str, list[str]],
169
+ cached_mtimes: dict[str, float],
170
+ new_mtimes: dict[str, float],
171
+ ) -> dict[str, list[str]]:
172
+ """Parse JS/TS files into adjacency list entries."""
173
+ graph: dict[str, list[str]] = {}
174
+ if regex_mod is None:
175
+ return graph
176
+
177
+ parse_fn = getattr(regex_mod, "parse_js_imports", None)
178
+ if parse_fn is None:
179
+ return graph
180
+
181
+ for js_file in files:
182
+ module_name = _module_name_for_path(root, js_file)
183
+ rel_key = str(js_file.relative_to(root))
184
+ current_mtime = js_file.stat().st_mtime
185
+
186
+ if (
187
+ rel_key in cached_mtimes
188
+ and cached_mtimes[rel_key] == current_mtime
189
+ and module_name in cached_graph
190
+ ):
191
+ graph[module_name] = cached_graph[module_name]
192
+ else:
193
+ try:
194
+ result = parse_fn(str(js_file))
195
+ graph[module_name] = _dedupe_preserve_order(result.get("imports", []))
196
+ except Exception:
197
+ graph[module_name] = []
198
+
199
+ new_mtimes[rel_key] = current_mtime
200
+
201
+ return graph
202
+
203
+
204
+ def _parse_go_files(
205
+ root: Path,
206
+ files: list[Path],
207
+ regex_mod: Any,
208
+ cached_graph: dict[str, list[str]],
209
+ cached_mtimes: dict[str, float],
210
+ new_mtimes: dict[str, float],
211
+ ) -> dict[str, list[str]]:
212
+ """Parse Go files into adjacency list entries."""
213
+ graph: dict[str, list[str]] = {}
214
+ if regex_mod is None:
215
+ return graph
216
+
217
+ parse_fn = getattr(regex_mod, "parse_go_imports", None)
218
+ if parse_fn is None:
219
+ return graph
220
+
221
+ for go_file in files:
222
+ module_name = _module_name_for_path(root, go_file)
223
+ rel_key = str(go_file.relative_to(root))
224
+ current_mtime = go_file.stat().st_mtime
225
+
226
+ if (
227
+ rel_key in cached_mtimes
228
+ and cached_mtimes[rel_key] == current_mtime
229
+ and module_name in cached_graph
230
+ ):
231
+ graph[module_name] = cached_graph[module_name]
232
+ else:
233
+ try:
234
+ result = parse_fn(str(go_file))
235
+ graph[module_name] = _dedupe_preserve_order(result.get("imports", []))
236
+ except Exception:
237
+ graph[module_name] = []
238
+
239
+ new_mtimes[rel_key] = current_mtime
240
+
241
+ return graph
242
+
243
+
244
+ # ---------------------------------------------------------------------------
245
+ # Cycle detection (DFS-based)
246
+ # ---------------------------------------------------------------------------
247
+
248
+ def _detect_cycles(graph: dict[str, list[str]]) -> list[list[str]]:
249
+ """Detect circular dependency cycles via DFS."""
250
+ visited: set[str] = set()
251
+ on_stack: set[str] = set()
252
+ stack: list[str] = []
253
+ cycle_set: set[tuple[str, ...]] = set()
254
+
255
+ def dfs(node: str) -> None:
256
+ visited.add(node)
257
+ on_stack.add(node)
258
+ stack.append(node)
259
+
260
+ for nxt in graph.get(node, []):
261
+ if nxt not in graph:
262
+ continue
263
+ if nxt not in visited:
264
+ dfs(nxt)
265
+ elif nxt in on_stack:
266
+ start_idx = stack.index(nxt)
267
+ cycle = stack[start_idx:] + [nxt]
268
+ cycle_set.add(_canonical_cycle(cycle))
269
+
270
+ stack.pop()
271
+ on_stack.remove(node)
272
+
273
+ for module in graph:
274
+ if module not in visited:
275
+ dfs(module)
276
+
277
+ return [list(c) for c in sorted(cycle_set)]
278
+
279
+
280
+ def _canonical_cycle(cycle: list[str]) -> tuple[str, ...]:
281
+ """Normalize a cycle to a canonical rotation for deduplication."""
282
+ core = cycle[:-1]
283
+ if not core:
284
+ return tuple(cycle)
285
+ rotations = [tuple(core[i:] + core[:i]) for i in range(len(core))]
286
+ minimal = min(rotations)
287
+ return minimal + (minimal[0],)
288
+
289
+
290
+ # ---------------------------------------------------------------------------
291
+ # Max depth computation
292
+ # ---------------------------------------------------------------------------
293
+
294
+ def _compute_max_depth(graph: dict[str, list[str]]) -> int:
295
+ """Compute the longest dependency chain depth."""
296
+ def depth(node: str, path: set[str]) -> int:
297
+ best = 0
298
+ for nxt in graph.get(node, []):
299
+ if nxt not in graph or nxt in path:
300
+ continue
301
+ best = max(best, 1 + depth(nxt, path | {nxt}))
302
+ return best
303
+
304
+ best_depth = 0
305
+ for module in graph:
306
+ best_depth = max(best_depth, depth(module, {module}))
307
+ return best_depth
308
+
309
+
310
+ # ---------------------------------------------------------------------------
311
+ # Metrics computation
312
+ # ---------------------------------------------------------------------------
313
+
314
+ def _compute_metrics(graph: dict[str, list[str]], cycles: list[list[str]]) -> dict[str, object]:
315
+ """Compute graph metrics."""
316
+ module_count = len(graph)
317
+ edge_count = sum(len(deps) for deps in graph.values())
318
+ max_depth = _compute_max_depth(graph)
319
+ coupling_score = edge_count / module_count if module_count > 0 else 0.0
320
+
321
+ return {
322
+ "module_count": module_count,
323
+ "edge_count": edge_count,
324
+ "max_depth": max_depth,
325
+ "circular_deps": cycles,
326
+ "coupling_score": coupling_score,
327
+ }
328
+
329
+
330
+ # ---------------------------------------------------------------------------
331
+ # Persistence
332
+ # ---------------------------------------------------------------------------
333
+
334
+ def _load_cached_state(project_dir: Path) -> tuple[dict[str, list[str]], dict[str, float]]:
335
+ """Load previously persisted graph and mtime cache."""
336
+ state_path = project_dir / ".omg" / "state" / "dependency-graph.json"
337
+ if not state_path.exists():
338
+ return {}, {}
339
+ try:
340
+ data = json.loads(state_path.read_text(encoding="utf-8"))
341
+ graph = data.get("graph", {})
342
+ mtimes = data.get("_mtime_cache", {})
343
+ return graph, mtimes
344
+ except Exception:
345
+ return {}, {}
346
+
347
+
348
+ def _persist(project_dir: Path, payload: dict[str, object]) -> None:
349
+ """Save full graph + metrics to .omg/state/dependency-graph.json."""
350
+ try:
351
+ output_path = project_dir / ".omg" / "state" / "dependency-graph.json"
352
+ output_path.parent.mkdir(parents=True, exist_ok=True)
353
+ output_path.write_text(
354
+ json.dumps(payload, indent=2, sort_keys=True),
355
+ encoding="utf-8",
356
+ )
357
+ except Exception:
358
+ pass # Crash isolation: never raise to caller
359
+
360
+
361
+ # ---------------------------------------------------------------------------
362
+ # Public API
363
+ # ---------------------------------------------------------------------------
364
+
365
+ _EMPTY_RESULT: dict[str, object] = {
366
+ "graph": {},
367
+ "metrics": {
368
+ "module_count": 0,
369
+ "edge_count": 0,
370
+ "max_depth": 0,
371
+ "circular_deps": [],
372
+ "coupling_score": 0.0,
373
+ },
374
+ }
375
+
376
+
377
+ def build_project_graph(project_dir: str) -> dict[str, object]:
378
+ """Build unified dependency graph across all detected languages.
379
+
380
+ Combines Python AST parser and JS/TS/Go regex parsers into a single
381
+ adjacency-list graph with computed metrics.
382
+
383
+ Feature-gated behind ``CODEBASE_VIZ`` (default: disabled).
384
+ Supports incremental updates via file mtime tracking.
385
+
386
+ Returns:
387
+ dict with keys ``graph`` (adjacency list) and ``metrics``.
388
+ """
389
+ try:
390
+ # Feature flag gate
391
+ if not _get_feature_flag("CODEBASE_VIZ", default=False):
392
+ return dict(_EMPTY_RESULT)
393
+
394
+ root = Path(project_dir)
395
+ if not root.is_dir():
396
+ return dict(_EMPTY_RESULT)
397
+
398
+ # Load cached state for incremental updates
399
+ cached_graph, cached_mtimes = _load_cached_state(root)
400
+ new_mtimes: dict[str, float] = {}
401
+
402
+ # Import parsers
403
+ ast_mod, regex_mod = _import_parsers()
404
+
405
+ # Collect files by language
406
+ files_by_lang = _collect_files(root)
407
+
408
+ # Parse each language
409
+ unified_graph: dict[str, list[str]] = {}
410
+
411
+ py_graph = _parse_python_files(
412
+ root, files_by_lang["python"], ast_mod, cached_graph, cached_mtimes, new_mtimes
413
+ )
414
+ unified_graph.update(py_graph)
415
+
416
+ js_graph = _parse_js_files(
417
+ root, files_by_lang["js"], regex_mod, cached_graph, cached_mtimes, new_mtimes
418
+ )
419
+ unified_graph.update(js_graph)
420
+
421
+ go_graph = _parse_go_files(
422
+ root, files_by_lang["go"], regex_mod, cached_graph, cached_mtimes, new_mtimes
423
+ )
424
+ unified_graph.update(go_graph)
425
+
426
+ # Compute metrics
427
+ cycles = _detect_cycles(unified_graph)
428
+ metrics = _compute_metrics(unified_graph, cycles)
429
+
430
+ # Build payload
431
+ payload: dict[str, object] = {
432
+ "graph": unified_graph,
433
+ "metrics": metrics,
434
+ "_mtime_cache": new_mtimes,
435
+ }
436
+
437
+ # Persist
438
+ _persist(root, payload)
439
+
440
+ return payload
441
+
442
+ except Exception:
443
+ # Crash isolation: never raise to caller
444
+ return dict(_EMPTY_RESULT)