@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,224 @@
1
+ #!/usr/bin/env python3
2
+ """Hashline Formatter Bridge — reconciles sidecar hash cache after formatters run.
3
+
4
+ When a post-write formatter (e.g. prettier, ruff format) modifies a file,
5
+ the cached line hashes become stale. This bridge detects the change and
6
+ refreshes the sidecar cache so subsequent reads/edits use correct anchors.
7
+
8
+ Feature flag: OMG_HASHLINE_ENABLED (default: False)
9
+ """
10
+ import json
11
+ import os
12
+ import sys
13
+
14
+ HOOKS_DIR = os.path.dirname(__file__)
15
+ if HOOKS_DIR not in sys.path:
16
+ sys.path.insert(0, HOOKS_DIR)
17
+
18
+ from _common import (
19
+ setup_crash_handler,
20
+ json_input,
21
+ get_feature_flag,
22
+ )
23
+
24
+ setup_crash_handler("hashline-formatter-bridge")
25
+
26
+
27
+ # --- Feature Flag ---
28
+
29
+
30
+ def _is_enabled() -> bool:
31
+ """Check if hashline features are enabled.
32
+
33
+ Resolution order: OMG_HASHLINE_ENABLED env var -> settings.json -> False
34
+ """
35
+ env_val = os.environ.get("OMG_HASHLINE_ENABLED", "").lower()
36
+ if env_val in ("1", "true", "yes"):
37
+ return True
38
+ if env_val in ("0", "false", "no"):
39
+ return False
40
+ return get_feature_flag("HASHLINE", default=False)
41
+
42
+
43
+ # --- Lazy Imports from hashline-injector ---
44
+
45
+ _injector = None
46
+
47
+
48
+ def _get_injector():
49
+ """Lazy-load hashline-injector module."""
50
+ global _injector
51
+ if _injector is None:
52
+ import importlib
53
+ _injector = importlib.import_module("hashline-injector")
54
+ return _injector
55
+
56
+
57
+ # --- Core Functions ---
58
+
59
+
60
+ def detect_formatter_change(file_path: str, original_content: str, formatted_content: str) -> bool:
61
+ """Return True if the formatter changed the content.
62
+
63
+ Compares stripped versions of each line to ignore trivial
64
+ trailing-whitespace-only differences while still detecting
65
+ real structural changes.
66
+
67
+ Args:
68
+ file_path: Path to the file (for context, not read).
69
+ original_content: Content before formatting.
70
+ formatted_content: Content after formatting.
71
+
72
+ Returns:
73
+ True if formatted_content differs from original_content.
74
+ """
75
+ if original_content == formatted_content:
76
+ return False
77
+
78
+ # Compare stripped lines to ignore trivial whitespace diffs
79
+ orig_lines = [l.rstrip() for l in original_content.split("\n")]
80
+ fmt_lines = [l.rstrip() for l in formatted_content.split("\n")]
81
+ return orig_lines != fmt_lines
82
+
83
+
84
+ def refresh_cache_after_format(file_path: str, formatted_content: str) -> bool:
85
+ """Recompute and save line hashes for newly formatted content.
86
+
87
+ Args:
88
+ file_path: Path to the formatted file.
89
+ formatted_content: The file content after formatting.
90
+
91
+ Returns:
92
+ True on success (or when feature is disabled), False on error.
93
+ """
94
+ if not _is_enabled():
95
+ return True
96
+
97
+ try:
98
+ injector = _get_injector()
99
+ _line_hash_id = injector._line_hash_id
100
+ _cache_hashes = injector._cache_hashes
101
+ except Exception:
102
+ return False
103
+
104
+ try:
105
+ lines = formatted_content.split("\n")
106
+ line_hashes = {}
107
+ for i, line in enumerate(lines, start=1):
108
+ line_hashes[str(i)] = _line_hash_id(line)
109
+
110
+ _cache_hashes(file_path, line_hashes)
111
+ return True
112
+ except Exception:
113
+ return False
114
+
115
+
116
+ def reconcile_post_format(file_path: str) -> dict:
117
+ """Reconcile hash cache with the current file on disk.
118
+
119
+ Reads the file, checks whether the cached mtime is stale
120
+ (indicating a formatter ran after the last cache write),
121
+ and refreshes the cache if needed.
122
+
123
+ Args:
124
+ file_path: Path to the file to reconcile.
125
+
126
+ Returns:
127
+ dict with reconciliation result:
128
+ - ``{"skipped": True}`` when feature is disabled
129
+ - ``{"refreshed": True/False, "lines_updated": int, "file": str}``
130
+ """
131
+ if not _is_enabled():
132
+ return {"skipped": True}
133
+
134
+ try:
135
+ injector = _get_injector()
136
+ _get_cached_hashes = injector._get_cached_hashes
137
+ _line_hash_id = injector._line_hash_id
138
+ _cache_hashes = injector._cache_hashes
139
+ except Exception:
140
+ return {"refreshed": False, "lines_updated": 0, "file": file_path}
141
+
142
+ try:
143
+ abs_path = os.path.abspath(file_path)
144
+ if not os.path.exists(abs_path):
145
+ return {"refreshed": False, "lines_updated": 0, "file": file_path}
146
+
147
+ # Read current content from disk
148
+ with open(abs_path, "r", encoding="utf-8", errors="replace") as f:
149
+ content = f.read()
150
+
151
+ # Check if cache exists — if _get_cached_hashes returns None,
152
+ # cache is either missing or mtime doesn't match (formatter ran).
153
+ cached = _get_cached_hashes(file_path)
154
+ if cached is not None:
155
+ # Cache is still valid (mtime matches) — no refresh needed
156
+ return {"refreshed": False, "lines_updated": 0, "file": file_path}
157
+
158
+ # Cache is stale or missing — refresh
159
+ lines = content.split("\n")
160
+ line_hashes = {}
161
+ for i, line in enumerate(lines, start=1):
162
+ line_hashes[str(i)] = _line_hash_id(line)
163
+
164
+ _cache_hashes(file_path, line_hashes)
165
+ return {"refreshed": True, "lines_updated": len(lines), "file": file_path}
166
+ except Exception:
167
+ return {"refreshed": False, "lines_updated": 0, "file": file_path}
168
+
169
+
170
+ # --- Write-tool names that trigger reconciliation ---
171
+
172
+ _WRITE_TOOLS = frozenset({
173
+ "Write", "Edit", "MultiEdit",
174
+ "mcp__filesystem__write_file",
175
+ "mcp__filesystem__edit_file",
176
+ })
177
+
178
+
179
+ # --- Hook Entry Point ---
180
+
181
+
182
+ def main():
183
+ """PostToolUse hook stdin/stdout entry point.
184
+
185
+ Reads JSON from stdin::
186
+
187
+ {"tool_name": "Write", "tool_input": {"file_path": "..."}}
188
+
189
+ If tool_name is a write tool and OMG_HASHLINE_ENABLED is set,
190
+ runs ``reconcile_post_format`` to refresh the hash cache after
191
+ any post-write formatter may have modified the file.
192
+
193
+ Always exits 0 — never raises.
194
+ """
195
+ if not _is_enabled():
196
+ sys.exit(0)
197
+
198
+ data = json_input()
199
+ if not isinstance(data, dict):
200
+ sys.exit(0)
201
+
202
+ tool_name = data.get("tool_name", "")
203
+ if tool_name not in _WRITE_TOOLS:
204
+ sys.exit(0)
205
+
206
+ tool_input = data.get("tool_input", {})
207
+ if not isinstance(tool_input, dict):
208
+ sys.exit(0)
209
+
210
+ file_path = tool_input.get("file_path", tool_input.get("filePath", ""))
211
+ if not file_path:
212
+ sys.exit(0)
213
+
214
+ try:
215
+ result = reconcile_post_format(file_path)
216
+ json.dump(result, sys.stdout)
217
+ except Exception:
218
+ pass # Graceful degradation — never crash
219
+
220
+ sys.exit(0)
221
+
222
+
223
+ if __name__ == "__main__":
224
+ main()
@@ -0,0 +1,273 @@
1
+ #!/usr/bin/env python3
2
+ """Hashline Injector — injects content-hash anchors into file content on read.
3
+
4
+ Each line gets a tag: `{line_number}#{2-char-id}|{original line}`
5
+ where the 2-char ID is derived from SHA-256 of the line content mapped to
6
+ the charset ZPMQVRWSNKTXJBYH (16 chars, 4-bit nibbles of first hash byte).
7
+
8
+ Uses a sidecar cache at `.omg/state/hashline_cache.json` to avoid
9
+ regenerating hashes for unchanged files. Never modifies original files.
10
+
11
+ Feature flag: OMG_HASHLINE_ENABLED (default: False)
12
+ """
13
+ import hashlib
14
+ import json
15
+ import os
16
+ import re
17
+ import sys
18
+ import time
19
+
20
+ HOOKS_DIR = os.path.dirname(__file__)
21
+ if HOOKS_DIR not in sys.path:
22
+ sys.path.insert(0, HOOKS_DIR)
23
+
24
+ from _common import (
25
+ setup_crash_handler,
26
+ json_input,
27
+ get_feature_flag,
28
+ get_project_dir,
29
+ atomic_json_write,
30
+ )
31
+
32
+ setup_crash_handler("hashline-injector")
33
+
34
+ # --- Constants ---
35
+
36
+ # 16-char charset for 4-bit nibble mapping
37
+ HASH_CHARSET = "ZPMQVRWSNKTXJBYH"
38
+
39
+ # Regex to strip hashline prefix: digits + # + 2 uppercase letters + |
40
+ _HASHLINE_RE = re.compile(r"^\d+#[A-Z]{2}\|")
41
+
42
+ # Sidecar cache path (relative to project dir)
43
+ _CACHE_REL_PATH = os.path.join(".omg", "state", "hashline_cache.json")
44
+
45
+
46
+ # --- Core Functions ---
47
+
48
+
49
+ def _line_hash_id(line: str) -> str:
50
+ """Generate 2-char hash ID from line content.
51
+
52
+ Takes first byte of SHA-256 digest, splits into two 4-bit nibbles,
53
+ maps each nibble to HASH_CHARSET.
54
+ """
55
+ digest = hashlib.sha256(line.encode("utf-8", errors="replace")).digest()
56
+ first_byte = digest[0]
57
+ high_nibble = (first_byte >> 4) & 0x0F
58
+ low_nibble = first_byte & 0x0F
59
+ return HASH_CHARSET[high_nibble] + HASH_CHARSET[low_nibble]
60
+
61
+
62
+ def inject_hashlines(content: str, file_path: str = None) -> str:
63
+ """Add hash anchors to each line of content.
64
+
65
+ Format: `{line_num}#{hash_id}|{original_line}` (1-indexed)
66
+
67
+ Args:
68
+ content: File content string
69
+ file_path: Optional file path for caching. If provided and the file
70
+ exists, hashes are cached to `.omg/state/hashline_cache.json`.
71
+
72
+ Returns:
73
+ Content with hash anchors prepended to each line.
74
+ Returns content unchanged if OMG_HASHLINE_ENABLED is False.
75
+ """
76
+ if not _is_enabled():
77
+ return content
78
+
79
+ # Check cache first
80
+ if file_path:
81
+ cached = _get_cached_hashes(file_path)
82
+ if cached is not None:
83
+ return _apply_cached_hashes(content, cached)
84
+
85
+ lines = content.split("\n")
86
+ result = []
87
+ line_hashes = {}
88
+
89
+ for i, line in enumerate(lines, start=1):
90
+ hash_id = _line_hash_id(line)
91
+ line_hashes[str(i)] = hash_id
92
+ result.append(f"{i}#{hash_id}|{line}")
93
+
94
+ # Cache if file_path provided
95
+ if file_path:
96
+ _cache_hashes(file_path, line_hashes)
97
+
98
+ return "\n".join(result)
99
+
100
+
101
+ def strip_hashlines(content: str) -> str:
102
+ """Remove hash anchors from content, restoring original text.
103
+
104
+ Strips `^\\d+#[A-Z]{2}\\|` prefix from each line.
105
+
106
+ Args:
107
+ content: Content with hash anchors
108
+
109
+ Returns:
110
+ Original content without hash anchors.
111
+ """
112
+ lines = content.split("\n")
113
+ result = []
114
+ for line in lines:
115
+ result.append(_HASHLINE_RE.sub("", line))
116
+ return "\n".join(result)
117
+
118
+
119
+ def _apply_cached_hashes(content: str, line_hashes: dict) -> str:
120
+ """Apply cached hash IDs to content lines."""
121
+ lines = content.split("\n")
122
+ result = []
123
+ for i, line in enumerate(lines, start=1):
124
+ hash_id = line_hashes.get(str(i))
125
+ if hash_id is None:
126
+ # Line count changed — cache is stale, regenerate
127
+ hash_id = _line_hash_id(line)
128
+ result.append(f"{i}#{hash_id}|{line}")
129
+ return "\n".join(result)
130
+
131
+
132
+ # --- Sidecar Cache ---
133
+
134
+
135
+ def _get_cache_path() -> str:
136
+ """Get absolute path to hashline cache file."""
137
+ return os.path.join(get_project_dir(), _CACHE_REL_PATH)
138
+
139
+
140
+ def _load_cache() -> dict:
141
+ """Load the entire hashline cache from disk. Returns empty dict on failure."""
142
+ cache_path = _get_cache_path()
143
+ try:
144
+ if not os.path.exists(cache_path):
145
+ return {}
146
+ with open(cache_path, "r", encoding="utf-8") as f:
147
+ return json.load(f)
148
+ except Exception:
149
+ return {}
150
+
151
+
152
+ def _get_cached_hashes(file_path: str):
153
+ """Get cached line hashes for a file, if still valid.
154
+
155
+ Args:
156
+ file_path: Path to the source file
157
+
158
+ Returns:
159
+ dict mapping line number (str) -> hash_id, or None if not cached
160
+ or if the file's mtime has changed (cache invalidation).
161
+ """
162
+ try:
163
+ abs_path = os.path.abspath(file_path)
164
+ if not os.path.exists(abs_path):
165
+ return None
166
+
167
+ cache = _load_cache()
168
+ entry = cache.get(abs_path)
169
+ if entry is None:
170
+ return None
171
+
172
+ # Check mtime for invalidation
173
+ current_mtime = os.path.getmtime(abs_path)
174
+ cached_mtime = entry.get("mtime", 0)
175
+ if abs(current_mtime - cached_mtime) > 0.001:
176
+ return None
177
+
178
+ return entry.get("line_hashes")
179
+ except Exception:
180
+ return None
181
+
182
+
183
+ def _cache_hashes(file_path: str, line_hashes: dict) -> None:
184
+ """Save line hashes to sidecar cache with mtime for invalidation.
185
+
186
+ Args:
187
+ file_path: Path to the source file
188
+ line_hashes: dict mapping line number (str) -> hash_id
189
+ """
190
+ try:
191
+ abs_path = os.path.abspath(file_path)
192
+ cache = _load_cache()
193
+
194
+ mtime = 0.0
195
+ if os.path.exists(abs_path):
196
+ mtime = os.path.getmtime(abs_path)
197
+
198
+ cache[abs_path] = {
199
+ "mtime": mtime,
200
+ "line_hashes": line_hashes,
201
+ }
202
+
203
+ atomic_json_write(_get_cache_path(), cache)
204
+ except Exception:
205
+ pass # Never crash on cache write failure
206
+
207
+
208
+ # --- Feature Flag ---
209
+
210
+
211
+ def _is_enabled() -> bool:
212
+ """Check if hashline injection is enabled.
213
+
214
+ Resolution order: OMG_HASHLINE_ENABLED env var → settings.json → False
215
+ """
216
+ # Fast path: check env var directly
217
+ env_val = os.environ.get("OMG_HASHLINE_ENABLED", "").lower()
218
+ if env_val in ("1", "true", "yes"):
219
+ return True
220
+ if env_val in ("0", "false", "no"):
221
+ return False
222
+ # Slow path: check settings.json via get_feature_flag
223
+ return get_feature_flag("HASHLINE", default=False)
224
+
225
+
226
+ # --- Hook Entry Point ---
227
+
228
+
229
+ def main():
230
+ """Hook stdin/stdout entry point for Claude Code PreToolUse hooks.
231
+
232
+ Reads JSON from stdin with tool_input containing file content.
233
+ If hashline injection is enabled and tool is a file read, injects
234
+ hash anchors into the content.
235
+ Writes modified tool input back to stdout.
236
+ Always exits 0 — never raises.
237
+ """
238
+ if not _is_enabled():
239
+ sys.exit(0)
240
+
241
+ data = json_input()
242
+ if not isinstance(data, dict):
243
+ sys.exit(0)
244
+
245
+ # Only inject for file-read tools
246
+ tool_name = data.get("tool_name", "")
247
+ if tool_name not in ("Read", "mcp__filesystem__read_file",
248
+ "mcp__filesystem__read_text_file"):
249
+ sys.exit(0)
250
+
251
+ tool_input = data.get("tool_input", {})
252
+ if not isinstance(tool_input, dict):
253
+ sys.exit(0)
254
+
255
+ content = tool_input.get("content", "")
256
+ file_path = tool_input.get("file_path", tool_input.get("filePath", ""))
257
+
258
+ if not content:
259
+ sys.exit(0)
260
+
261
+ try:
262
+ injected = inject_hashlines(content, file_path or None)
263
+ tool_input["content"] = injected
264
+ data["tool_input"] = tool_input
265
+ json.dump(data, sys.stdout)
266
+ except Exception:
267
+ pass # Graceful degradation — never crash
268
+
269
+ sys.exit(0)
270
+
271
+
272
+ if __name__ == "__main__":
273
+ main()
@@ -0,0 +1,216 @@
1
+ #!/usr/bin/env python3
2
+ """Hashline Validator — validates edit targets against stored hash anchors.
3
+
4
+ Validates that ``line_ref`` (e.g. ``"11#VK"``) matches the cached hash for
5
+ that line before allowing an edit. Rejects mismatched edits with a clear
6
+ error dict. Updates cache after successful edits.
7
+
8
+ Feature flag: OMG_HASHLINE_ENABLED (default: False)
9
+ """
10
+ import json
11
+ import os
12
+ import re
13
+ import sys
14
+
15
+ HOOKS_DIR = os.path.dirname(__file__)
16
+ if HOOKS_DIR not in sys.path:
17
+ sys.path.insert(0, HOOKS_DIR)
18
+
19
+ from _common import (
20
+ setup_crash_handler,
21
+ json_input,
22
+ get_feature_flag,
23
+ )
24
+
25
+ setup_crash_handler("hashline-validator")
26
+
27
+ # --- Constants ---
28
+
29
+ # Valid line_ref: digits + # + exactly 2 chars from HASH_CHARSET
30
+ _LINE_REF_RE = re.compile(r"^\d+#[ZPMQVRWSNKTXJBYH]{2}$")
31
+
32
+
33
+ # --- Feature Flag ---
34
+
35
+
36
+ def _is_enabled() -> bool:
37
+ """Check if hashline validation is enabled.
38
+
39
+ Resolution order: OMG_HASHLINE_ENABLED env var → settings.json → False
40
+ """
41
+ env_val = os.environ.get("OMG_HASHLINE_ENABLED", "").lower()
42
+ if env_val in ("1", "true", "yes"):
43
+ return True
44
+ if env_val in ("0", "false", "no"):
45
+ return False
46
+ return get_feature_flag("HASHLINE", default=False)
47
+
48
+
49
+ # --- Lazy Imports from hashline-injector ---
50
+
51
+ _injector = None
52
+
53
+
54
+ def _get_injector():
55
+ """Lazy-load hashline-injector module."""
56
+ global _injector
57
+ if _injector is None:
58
+ import importlib
59
+ _injector = importlib.import_module("hashline-injector")
60
+ return _injector
61
+
62
+
63
+ # --- Core Functions ---
64
+
65
+
66
+ def validate_line_ref_format(line_ref: str) -> bool:
67
+ """Return True if *line_ref* matches ``'{line_num}#{2-char hash_id}'``.
68
+
69
+ Hash ID characters must belong to the charset ``ZPMQVRWSNKTXJBYH``.
70
+
71
+ Args:
72
+ line_ref: Line reference string (e.g. ``"11#VK"``)
73
+
74
+ Returns:
75
+ True if format is valid, False otherwise.
76
+ """
77
+ if not isinstance(line_ref, str):
78
+ return False
79
+ return bool(_LINE_REF_RE.match(line_ref))
80
+
81
+
82
+ def validate_edit(file_path: str, line_ref: str, expected_line: str) -> dict:
83
+ """Validate a hash anchor before allowing an edit.
84
+
85
+ Args:
86
+ file_path: Path to the file being edited.
87
+ line_ref: Line reference ``"{line_num}#{hash_id}"`` (e.g. ``"11#VK"``).
88
+ expected_line: The expected content of the line (context, not used
89
+ for hash matching itself).
90
+
91
+ Returns:
92
+ dict with validation result — always contains ``"valid"`` key:
93
+
94
+ * Feature disabled → ``{"valid": True, "skipped": True}``
95
+ * No cache available → ``{"valid": True, "uncached": True}``
96
+ * Hash match → ``{"valid": True, "line": <int>}``
97
+ * Hash mismatch → ``{"valid": False, "error": "HASH_MISMATCH",
98
+ "line": <int>, "expected": <str>, "actual": <str>}``
99
+ * Bad format → ``{"valid": False, "error": "INVALID_LINE_REF",
100
+ "line_ref": <str>}``
101
+ """
102
+ # Skip when disabled
103
+ if not _is_enabled():
104
+ return {"valid": True, "skipped": True}
105
+
106
+ # Validate format
107
+ if not validate_line_ref_format(line_ref):
108
+ return {"valid": False, "error": "INVALID_LINE_REF", "line_ref": line_ref}
109
+
110
+ # Parse line_ref
111
+ parts = line_ref.split("#")
112
+ line_num = int(parts[0])
113
+ hash_id = parts[1]
114
+
115
+ # Load cache via injector
116
+ try:
117
+ injector = _get_injector()
118
+ cached_hashes = injector._get_cached_hashes(file_path)
119
+ except Exception:
120
+ # Injector unavailable — cannot validate
121
+ return {"valid": True, "uncached": True}
122
+
123
+ if cached_hashes is None:
124
+ return {"valid": True, "uncached": True}
125
+
126
+ # Look up the line in the cache
127
+ stored_hash = cached_hashes.get(str(line_num))
128
+ if stored_hash is None:
129
+ # Line number not in cache (file may have grown since last cache)
130
+ return {"valid": True, "uncached": True}
131
+
132
+ # Compare
133
+ if stored_hash != hash_id:
134
+ return {
135
+ "valid": False,
136
+ "error": "HASH_MISMATCH",
137
+ "line": line_num,
138
+ "expected": hash_id,
139
+ "actual": stored_hash,
140
+ }
141
+
142
+ return {"valid": True, "line": line_num}
143
+
144
+
145
+ def update_hashes_after_edit(file_path: str, new_content: str) -> bool:
146
+ """Refresh the hash cache after a successful edit.
147
+
148
+ Re-generates line hashes for *new_content* and updates the sidecar
149
+ cache (``hashline_cache.json``) for *file_path*.
150
+
151
+ Args:
152
+ file_path: Path to the edited file.
153
+ new_content: The file content after the edit.
154
+
155
+ Returns:
156
+ True on success (or when disabled), False on error.
157
+ """
158
+ if not _is_enabled():
159
+ return True
160
+
161
+ try:
162
+ injector = _get_injector()
163
+ _line_hash_id = injector._line_hash_id
164
+ _cache_hashes = injector._cache_hashes
165
+ except Exception:
166
+ return False
167
+
168
+ try:
169
+ lines = new_content.split("\n")
170
+ line_hashes = {}
171
+ for i, line in enumerate(lines, start=1):
172
+ line_hashes[str(i)] = _line_hash_id(line)
173
+
174
+ _cache_hashes(file_path, line_hashes)
175
+ return True
176
+ except Exception:
177
+ return False
178
+
179
+
180
+ # --- Hook Entry Point ---
181
+
182
+
183
+ def main():
184
+ """Hook stdin/stdout entry point.
185
+
186
+ Reads JSON from stdin::
187
+
188
+ {"file_path": "...", "line_ref": "11#VK", "expected_line": "..."}
189
+
190
+ Calls :func:`validate_edit` and writes the result dict to stdout.
191
+ Always exits 0 — never raises.
192
+ """
193
+ if not _is_enabled():
194
+ json.dump({"valid": True, "skipped": True}, sys.stdout)
195
+ sys.exit(0)
196
+
197
+ data = json_input()
198
+ if not isinstance(data, dict):
199
+ json.dump({"valid": False, "error": "INVALID_INPUT"}, sys.stdout)
200
+ sys.exit(0)
201
+
202
+ file_path = data.get("file_path", "")
203
+ line_ref = data.get("line_ref", "")
204
+ expected_line = data.get("expected_line", "")
205
+
206
+ try:
207
+ result = validate_edit(file_path, line_ref, expected_line)
208
+ json.dump(result, sys.stdout)
209
+ except Exception:
210
+ json.dump({"valid": False, "error": "INTERNAL_ERROR"}, sys.stdout)
211
+
212
+ sys.exit(0)
213
+
214
+
215
+ if __name__ == "__main__":
216
+ main()