@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,879 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ UserPromptSubmit Hook — OMG v1
4
+
5
+ Inspired by earlier OMG routing experiments. Key upgrades:
6
+ 1. Intent classification BEFORE acting (IntentGate)
7
+ 2. Discipline enforcement — never stop halfway
8
+ 3. Agent-aware routing — Codex/Gemini/Claude orchestration
9
+ 4. Anti-hallucination protocol
10
+ 5. Error loop prevention (circuit-breaker awareness)
11
+ 6. Vision/screenshot auto-detection
12
+ 7. DDD/Security domain auto-triggers
13
+ 8. Context budget: MAX 800 chars output
14
+
15
+ No dependency on CLAUDE.md or AGENTS.md.
16
+ """
17
+ from __future__ import annotations
18
+
19
+ import hashlib
20
+ import json, sys, os, re, time
21
+ from datetime import datetime, timezone
22
+ import importlib
23
+ from pathlib import Path
24
+
25
+ HOOKS_DIR = str(Path(__file__).resolve().parent)
26
+ _PROJECT_ROOT = str(Path(HOOKS_DIR).parent)
27
+ _PORTABLE_RUNTIME_ROOT = str(Path(_PROJECT_ROOT) / "omg-runtime")
28
+ for path in (HOOKS_DIR, _PROJECT_ROOT, _PORTABLE_RUNTIME_ROOT):
29
+ if path not in sys.path:
30
+ sys.path.insert(0, path)
31
+
32
+ try:
33
+ from runtime.complexity_scorer import score_complexity
34
+ except ImportError:
35
+ score_complexity = None
36
+
37
+ try:
38
+ from hooks._common import setup_crash_handler, json_input, atomic_json_write, get_feature_flag, _resolve_project_dir
39
+ from hooks.state_migration import resolve_state_dir
40
+ from hooks._budget import BUDGET_PROMPT_TOTAL as budget_prompt_total
41
+ from hooks.context_pressure import estimate_context_pressure
42
+ except ImportError:
43
+ _common = importlib.import_module("_common")
44
+ _state_migration = importlib.import_module("state_migration")
45
+ _budget = importlib.import_module("_budget")
46
+ _context_pressure = importlib.import_module("context_pressure")
47
+ setup_crash_handler = _common.setup_crash_handler
48
+ json_input = _common.json_input
49
+ atomic_json_write = _common.atomic_json_write
50
+ get_feature_flag = _common.get_feature_flag
51
+ _resolve_project_dir = _common._resolve_project_dir
52
+ resolve_state_dir = _state_migration.resolve_state_dir
53
+ budget_prompt_total = _budget.BUDGET_PROMPT_TOTAL
54
+ estimate_context_pressure = _context_pressure.estimate_context_pressure
55
+
56
+ BUDGET_PROMPT_TOTAL = budget_prompt_total
57
+
58
+ setup_crash_handler("prompt-enhancer", fail_closed=False)
59
+
60
+ data = json_input()
61
+
62
+ prompt = data.get("tool_input", {}).get("user_message", "") or data.get("user_message", "")
63
+ if not prompt:
64
+ sys.exit(0)
65
+
66
+ prompt_lower = prompt.lower().strip()
67
+ project_dir = _resolve_project_dir()
68
+ omg_root = os.path.join(project_dir, ".omg")
69
+ state_dir = resolve_state_dir(project_dir, "state", "")
70
+ knowledge_dir = resolve_state_dir(project_dir, "knowledge", "knowledge")
71
+ injections = []
72
+
73
+ # ── Context budget ──
74
+ MAX_CHARS = BUDGET_PROMPT_TOTAL
75
+
76
+ def budget_ok():
77
+ return sum(len(i) for i in injections) < MAX_CHARS
78
+
79
+ def add(text):
80
+ remaining = MAX_CHARS - sum(len(i) for i in injections)
81
+ if remaining <= 20:
82
+ return
83
+ if len(text) > remaining:
84
+ text = text[:remaining - 3] + "..."
85
+ injections.append(text)
86
+
87
+
88
+ def signal_matches_text(signal, text):
89
+ if re.search(r'[\uac00-\ud7a3]', signal):
90
+ return signal in text
91
+ return re.search(r'\b' + re.escape(signal) + r'\b', text, re.IGNORECASE) is not None
92
+
93
+
94
+ def _hash_prompt(value):
95
+ return hashlib.sha256(value.encode("utf-8")).hexdigest()
96
+
97
+
98
+ def _single_line(text, max_chars=220):
99
+ line = " ".join(str(text).replace("\r", " ").replace("\n", " ").split())
100
+ if len(line) > max_chars:
101
+ return line[: max_chars - 3] + "..."
102
+ return line
103
+
104
+
105
+ def _resolve_run_id(payload, prompt_hash):
106
+ if isinstance(payload, dict):
107
+ run_id = payload.get("run_id")
108
+ if isinstance(run_id, str) and run_id.strip():
109
+ return run_id.strip()
110
+ tool_input = payload.get("tool_input")
111
+ if isinstance(tool_input, dict):
112
+ metadata = tool_input.get("metadata")
113
+ if isinstance(metadata, dict):
114
+ metadata_run_id = metadata.get("run_id")
115
+ if isinstance(metadata_run_id, str) and metadata_run_id.strip():
116
+ return metadata_run_id.strip()
117
+ env_run_id = os.environ.get("OMG_RUN_ID", "").strip()
118
+ if env_run_id:
119
+ return env_run_id
120
+ return prompt_hash[:24]
121
+
122
+
123
+ def _count_signals(signals, text):
124
+ return sum(1 for sig in signals if signal_matches_text(sig, text))
125
+
126
+
127
+ def _write_intent_gate_artifact(state_root, run_id, artifact):
128
+ state_path = os.path.join(state_root, "intent_gate", f"{run_id}.json")
129
+ os.makedirs(os.path.dirname(state_path), exist_ok=True)
130
+ tmp_path = f"{state_path}.tmp"
131
+ with open(tmp_path, "w", encoding="utf-8") as tmp_file:
132
+ json.dump(artifact, tmp_file, indent=2, ensure_ascii=True)
133
+ os.replace(tmp_path, state_path)
134
+
135
+ # ── Zero-injection optimization ──
136
+ # Simple prompts (≤10 words, no coding/mode/routing signals) get zero overhead
137
+ _word_count_early = len(prompt_lower.split())
138
+ _has_any_signal = any([
139
+ any(signal_matches_text(sig, prompt) for sig in ["fix","bug","implement","build","create","refactor",
140
+ "review","auth","css","layout","ui","ux","test",
141
+ "stuck","error","crash","ralph","ulw","crazy",
142
+ "plan","design","search","find","research","explain",
143
+ "codex","gemini","ccg","screenshot","screen",
144
+ "security","warning","hook error","resume","handoff",
145
+ "continue","domain","scaffold","debug","deploy",
146
+ "setup","credential","credentials","preference",
147
+ "preferences","remember","settings","memory",
148
+ "수정","구현","버그","에러","고쳐","스크린샷","보안"]),
149
+ _word_count_early > 10,
150
+ ])
151
+ if not _has_any_signal:
152
+ sys.exit(0)
153
+ # ═══════════════════════════════════════════════════════════
154
+ # 1. INTENT CLASSIFICATION (IntentGate)
155
+ # ═══════════════════════════════════════════════════════════
156
+ INTENT_MAP = {
157
+ "fix": {
158
+ "signals": ["fix", "bug", "error", "broken", "crash", "not working", "fails",
159
+ "수정", "버그", "에러", "고쳐", "고치", "안돼", "안됨", "깨짐", "오류"],
160
+ "directive": "FIX — Debug root cause, patch source code (NOT tests), verify with evidence"
161
+ },
162
+ "plan": {
163
+ "signals": ["plan", "design", "architect", "strategy",
164
+ "계획", "설계", "아키텍처", "전략"],
165
+ "directive": "PLAN — Ask clarifying questions. Map domain. Plan before code"
166
+ },
167
+ "refactor": {
168
+ "signals": ["refactor", "clean", "optimize", "improve", "simplify",
169
+ "리팩토링", "리팩터", "최적화", "개선", "정리"],
170
+ "directive": "REFACTOR — Preserve behavior. Before AND after tests must pass"
171
+ },
172
+ "review": {
173
+ "signals": ["review", "check", "audit", "inspect", "look at",
174
+ "리뷰", "검토", "확인", "감사", "점검"],
175
+ "directive": "REVIEW — Read ALL code first. Report findings. Don't change unless asked"
176
+ },
177
+ "research": {
178
+ "signals": ["research", "find", "search", "how to", "what is", "explain",
179
+ "검색", "찾아", "어떻게", "설명", "문서"],
180
+ "directive": "RESEARCH — Search, synthesize, report. Use web_search if needed"
181
+ },
182
+ "implement": {
183
+ "signals": ["implement", "build", "create", "add", "make", "feature", "new",
184
+ "구현", "빌드", "생성", "만들", "추가", "기능", "개발"],
185
+ "directive": "IMPLEMENT — Plan → code → test → verify. Follow existing patterns"
186
+ },
187
+ "auth_setup": {
188
+ "signals": ["auth", "login", "credential", "credentials", "oauth", "token", "setup auth",
189
+ "setup credential", "set up credential", "인증", "로그인", "자격 증명", "토큰"],
190
+ "directive": "AUTH_SETUP — Clarify auth target and credential source before changes"
191
+ },
192
+ "preference_memory": {
193
+ "signals": ["remember my settings", "remember settings", "preference", "preferences", "settings",
194
+ "memory style", "save my setup", "기억", "설정", "선호"],
195
+ "directive": "PREFERENCE_MEMORY — Clarify scope and persistence policy before changes"
196
+ },
197
+ "ambiguous_config": {
198
+ "signals": ["setup", "configure", "config", "remember", "save", "setup my", "set up",
199
+ "설정해", "구성", "저장"],
200
+ "directive": "AMBIGUOUS_CONFIG — Ask one-line clarification before any implementation"
201
+ },
202
+ }
203
+
204
+ IMPLEMENTATION_ACTION_SIGNALS = [
205
+ "implement", "build", "create", "add", "fix", "refactor", "update", "write", "code",
206
+ "debug", "test", "migrate", "deploy", "patch", "change", "구현", "추가", "수정", "개발",
207
+ ]
208
+ AUTH_PROVIDER_SIGNALS = [
209
+ "codex", "claude", "gemini", "github", "google", "openai", "provider", "service", "cli",
210
+ ]
211
+ AUTH_SOURCE_SIGNALS = [
212
+ "env", "token", "key", "secret", "credential", "password", "vault", "profile", "yaml",
213
+ ]
214
+ PREFERENCE_SCOPE_SIGNALS = ["session", "project", "global", "default", "always", "workspace", "local"]
215
+
216
+
217
+ def _build_intent_gate_state(prompt_text, payload):
218
+ has_auth = _count_signals(INTENT_MAP["auth_setup"]["signals"], prompt_text) > 0
219
+ has_pref = _count_signals(INTENT_MAP["preference_memory"]["signals"], prompt_text) > 0
220
+ has_ambiguous_config = _count_signals(INTENT_MAP["ambiguous_config"]["signals"], prompt_text) > 0
221
+ if not (has_auth or has_pref or has_ambiguous_config):
222
+ return None
223
+
224
+ has_specific_action = any(signal_matches_text(sig, prompt_text) for sig in IMPLEMENTATION_ACTION_SIGNALS)
225
+
226
+ if has_auth and has_pref:
227
+ intent_class = "ambiguous_config"
228
+ elif has_auth and has_ambiguous_config and not has_specific_action:
229
+ intent_class = "ambiguous_config"
230
+ elif has_auth:
231
+ intent_class = "auth_setup"
232
+ elif has_pref:
233
+ intent_class = "preference_memory"
234
+ else:
235
+ intent_class = "ambiguous_config"
236
+
237
+ missing_slots = []
238
+ if intent_class in ("auth_setup", "ambiguous_config"):
239
+ if not any(signal_matches_text(sig, prompt_text) for sig in AUTH_PROVIDER_SIGNALS):
240
+ missing_slots.append("provider")
241
+ if not any(signal_matches_text(sig, prompt_text) for sig in AUTH_SOURCE_SIGNALS):
242
+ missing_slots.append("credential_source")
243
+ if intent_class in ("preference_memory", "ambiguous_config"):
244
+ if not any(signal_matches_text(sig, prompt_text) for sig in PREFERENCE_SCOPE_SIGNALS):
245
+ missing_slots.append("scope")
246
+ if not has_specific_action:
247
+ missing_slots.append("desired_action")
248
+
249
+ requires_clarification = intent_class == "ambiguous_config" or bool(missing_slots)
250
+ clarification_prompt = ""
251
+ if requires_clarification:
252
+ prompt_map = {
253
+ "auth_setup": "Clarify auth setup in one line: target service, credential source, and exact action to run.",
254
+ "preference_memory": "Clarify preference memory in one line: settings to save, scope, and when to apply them.",
255
+ "ambiguous_config": "Clarify in one line whether this is auth setup or preference memory, plus the exact action to execute.",
256
+ }
257
+ clarification_prompt = _single_line(prompt_map[intent_class])
258
+
259
+ source_prompt_hash = _hash_prompt(prompt_text)
260
+ run_id = _resolve_run_id(payload, source_prompt_hash)
261
+ signal_hits = _count_signals(INTENT_MAP[intent_class]["signals"], prompt_text)
262
+ confidence = min(0.99, 0.76 + (signal_hits * 0.07) + (0.06 if intent_class == "ambiguous_config" else 0.0))
263
+ governance_payload = {}
264
+ if score_complexity is not None:
265
+ try:
266
+ governance_raw = score_complexity(prompt_text).get("governance")
267
+ if isinstance(governance_raw, dict):
268
+ governance_payload = governance_raw
269
+ except Exception:
270
+ governance_payload = {}
271
+
272
+ return {
273
+ "schema": "IntentGateClarificationState",
274
+ "schema_version": "1.0.0",
275
+ "run_id": run_id,
276
+ "intent_class": intent_class,
277
+ "confidence": round(confidence, 2),
278
+ "requires_clarification": requires_clarification,
279
+ "missing_slots": missing_slots,
280
+ "clarification_prompt": clarification_prompt,
281
+ "source_prompt_hash": source_prompt_hash,
282
+ "governance": governance_payload,
283
+ "updated_at": datetime.now(timezone.utc).isoformat(),
284
+ }
285
+
286
+ detected_intent = None
287
+ for intent_key, intent_data in INTENT_MAP.items():
288
+ if any(signal_matches_text(sig, prompt) for sig in intent_data["signals"]):
289
+ detected_intent = intent_key
290
+ break
291
+
292
+ intent_gate_state = _build_intent_gate_state(prompt, data)
293
+ if intent_gate_state is not None:
294
+ try:
295
+ _write_intent_gate_artifact(state_dir, intent_gate_state["run_id"], intent_gate_state)
296
+ except Exception:
297
+ pass
298
+
299
+ # ═══════════════════════════════════════════════════════════
300
+ # 2. DISCIPLINE SYSTEM (Sisyphus-grade)
301
+ # ═══════════════════════════════════════════════════════════
302
+ parts = []
303
+
304
+ if detected_intent:
305
+ parts.append(f"@intent: {INTENT_MAP[detected_intent]['directive']}")
306
+
307
+ if intent_gate_state and intent_gate_state.get("requires_clarification"):
308
+ clarification_line = _single_line(intent_gate_state.get("clarification_prompt", ""))
309
+ if clarification_line:
310
+ parts.append(f"@intent-clarify: {clarification_line}")
311
+
312
+ parts.append(
313
+ "@discipline: Senior-eng mode. Clean minimal code. "
314
+ "VERIFY changes. NEVER claim done unverified. "
315
+ "NEVER modify tests as fix. No noise comments, "
316
+ "no generic names (data/result/temp/val). FULL file reads."
317
+ )
318
+
319
+ if detected_intent in ("fix", "implement", "refactor"):
320
+ parts.append(
321
+ "@verify: After EVERY change run build/lint/test. Show exit code."
322
+ )
323
+ methodology_run_id = _resolve_run_id(data, _hash_prompt(prompt))
324
+ parts.append(
325
+ "@methodology: "
326
+ f"run_id={methodology_run_id} require plan+lock+done_when before mutation; "
327
+ "verify done_when after run."
328
+ )
329
+
330
+ _gov_payload: dict[str, object] | None = None
331
+ if score_complexity is not None and detected_intent in (
332
+ "fix", "implement", "refactor", "plan", "review",
333
+ ):
334
+ try:
335
+ _gov_raw = score_complexity(prompt).get("governance")
336
+ if isinstance(_gov_raw, dict):
337
+ _gov_payload = _gov_raw
338
+ except Exception:
339
+ pass
340
+ if _gov_payload and budget_ok():
341
+ parts.append(
342
+ f"@governance: read_first={_gov_payload.get('read_first', False)} "
343
+ f"simplify_only={_gov_payload.get('simplify_only', False)} "
344
+ f"optimize_only={_gov_payload.get('optimize_only', False)} "
345
+ f"complexity={_gov_payload.get('complexity', 'low')}"
346
+ )
347
+
348
+ if parts and budget_ok():
349
+ add("\n".join(parts))
350
+
351
+ # ═══════════════════════════════════════════════════════════
352
+ # 3. MODE DETECTION (ulw/ralph/crazy)
353
+ # ═══════════════════════════════════════════════════════════
354
+ ULW_SIGNALS = ["ulw", "ultrawork", "ralph", "끝까지", "멈추지마", "계속해",
355
+ "다될때까지", "don't stop", "keep going", "until done",
356
+ "finish everything", "complete all"]
357
+ is_ulw = any(signal_matches_text(sig, prompt) for sig in ULW_SIGNALS)
358
+
359
+ CRAZY_SIGNALS = ["crazy", "all agents", "maximum", "모든 에이전트", "최대", "미친"]
360
+ is_crazy = any(signal_matches_text(sig, prompt) for sig in CRAZY_SIGNALS)
361
+
362
+ if is_crazy and budget_ok():
363
+ add(
364
+ "@mode:CRAZY — All agents active. "
365
+ "Brainstorming is merged in CRAZY (no separate brainstorm step). "
366
+ "Claude=orchestrator, Codex=deep-code+security, Gemini=UI/UX. "
367
+ "Parallel dispatch. Error-loop prevention ON. "
368
+ "After planning, run a Codex validation pass before implementation."
369
+ )
370
+ elif is_ulw and budget_ok():
371
+ add(
372
+ "@mode:PERSISTENT — Do NOT stop until complete. "
373
+ "Work through ALL items. Skip if blocked, continue others. "
374
+ "Escalate to Codex/Gemini as needed. Verify everything."
375
+ )
376
+
377
+ # ── Ralph loop auto-activation on keyword ──
378
+ if is_ulw and get_feature_flag('ralph_loop'):
379
+ ralph_path = os.path.join(project_dir, '.omg', 'state', 'ralph-loop.json')
380
+ if not os.path.exists(ralph_path):
381
+ # Extract the goal from the prompt (everything after the keyword)
382
+ goal = prompt.strip()
383
+ for kw in ('ralph', 'ulw', 'ultrawork'):
384
+ if kw in prompt_lower:
385
+ idx = prompt_lower.find(kw) + len(kw)
386
+ extracted = prompt[idx:].strip()
387
+ if extracted:
388
+ goal = extracted
389
+ break
390
+ from datetime import datetime as _dt, timezone
391
+ state = {
392
+ 'active': True,
393
+ 'iteration': 0,
394
+ 'max_iterations': 50,
395
+ 'original_prompt': goal[:200],
396
+ 'started_at': _dt.now(timezone.utc).isoformat(),
397
+ 'checklist_path': '.omg/state/_checklist.md'
398
+ }
399
+ try:
400
+ os.makedirs(os.path.dirname(ralph_path), exist_ok=True)
401
+ atomic_json_write(ralph_path, state)
402
+ except Exception:
403
+ pass
404
+
405
+ # ═══════════════════════════════════════════════════════════
406
+ # 3b. AUTO-COMPLEXITY DETECTION (auto-trigger modes for complex tasks)
407
+ # ═══════════════════════════════════════════════════════════
408
+ # If user didn't explicitly request crazy/ulw, detect complexity and auto-suggest
409
+ if not is_crazy and not is_ulw and budget_ok():
410
+ complexity_score = 0
411
+
412
+ # Multi-step connectors (+1 each)
413
+ MULTI_STEP = ["and then", "after that", "followed by", "next", "also",
414
+ "그리고", "다음에", "이후에", "또한", "하고", "그다음"]
415
+ complexity_score += sum(1 for s in MULTI_STEP if signal_matches_text(s, prompt))
416
+
417
+ # Multiple action verbs in same prompt (+1 per verb beyond first, max +3)
418
+ ACTION_VERBS = ["fix", "implement", "build", "create", "add", "update",
419
+ "refactor", "migrate", "deploy", "rewrite", "redesign",
420
+ "수정", "구현", "만들", "추가", "수정", "리팩토링", "배포"]
421
+ verb_count = sum(1 for v in ACTION_VERBS if signal_matches_text(v, prompt))
422
+ complexity_score += min(max(verb_count - 1, 0), 3)
423
+
424
+ # Multi-file/component signals (+2 each)
425
+ MULTI_COMPONENT = ["entire", "all files", "whole project", "full stack",
426
+ "frontend and backend", "client and server", "end to end",
427
+ "every", "all the", "across",
428
+ "전체", "모든 파일", "풀스택", "모두", "전부",
429
+ "처음부터 끝까지"]
430
+ complexity_score += sum(2 for s in MULTI_COMPONENT if signal_matches_text(s, prompt))
431
+
432
+ # Architecture signals (+2 each)
433
+ ARCH_SIGNALS = ["architect", "redesign", "migration", "microservice",
434
+ "monorepo", "restructure", "overhaul", "rewrite from scratch",
435
+ "아키텍처", "마이그레이션", "재설계", "전면 수정", "처음부터 다시"]
436
+ complexity_score += sum(2 for s in ARCH_SIGNALS if signal_matches_text(s, prompt))
437
+
438
+ # Enumeration signals (numbered/bullet lists)
439
+ numbered_items = len(re.findall(r'(?:^|\n)\s*[\d]+[.)]\s', prompt_lower))
440
+ bullet_items = len(re.findall(r'(?:^|\n)\s*[-*]\s', prompt_lower))
441
+ complexity_score += min(numbered_items + bullet_items, 5)
442
+
443
+ # Word count signal
444
+ word_count = len(prompt_lower.split())
445
+ if word_count > 80:
446
+ complexity_score += 2
447
+ elif word_count > 40:
448
+ complexity_score += 1
449
+
450
+ complexity_category = "low"
451
+ if score_complexity is not None:
452
+ try:
453
+ scored = score_complexity(prompt)
454
+ scored_category = str(scored.get("category", "low")).strip().lower()
455
+ if scored_category in {"trivial", "low", "medium", "high"}:
456
+ complexity_category = scored_category
457
+ except Exception:
458
+ pass
459
+
460
+ # HIGH complexity (≥4): auto-trigger CRAZY
461
+ if complexity_score >= 4:
462
+ add(
463
+ "@mode:CRAZY(auto) — Complex task detected (multi-step/multi-component). "
464
+ f"Complexity label={complexity_category}. "
465
+ "All agents active: Claude=orchestrator, Codex=deep-code, Gemini=UI/UX. "
466
+ "Work through all items systematically. Verify each step."
467
+ )
468
+ # MEDIUM complexity (≥2): auto-trigger PERSISTENT
469
+ elif complexity_score >= 2:
470
+ add(
471
+ "@mode:PERSISTENT(auto) — Multi-step task detected. "
472
+ f"Complexity label={complexity_category}. "
473
+ "Work through ALL items. Skip if blocked, continue others. "
474
+ "Don't stop until checklist complete."
475
+ )
476
+
477
+ # ═══════════════════════════════════════════════════════════
478
+ # 3c. COGNITIVE MODE (from .omg/state/mode.txt)
479
+ # ═══════════════════════════════════════════════════════════
480
+ _mode_path = os.path.join(state_dir, 'mode.txt')
481
+ if os.path.exists(_mode_path) and budget_ok():
482
+ try:
483
+ with open(_mode_path, 'r', encoding='utf-8') as _mf:
484
+ _mode = _mf.read().strip().lower()
485
+ if _mode in ('research', 'architect', 'implement'):
486
+ _mode_hints = {
487
+ 'research': 'RESEARCH — Read/search/synthesize. No code changes unless asked.',
488
+ 'architect': 'ARCHITECT — Map system first. Specs and interfaces only, no implementation.',
489
+ 'implement': 'IMPLEMENT — TDD. Verify every change. Follow existing patterns.',
490
+ }
491
+ add(f'@mode:{_mode_hints[_mode]}')
492
+ except Exception:
493
+ pass
494
+
495
+
496
+ # ═══════════════════════════════════════════════════════════
497
+ # 4. SPECIALIST ROUTING (registry-based)
498
+ # ═══════════════════════════════════════════════════════════
499
+ CCG_SIGNALS = [
500
+ "ccg", "full stack", "full-stack", "frontend and backend", "backend and frontend",
501
+ "architecture review", "review everything", "cross-functional", "end-to-end", "e2e",
502
+ "풀스택", "아키텍처 리뷰", "전체 리뷰",
503
+ ]
504
+ DEEP_PLAN_SIGNALS = ["deep-plan", "deep plan", "/omg:deep-plan"]
505
+ EXPLICIT_GEMINI = ["gemini", "제미니"]
506
+ EXPLICIT_CODEX = ["codex", "코덱스"]
507
+
508
+ # Keyword-first model routing. If an explicit keyword exists, force OMG route first.
509
+ has_ccg_signal = any(signal_matches_text(sig, prompt) for sig in CCG_SIGNALS)
510
+ has_deep_plan_signal = any(signal_matches_text(sig, prompt) for sig in DEEP_PLAN_SIGNALS)
511
+ has_gemini_signal = any(signal_matches_text(sig, prompt) for sig in EXPLICIT_GEMINI)
512
+ has_codex_signal = any(signal_matches_text(sig, prompt) for sig in EXPLICIT_CODEX)
513
+
514
+ route_lock = ""
515
+ if has_deep_plan_signal:
516
+ route_lock = "deep-plan"
517
+ elif has_ccg_signal or (has_gemini_signal and has_codex_signal):
518
+ route_lock = "ccg"
519
+ elif has_gemini_signal:
520
+ route_lock = "gemini"
521
+ elif has_codex_signal:
522
+ route_lock = "codex"
523
+
524
+ if route_lock and budget_ok():
525
+ if route_lock == "deep-plan":
526
+ add(
527
+ '@route-lock: Explicit keyword route=deep-plan. Execute /OMG:deep-plan "[goal]" FIRST. '
528
+ "Do NOT call plugin/Skill routes (omg-teams/frontend-design/etc) before this OMG route."
529
+ )
530
+ elif route_lock == "ccg":
531
+ add(
532
+ '@route-lock: Explicit keyword route=ccg. Execute /OMG:ccg "[problem]" FIRST. '
533
+ "Do NOT call plugin/Skill routes (omg-teams/frontend-design/etc) before this OMG route."
534
+ )
535
+ elif route_lock == "gemini":
536
+ add(
537
+ '@route-lock: Explicit keyword route=gemini. Execute /OMG:escalate gemini "[problem]" FIRST. '
538
+ "Do NOT call plugin/Skill routes (omg-teams/frontend-design/etc) before this OMG route."
539
+ )
540
+ else:
541
+ add(
542
+ '@route-lock: Explicit keyword route=codex. Execute /OMG:escalate codex "[problem]" FIRST. '
543
+ "Do NOT call plugin/Skill routes (omg-teams/frontend-design/etc) before this OMG route."
544
+ )
545
+
546
+ if not route_lock and get_feature_flag('agent_registry') and budget_ok():
547
+ try:
548
+ try:
549
+ from hooks._agent_registry import resolve_agent, detect_available_models
550
+ except ImportError:
551
+ _agent_registry = importlib.import_module("_agent_registry")
552
+ resolve_agent = _agent_registry.resolve_agent
553
+ detect_available_models = _agent_registry.detect_available_models
554
+ _maybe_kws = locals().get("kws")
555
+ _routing_kws = _maybe_kws if _maybe_kws else set(re.findall(r'\b[a-zA-Z]{3,}\b', prompt_lower))
556
+ matched_agent = resolve_agent(_routing_kws)
557
+ if isinstance(matched_agent, dict):
558
+ _agent_name = matched_agent.get('name', '')
559
+ _preferred = matched_agent.get('preferred_model', 'claude')
560
+ if _preferred == 'gemini-cli':
561
+ add(f'@agent: {_agent_name} → /OMG:escalate gemini "[task]" (visual/frontend domain)')
562
+ elif _preferred == 'codex-cli':
563
+ add(f'@agent: {_agent_name} → /OMG:escalate codex "[task]" (backend/security domain)')
564
+ elif _preferred in ('claude', 'domain-dependent'):
565
+ _desc = str(matched_agent.get('description', ''))[:80]
566
+ if _desc:
567
+ add(f'@agent: {_agent_name} — {_desc}')
568
+ except Exception:
569
+ pass
570
+
571
+ SEQUENTIAL_THINKING_SIGNALS = [
572
+ "sequential thinking",
573
+ "sequential-thinking",
574
+ "chain of thought",
575
+ "step by step reasoning",
576
+ "단계적 사고",
577
+ ]
578
+ if any(signal_matches_text(sig, prompt) for sig in SEQUENTIAL_THINKING_SIGNALS) and budget_ok():
579
+ add("@reasoning: Use /OMG:sequential-thinking for structured hypothesis and verification flow.")
580
+
581
+ # Security domain warning (keep this — it's additive, not routing)
582
+ SECURITY_SIGNALS = [
583
+ "auth", "login", "signup", "session", "token", "password", "jwt", "oauth",
584
+ "payment", "billing", "checkout", "stripe", "card",
585
+ "database", "migration", "schema", "sql", "query",
586
+ "encrypt", "decrypt", "cors",
587
+ "인증", "로그인", "세션", "토큰", "비밀번호", "결제", "데이터베이스", "보안",
588
+ ]
589
+ if not route_lock and any(signal_matches_text(sig, prompt) for sig in SECURITY_SIGNALS) and budget_ok():
590
+ if detected_intent in ("fix", "implement", "refactor"):
591
+ add("@security: CRITICAL DOMAIN — No hardcoded secrets. Run /OMG:security-check after.")
592
+
593
+ # ═══════════════════════════════════════════════════════════
594
+ # 5. VISION DETECTION
595
+ # ═══════════════════════════════════════════════════════════
596
+ VISION_SIGNALS = [
597
+ "screenshot", "screen", "look at this", "see this", "attached image",
598
+ "this image", "the picture", "visual bug", "looks wrong", "looks broken",
599
+ "스크린샷", "화면 캡처", "이미지", "사진", "보여", "이렇게 보여",
600
+ ]
601
+ if any(signal_matches_text(sig, prompt) for sig in VISION_SIGNALS) and budget_ok():
602
+ add(
603
+ "@vision: Visual context detected. Use screenshot tools if available. "
604
+ "/OMG:escalate gemini for visual analysis."
605
+ )
606
+
607
+ # ═══════════════════════════════════════════════════════════
608
+ # 6. RESUME / HANDOFF
609
+ # ═══════════════════════════════════════════════════════════
610
+ RESUME_SIGNALS = [
611
+ "continue where", "pick up where", "left off", "resume", "handoff",
612
+ "what was i working on", "previous session",
613
+ "이어서", "계속해", "이전 세션", "하던 거", "핸드오프",
614
+ "session handoff", "## what was done",
615
+ ]
616
+ if any(signal_matches_text(sig, prompt) for sig in RESUME_SIGNALS) and budget_ok():
617
+ for hp in [os.path.join(state_dir, "handoff.md"), os.path.join(state_dir, "handoff-portable.md")]:
618
+ if os.path.exists(hp):
619
+ try:
620
+ with open(hp, "r", encoding="utf-8", errors="ignore") as f:
621
+ htext = f.read(1500)
622
+ sections = []
623
+ for s in re.split(r"\n## ", htext):
624
+ h = s.split("\n")[0].lower()
625
+ if any(k in h for k in ("next", "state", "fail")):
626
+ sections.append("## " + s.strip()[:200])
627
+ if sections:
628
+ add("@handoff:" + "\n".join(sections)[:250])
629
+ else:
630
+ add("@handoff: Read .omg/state/handoff.md for context")
631
+ except Exception:
632
+ pass
633
+ break
634
+
635
+ # ═══════════════════════════════════════════════════════════
636
+ # 7. CODING CONTEXT (checklist + DDD + knowledge)
637
+ # ═══════════════════════════════════════════════════════════
638
+ CODE_SIGNALS = [
639
+ "fix", "implement", "refactor", "build", "add", "create", "modify",
640
+ "change", "update", "code", "test", "debug",
641
+ "수정", "구현", "빌드", "추가", "생성", "코드", "테스트", "디버그",
642
+ "고쳐", "개발",
643
+ ]
644
+ is_coding = any(signal_matches_text(sig, prompt) for sig in CODE_SIGNALS)
645
+
646
+ if is_coding and budget_ok():
647
+ cp = os.path.join(state_dir, "_checklist.md")
648
+ if os.path.exists(cp):
649
+ try:
650
+ with open(cp, "r", encoding="utf-8", errors="ignore") as f:
651
+ lines = f.readlines()
652
+ done = sum(1 for l in lines if "[x]" in l.lower())
653
+ total = sum(1 for l in lines if l.strip().startswith(("[", "- [")))
654
+ pending = [l.strip().replace("[ ] ", "").replace("- [ ] ", "")[:50]
655
+ for l in lines if "[ ]" in l][:2]
656
+ if total > 0:
657
+ add(f"@progress: {done}/{total} | next: {' → '.join(pending)}")
658
+ except Exception:
659
+ pass
660
+
661
+ # DDD
662
+ DDD_SIGNALS = ["new domain", "new module", "scaffold", "domain", "새 도메인", "새 모듈"]
663
+ if any(signal_matches_text(sig, prompt) for sig in DDD_SIGNALS) and budget_ok():
664
+ pd = os.path.join(knowledge_dir, "domain-patterns")
665
+ if os.path.isdir(pd):
666
+ pats = [f.replace(".md", "") for f in os.listdir(pd) if f.endswith(".md")]
667
+ if pats:
668
+ add(f"@ddd: Patterns: {', '.join(pats[:3])}. Follow existing.")
669
+ else:
670
+ add("@ddd: No patterns. Use /OMG:domain-init for first reference.")
671
+
672
+ # Knowledge retrieval (top-2, with index cache for performance)
673
+ # §4.5: Instead of os.walk + read every file on every prompt,
674
+ # maintain a lightweight index (.omg/knowledge/.index.json) keyed by mtime.
675
+ kd = knowledge_dir
676
+ # Skip knowledge search for very short prompts with no coding signals (perf optimization)
677
+ _word_count = len(prompt_lower.split())
678
+ _has_code_signal = is_coding or detected_intent is not None
679
+ if os.path.isdir(kd) and budget_ok() and (_word_count >= 15 or _has_code_signal):
680
+ words = set(re.findall(r'\b[a-zA-Z]{3,}\b', prompt_lower))
681
+ words |= set(re.findall(r'[\uac00-\ud7a3]{2,}', prompt))
682
+ stops = {"the","and","for","that","this","with","from","have","will",
683
+ "but","not","are","was","can","could","should","about",
684
+ "just","also","want","need","like","make","please","help","use","try"}
685
+ kws = words - stops
686
+ if kws:
687
+ # Load or rebuild index
688
+ index_path = os.path.join(kd, ".index.json")
689
+ index = {}
690
+ try:
691
+ if os.path.exists(index_path):
692
+ with open(index_path, "r") as f:
693
+ index = json.load(f)
694
+ if not isinstance(index, dict):
695
+ print(f"[OMG] prompt-enhancer: index.json is not a dict ({type(index).__name__}), rebuilding", file=sys.stderr)
696
+ try:
697
+ os.remove(index_path)
698
+ except OSError:
699
+ pass
700
+ index = {}
701
+ except (json.JSONDecodeError, ValueError):
702
+ # Corrupted index — delete and rebuild
703
+ try:
704
+ os.remove(index_path)
705
+ except OSError:
706
+ pass
707
+ index = {}
708
+ except FileNotFoundError:
709
+ index = {}
710
+ except Exception:
711
+ index = {}
712
+
713
+ # Scan files, rebuild stale/missing entries (cap: 30 files)
714
+ rebuild = False
715
+ file_count = 0
716
+ for root, dirs, files in os.walk(kd):
717
+ for fn in files:
718
+ if not fn.endswith(".md") or fn.startswith("."):
719
+ continue
720
+ file_count += 1
721
+ if file_count > 30:
722
+ break
723
+ fp = os.path.join(root, fn)
724
+ try:
725
+ mtime = str(os.path.getmtime(fp))
726
+ cached = index.get(fp, {})
727
+ if cached.get("mtime") == mtime:
728
+ continue # still fresh
729
+ # Read and index (sanitize potential secrets before caching)
730
+ with open(fp, "r", encoding="utf-8", errors="ignore") as f:
731
+ content = f.read(1500).lower()
732
+ # Strip lines that look like secret assignments before caching
733
+ sanitized_lines = []
734
+ for cline in content.split("\n"):
735
+ if re.search(r'(?:key|secret|token|password|credential)\s*[:=]', cline):
736
+ continue
737
+ sanitized_lines.append(cline)
738
+ content = "\n".join(sanitized_lines)
739
+ index[fp] = {"mtime": mtime, "content": content}
740
+ rebuild = True
741
+ except Exception:
742
+ pass
743
+ if file_count > 30:
744
+ break
745
+
746
+ # Cap index at 100 entries, remove oldest by mtime if needed
747
+ if len(index) > 100:
748
+ # Sort by mtime (oldest first) and remove excess
749
+ sorted_entries = sorted(index.items(), key=lambda x: x[1].get("mtime", "0"))
750
+ entries_to_remove = len(index) - 100
751
+ for fp, _ in sorted_entries[:entries_to_remove]:
752
+ del index[fp]
753
+ rebuild = True
754
+
755
+ # Save index if changed using atomic write
756
+ if rebuild:
757
+ atomic_json_write(index_path, index)
758
+
759
+ # Match keywords against cached content
760
+ matches = []
761
+ for fp, data in index.items():
762
+ if not isinstance(data, dict) or "content" not in data:
763
+ continue
764
+ c = data["content"]
765
+ sc = sum(1 for kw in kws if kw in c)
766
+ if sc >= 2:
767
+ matches.append((sc, fp))
768
+ matches.sort(key=lambda x: -x[0])
769
+ for sc, fp in matches[:2]:
770
+ if not budget_ok():
771
+ break
772
+ rel = os.path.relpath(fp, omg_root)
773
+ add(f"@knowledge({rel})")
774
+
775
+ # ═══════════════════════════════════════════════════════════
776
+ # 7b. MEMORY RETRIEVAL (cross-session context)
777
+ # ═══════════════════════════════════════════════════════════
778
+ if get_feature_flag('memory') and budget_ok():
779
+ try:
780
+ try:
781
+ from hooks._memory import search_memories
782
+ except ImportError:
783
+ _memory = importlib.import_module("_memory")
784
+ search_memories = _memory.search_memories
785
+ # Reuse keywords already extracted for knowledge search
786
+ _kws_local = locals().get("kws")
787
+ _mem_kws = list(_kws_local) if _kws_local else []
788
+ if _mem_kws:
789
+ mem_context = search_memories(project_dir, _mem_kws, max_results=3, max_chars=200)
790
+ if mem_context:
791
+ add(f'@memory: {mem_context}')
792
+ except Exception:
793
+ pass
794
+
795
+ # ═══════════════════════════════════════════════════════════
796
+ # 8. ERROR LOOP PREVENTION
797
+ # ═══════════════════════════════════════════════════════════
798
+ STUCK_SIGNALS = ["stuck", "same error", "keep getting", "tried everything",
799
+ "doesn't work", "막혀", "안돼", "실패", "같은에러", "모르겠"]
800
+ if any(signal_matches_text(sig, prompt) for sig in STUCK_SIGNALS) and budget_ok():
801
+ tp = os.path.join(state_dir, "ledger", "failure-tracker.json")
802
+ ctx = ""
803
+ active = {}
804
+ if os.path.exists(tp):
805
+ try:
806
+ with open(tp, "r") as f:
807
+ t = json.load(f)
808
+ active = {k: v.get("count", 0) for k, v in t.items()
809
+ if isinstance(v, dict) and v.get("count", 0) >= 2}
810
+ if active:
811
+ top = sorted(active.items(), key=lambda x: -x[1])[:2]
812
+ ctx = f" ({', '.join(f'{k[:25]}×{c}' for k,c in top)})"
813
+ except Exception:
814
+ pass
815
+ # Only inject if there are ≥2 tracked failures (not just keyword match)
816
+ if active:
817
+ # Dedup: skip if @stuck was injected within last 60 seconds
818
+ ts_path = os.path.join(state_dir, ".last-stuck-ts")
819
+ now = time.time()
820
+ should_inject = True
821
+ try:
822
+ if os.path.exists(ts_path):
823
+ with open(ts_path, "r") as f:
824
+ last_ts = float(f.read().strip())
825
+ if now - last_ts < 60:
826
+ should_inject = False
827
+ except (ValueError, OSError):
828
+ pass # Corrupt file → allow injection
829
+ if should_inject:
830
+ try:
831
+ os.makedirs(os.path.dirname(ts_path) or ".", exist_ok=True)
832
+ with open(ts_path, "w") as f:
833
+ f.write(str(now))
834
+ except OSError:
835
+ pass
836
+ add(f"@stuck{ctx}: STOP retrying. /OMG:escalate codex | different approach | ask user")
837
+
838
+ # ═══════════════════════════════════════════════════════════
839
+ # 9. WRITE/EDIT FAILURE AWARENESS (anti-hallucination)
840
+ # ═══════════════════════════════════════════════════════════
841
+ # When hook errors or write/edit failures occur, Claude often claims success.
842
+ # Detect error patterns and inject a verification requirement.
843
+ WRITE_ERROR_SIGNALS = [
844
+ "hook error", "error editing file", "error writing file",
845
+ "error: pretooluse", "error: posttooluse",
846
+ "security warning", "security_reminder",
847
+ "⚠️", "xss", "innerhtml", "xss vulnerabilit",
848
+ "hook 에러", "파일 수정 에러", "파일 쓰기 에러",
849
+ ]
850
+ if any(signal_matches_text(sig, prompt) for sig in WRITE_ERROR_SIGNALS) and budget_ok():
851
+ add(
852
+ "@write-verify: Hook/Write/Edit error detected in conversation. "
853
+ "BEFORE claiming success: READ the target file to verify changes are present. "
854
+ "If file unchanged → retry with different method (Edit, Bash heredoc, or cat >). "
855
+ "NEVER say 'updated successfully' without reading the file first."
856
+ )
857
+
858
+ # Context engine packet pointer (if available, include pointer — not raw content)
859
+ _ctx_engine_packet_path = os.path.join(project_dir, ".omg", "state", "context_engine_packet.json")
860
+ if os.path.isfile(_ctx_engine_packet_path) and budget_ok():
861
+ add("@context-engine: see .omg/state/context_engine_packet.json")
862
+
863
+ # ═══════════════════════════════════════════════════════════
864
+ # OUTPUT
865
+ # ═══════════════════════════════════════════════════════════
866
+ try:
867
+ tool_count, _threshold, is_high_pressure = estimate_context_pressure(project_dir)
868
+ if is_high_pressure:
869
+ add(f"@context-pressure: High context usage detected ({tool_count} tool calls). Auto-saving state...")
870
+ except Exception:
871
+ pass
872
+
873
+ if injections:
874
+ output = "\n".join(injections)
875
+ if len(output) > MAX_CHARS:
876
+ output = output[:MAX_CHARS - 3] + "..."
877
+ json.dump({"contextInjection": output}, sys.stdout)
878
+
879
+ sys.exit(0)