@trac3er/oh-my-god 2.0.0 → 2.0.2

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 (243) hide show
  1. package/.claude-plugin/marketplace.json +8 -8
  2. package/.claude-plugin/plugin.json +5 -4
  3. package/.claude-plugin/scripts/uninstall.sh +74 -3
  4. package/.claude-plugin/scripts/update.sh +78 -3
  5. package/.coveragerc +26 -0
  6. package/.mcp.json +4 -4
  7. package/CHANGELOG.md +14 -0
  8. package/CODE_OF_CONDUCT.md +27 -0
  9. package/CONTRIBUTING.md +62 -0
  10. package/OMG-setup.sh +1201 -355
  11. package/README.md +77 -56
  12. package/SECURITY.md +25 -0
  13. package/agents/__init__.py +1 -0
  14. package/agents/model_roles.py +196 -0
  15. package/agents/omg-architect-mode.md +3 -5
  16. package/agents/omg-backend-engineer.md +3 -5
  17. package/agents/omg-database-engineer.md +3 -5
  18. package/agents/omg-frontend-designer.md +4 -5
  19. package/agents/omg-implement-mode.md +4 -5
  20. package/agents/omg-infra-engineer.md +3 -5
  21. package/agents/omg-research-mode.md +4 -6
  22. package/agents/omg-security-auditor.md +3 -5
  23. package/agents/omg-testing-engineer.md +3 -5
  24. package/build/lib/yaml.py +321 -0
  25. package/commands/OMG:ai-commit.md +101 -14
  26. package/commands/OMG:arch.md +302 -19
  27. package/commands/OMG:ccg.md +12 -7
  28. package/commands/OMG:compat.md +25 -17
  29. package/commands/OMG:cost.md +173 -13
  30. package/commands/OMG:crazy.md +1 -1
  31. package/commands/OMG:create-agent.md +170 -20
  32. package/commands/OMG:deps.md +235 -17
  33. package/commands/OMG:domain-init.md +1 -1
  34. package/commands/OMG:escalate.md +41 -12
  35. package/commands/OMG:health-check.md +37 -13
  36. package/commands/OMG:init.md +122 -14
  37. package/commands/OMG:project-init.md +1 -1
  38. package/commands/OMG:session-branch.md +76 -9
  39. package/commands/OMG:session-fork.md +42 -5
  40. package/commands/OMG:session-merge.md +124 -8
  41. package/commands/OMG:setup.md +69 -12
  42. package/commands/OMG:stats.md +215 -14
  43. package/commands/OMG:teams.md +19 -10
  44. package/config/lsp_languages.yaml +8 -0
  45. package/hooks/__init__.py +0 -0
  46. package/hooks/_agent_registry.py +423 -0
  47. package/hooks/_analytics.py +291 -0
  48. package/hooks/_budget.py +31 -0
  49. package/hooks/_common.py +569 -0
  50. package/hooks/_compression_optimizer.py +119 -0
  51. package/hooks/_cost_ledger.py +176 -0
  52. package/hooks/_learnings.py +126 -0
  53. package/hooks/_memory.py +103 -0
  54. package/hooks/_protected_context.py +150 -0
  55. package/hooks/_token_counter.py +221 -0
  56. package/hooks/branch_manager.py +236 -0
  57. package/hooks/budget_governor.py +232 -0
  58. package/hooks/circuit-breaker.py +270 -0
  59. package/hooks/compression_feedback.py +254 -0
  60. package/hooks/config-guard.py +216 -0
  61. package/hooks/context_pressure.py +53 -0
  62. package/hooks/credential_store.py +1020 -0
  63. package/hooks/fetch-rate-limits.py +212 -0
  64. package/hooks/firewall.py +48 -0
  65. package/hooks/hashline-formatter-bridge.py +224 -0
  66. package/hooks/hashline-injector.py +273 -0
  67. package/hooks/hashline-validator.py +216 -0
  68. package/hooks/idle-detector.py +95 -0
  69. package/hooks/intentgate-keyword-detector.py +188 -0
  70. package/hooks/magic-keyword-router.py +195 -0
  71. package/hooks/policy_engine.py +505 -0
  72. package/hooks/post-tool-failure.py +19 -0
  73. package/hooks/post-write.py +219 -0
  74. package/hooks/post_write.py +46 -0
  75. package/hooks/pre-compact.py +398 -0
  76. package/hooks/pre-tool-inject.py +98 -0
  77. package/hooks/prompt-enhancer.py +672 -0
  78. package/hooks/quality-runner.py +191 -0
  79. package/hooks/query.py +512 -0
  80. package/hooks/secret-guard.py +61 -0
  81. package/hooks/secret_audit.py +144 -0
  82. package/hooks/session-end-capture.py +137 -0
  83. package/hooks/session-start.py +277 -0
  84. package/hooks/setup_wizard.py +582 -0
  85. package/hooks/shadow_manager.py +297 -0
  86. package/hooks/state_migration.py +225 -0
  87. package/hooks/stop-gate.py +7 -0
  88. package/hooks/stop_dispatcher.py +945 -0
  89. package/hooks/test-validator.py +361 -0
  90. package/hooks/test_generator_hook.py +123 -0
  91. package/hooks/todo-state-tracker.py +114 -0
  92. package/hooks/tool-ledger.py +149 -0
  93. package/hooks/trust_review.py +585 -0
  94. package/hud/omg-hud.mjs +31 -1
  95. package/lab/__init__.py +1 -0
  96. package/lab/pipeline.py +75 -0
  97. package/lab/policies.py +52 -0
  98. package/package.json +7 -18
  99. package/plugins/README.md +33 -61
  100. package/plugins/advanced/commands/OMG:deep-plan.md +3 -3
  101. package/plugins/advanced/commands/OMG:learn.md +1 -1
  102. package/plugins/advanced/commands/OMG:security-review.md +3 -3
  103. package/plugins/advanced/commands/OMG:ship.md +1 -1
  104. package/plugins/advanced/plugin.json +1 -1
  105. package/plugins/core/plugin.json +8 -3
  106. package/plugins/dephealth/__init__.py +0 -0
  107. package/plugins/dephealth/cve_scanner.py +188 -0
  108. package/plugins/dephealth/license_checker.py +135 -0
  109. package/plugins/dephealth/manifest_detector.py +423 -0
  110. package/plugins/dephealth/vuln_analyzer.py +169 -0
  111. package/plugins/testgen/__init__.py +0 -0
  112. package/plugins/testgen/codamosa_engine.py +402 -0
  113. package/plugins/testgen/edge_case_synthesizer.py +184 -0
  114. package/plugins/testgen/framework_detector.py +271 -0
  115. package/plugins/testgen/skeleton_generator.py +219 -0
  116. package/plugins/viz/__init__.py +0 -0
  117. package/plugins/viz/ast_parser.py +139 -0
  118. package/plugins/viz/diagram_generator.py +192 -0
  119. package/plugins/viz/graph_builder.py +444 -0
  120. package/plugins/viz/native_parsers.py +259 -0
  121. package/plugins/viz/regex_parser.py +112 -0
  122. package/pyproject.toml +81 -0
  123. package/rules/contextual/write-verify.md +2 -2
  124. package/rules/core/00-truth.md +1 -1
  125. package/rules/core/01-surgical.md +1 -1
  126. package/rules/core/02-circuit-breaker.md +2 -2
  127. package/rules/core/03-ensemble.md +3 -3
  128. package/rules/core/04-testing.md +3 -3
  129. package/runtime/__init__.py +32 -0
  130. package/runtime/adapters/__init__.py +13 -0
  131. package/runtime/adapters/claude.py +60 -0
  132. package/runtime/adapters/gpt.py +53 -0
  133. package/runtime/adapters/local.py +53 -0
  134. package/runtime/adoption.py +212 -0
  135. package/runtime/business_workflow.py +220 -0
  136. package/runtime/cli_provider.py +85 -0
  137. package/runtime/compat.py +1299 -0
  138. package/runtime/custom_agent_loader.py +366 -0
  139. package/runtime/dispatcher.py +47 -0
  140. package/runtime/ecosystem.py +371 -0
  141. package/runtime/legacy_compat.py +7 -0
  142. package/runtime/mcp_config_writers.py +115 -0
  143. package/runtime/mcp_lifecycle.py +153 -0
  144. package/runtime/mcp_memory_server.py +135 -0
  145. package/runtime/memory_parsers/__init__.py +0 -0
  146. package/runtime/memory_parsers/chatgpt_parser.py +257 -0
  147. package/runtime/memory_parsers/claude_import.py +107 -0
  148. package/runtime/memory_parsers/export.py +97 -0
  149. package/runtime/memory_parsers/gemini_import.py +91 -0
  150. package/runtime/memory_parsers/kimi_import.py +91 -0
  151. package/runtime/memory_store.py +215 -0
  152. package/runtime/omc_compat.py +7 -0
  153. package/runtime/providers/__init__.py +0 -0
  154. package/runtime/providers/codex_provider.py +112 -0
  155. package/runtime/providers/gemini_provider.py +128 -0
  156. package/runtime/providers/kimi_provider.py +151 -0
  157. package/runtime/providers/opencode_provider.py +144 -0
  158. package/runtime/subagent_dispatcher.py +362 -0
  159. package/runtime/team_router.py +1167 -0
  160. package/runtime/tmux_session_manager.py +169 -0
  161. package/scripts/check-omg-compat-contract-snapshot.py +137 -0
  162. package/scripts/check-omg-contract-snapshot.py +12 -0
  163. package/scripts/check-omg-public-ready.py +193 -0
  164. package/scripts/check-omg-standalone-clean.py +103 -0
  165. package/scripts/legacy_to_omg_migrate.py +29 -0
  166. package/scripts/migrate-legacy.py +464 -0
  167. package/scripts/omc_to_omg_migrate.py +12 -0
  168. package/scripts/omg.py +492 -0
  169. package/scripts/settings-merge.py +283 -0
  170. package/scripts/verify-standalone.sh +8 -4
  171. package/settings.json +126 -29
  172. package/templates/profile.yaml +1 -1
  173. package/tools/__init__.py +2 -0
  174. package/tools/browser_consent.py +289 -0
  175. package/tools/browser_stealth.py +481 -0
  176. package/tools/browser_tool.py +448 -0
  177. package/tools/changelog_generator.py +347 -0
  178. package/tools/commit_splitter.py +746 -0
  179. package/tools/config_discovery.py +151 -0
  180. package/tools/config_merger.py +449 -0
  181. package/tools/dashboard_generator.py +300 -0
  182. package/tools/git_inspector.py +298 -0
  183. package/tools/lsp_client.py +275 -0
  184. package/tools/lsp_discovery.py +231 -0
  185. package/tools/lsp_operations.py +392 -0
  186. package/tools/pr_generator.py +404 -0
  187. package/tools/python_repl.py +656 -0
  188. package/tools/python_sandbox.py +609 -0
  189. package/tools/search_providers/__init__.py +77 -0
  190. package/tools/search_providers/brave.py +115 -0
  191. package/tools/search_providers/exa.py +116 -0
  192. package/tools/search_providers/jina.py +104 -0
  193. package/tools/search_providers/perplexity.py +139 -0
  194. package/tools/search_providers/synthetic.py +74 -0
  195. package/tools/session_snapshot.py +736 -0
  196. package/tools/ssh_manager.py +912 -0
  197. package/tools/theme_engine.py +294 -0
  198. package/tools/theme_selector.py +137 -0
  199. package/tools/web_search.py +622 -0
  200. package/yaml.py +321 -0
  201. package/.claude-plugin/scripts/install.sh +0 -9
  202. package/bun.lock +0 -23
  203. package/bunfig.toml +0 -3
  204. package/hooks/_budget.ts +0 -1
  205. package/hooks/_common.ts +0 -63
  206. package/hooks/circuit-breaker.ts +0 -101
  207. package/hooks/config-guard.ts +0 -4
  208. package/hooks/firewall.ts +0 -20
  209. package/hooks/policy_engine.ts +0 -156
  210. package/hooks/post-tool-failure.ts +0 -22
  211. package/hooks/post-write.ts +0 -4
  212. package/hooks/pre-tool-inject.ts +0 -4
  213. package/hooks/prompt-enhancer.ts +0 -46
  214. package/hooks/quality-runner.ts +0 -24
  215. package/hooks/secret-guard.ts +0 -4
  216. package/hooks/session-end-capture.ts +0 -19
  217. package/hooks/session-start.ts +0 -19
  218. package/hooks/shadow_manager.ts +0 -81
  219. package/hooks/stop-gate.ts +0 -22
  220. package/hooks/stop_dispatcher.ts +0 -147
  221. package/hooks/test-generator-hook.ts +0 -4
  222. package/hooks/tool-ledger.ts +0 -27
  223. package/hooks/trust_review.ts +0 -175
  224. package/lab/pipeline.ts +0 -75
  225. package/lab/policies.ts +0 -68
  226. package/runtime/common.ts +0 -111
  227. package/runtime/compat.ts +0 -174
  228. package/runtime/dispatcher.ts +0 -25
  229. package/runtime/ecosystem.ts +0 -186
  230. package/runtime/provider_bootstrap.ts +0 -99
  231. package/runtime/provider_smoke.ts +0 -34
  232. package/runtime/release_readiness.ts +0 -186
  233. package/runtime/team_router.ts +0 -144
  234. package/scripts/check-omg-compat-contract-snapshot.ts +0 -20
  235. package/scripts/check-omg-standalone-clean.ts +0 -12
  236. package/scripts/check-runtime-clean.ts +0 -94
  237. package/scripts/omg.ts +0 -352
  238. package/scripts/settings-merge.ts +0 -93
  239. package/tools/commit_splitter.ts +0 -23
  240. package/tools/git_inspector.ts +0 -18
  241. package/tools/session_snapshot.ts +0 -47
  242. package/trac3er-oh-my-god-2.0.0.tgz +0 -0
  243. package/tsconfig.json +0 -15
@@ -0,0 +1,52 @@
1
+ """Policy checks for OMG lab train/eval pipeline."""
2
+ from __future__ import annotations
3
+
4
+ from typing import Any
5
+
6
+
7
+ ALLOWED_LICENSES = {"apache-2.0", "mit", "bsd-3-clause", "cc-by-4.0"}
8
+ BLOCKED_SOURCE_TOKENS = {"unknown", "leaked", "stolen", "unauthorized", "pirated"}
9
+
10
+
11
+ def validate_dataset_source(dataset: dict[str, Any]) -> tuple[bool, str]:
12
+ license_name = str(dataset.get("license", "")).lower()
13
+ source = str(dataset.get("source", "")).lower()
14
+
15
+ if not license_name:
16
+ return False, "dataset license missing"
17
+ if license_name not in ALLOWED_LICENSES:
18
+ return False, f"dataset license not allowed: {license_name}"
19
+ if any(token in source for token in BLOCKED_SOURCE_TOKENS):
20
+ return False, "dataset source violates policy"
21
+ return True, "ok"
22
+
23
+
24
+ def validate_model_source(model: dict[str, Any]) -> tuple[bool, str]:
25
+ source = str(model.get("source", "")).lower()
26
+ allow_distill = bool(model.get("allow_distill", False))
27
+
28
+ if any(token in source for token in BLOCKED_SOURCE_TOKENS):
29
+ return False, "model source violates policy"
30
+ if not allow_distill:
31
+ return False, "model source disallows distillation"
32
+ return True, "ok"
33
+
34
+
35
+ def validate_job_request(job: dict[str, Any]) -> tuple[bool, str]:
36
+ dataset = job.get("dataset")
37
+ model = job.get("base_model")
38
+
39
+ if not isinstance(dataset, dict):
40
+ return False, "dataset block missing"
41
+ if not isinstance(model, dict):
42
+ return False, "base_model block missing"
43
+
44
+ ok, reason = validate_dataset_source(dataset)
45
+ if not ok:
46
+ return False, reason
47
+
48
+ ok, reason = validate_model_source(model)
49
+ if not ok:
50
+ return False, reason
51
+
52
+ return True, "ok"
package/package.json CHANGED
@@ -1,18 +1,13 @@
1
1
  {
2
2
  "name": "@trac3er/oh-my-god",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "OMG (Oh My God) — Multi-agent orchestration, intelligent model routing, and durable session state for Claude Code",
5
- "bin": {
6
- "omg": "scripts/omg.ts"
7
- },
8
- "main": "scripts/omg.ts",
5
+ "main": "OMG-setup.sh",
9
6
  "scripts": {
10
- "postinstall": "bash ./OMG-setup.sh install --non-interactive",
11
- "update": "bash ./OMG-setup.sh update",
12
- "uninstall": "bash ./OMG-setup.sh uninstall",
13
- "test": "bun test",
14
- "typecheck": "bunx tsc --noEmit",
15
- "check:runtime-clean": "bun scripts/check-runtime-clean.ts"
7
+ "postinstall": "./OMG-setup.sh install --non-interactive",
8
+ "update": "./OMG-setup.sh update",
9
+ "uninstall": "./OMG-setup.sh uninstall",
10
+ "test": "python3 -m pytest tests/ -x -q"
16
11
  },
17
12
  "keywords": [
18
13
  "claude",
@@ -35,12 +30,6 @@
35
30
  },
36
31
  "homepage": "https://github.com/trac3er00/OMG#readme",
37
32
  "engines": {
38
- "bun": ">=1.3.0"
39
- },
40
- "packageManager": "bun@1.3.9",
41
- "devDependencies": {
42
- "@types/node": "^25.3.5",
43
- "bun-types": "^1.3.10",
44
- "typescript": "^5.9.2"
33
+ "node": ">=14"
45
34
  }
46
35
  }
package/plugins/README.md CHANGED
@@ -1,82 +1,54 @@
1
1
  # OMG Commands
2
2
 
3
- OMG provides two tiers of commands:
3
+ OMG exposes a small native front door and keeps the rest of the surface available as advanced plugins.
4
4
 
5
- ## Core Commands (`commands/`)
5
+ ## Native Entry Points
6
6
 
7
- Essential functionality available in all OMG installations:
7
+ | Command | Description |
8
+ |---------|-------------|
9
+ | `/OMG:setup` | Native setup and adoption flow for supported hosts |
10
+ | `/OMG:crazy` | Default OMG orchestration flow |
11
+
12
+ ## Core Commands
8
13
 
9
14
  | Command | Description |
10
15
  |---------|-------------|
11
16
  | `/OMG:init` | Initialize project or domain |
12
- | `/OMG:escalate` | Route to Codex/Gemini/CCG |
13
- | `/OMG:teams` | Team routing (standalone) |
14
- | `/OMG:ccg` | Tri-track synthesis (Claude+Codex+Gemini) |
15
- | `/OMG:crazy` | Parallel multi-agent orchestration |
16
- | `/OMG:compat` | Legacy compatibility dispatcher |
17
- | `/OMG:health-check` | Verify setup and tools |
18
- | `/OMG:mode` | Set cognitive mode |
19
-
20
- ## Advanced Commands (`plugins/advanced/`)
17
+ | `/OMG:escalate` | Route to Codex, Gemini, or CCG |
18
+ | `/OMG:teams` | Team routing for internal OMG execution |
19
+ | `/OMG:ccg` | Tri-track synthesis |
20
+ | `/OMG:compat` | Legacy compatibility routing |
21
+ | `/OMG:health-check` | Verify setup and tool integration |
22
+ | `/OMG:mode` | Set cognitive mode for the session |
21
23
 
22
- Extended functionality for specialized workflows:
24
+ ## Advanced Commands
23
25
 
24
26
  | Command | Category | Description |
25
27
  |---------|----------|-------------|
26
28
  | `/OMG:deep-plan` | Planning | Strategic planning with domain awareness |
27
- | `/OMG:learn` | Knowledge | Create skills from patterns |
28
- | `/OMG:code-review` | Quality | Deep code review |
29
- | `/OMG:security-review` | Security | Security vulnerability scanning |
30
- | `/OMG:ship` | Delivery | Ship pipeline (idea PR) |
31
- | `/OMG:handoff` | Collaboration | Session transfer |
32
- | `/OMG:maintainer` | OSS | Open-source maintainer tools |
33
- | `/OMG:sequential-thinking` | Thinking | Structured reasoning |
34
- | `/OMG:ralph-start` | Automation | Start Ralph loop |
35
- | `/OMG:ralph-stop` | Automation | Stop Ralph loop |
29
+ | `/OMG:learn` | Knowledge | Convert patterns into OMG-native instincts and skills |
30
+ | `/OMG:code-review` | Quality | Deep review flow |
31
+ | `/OMG:security-review` | Security | Security-focused review |
32
+ | `/OMG:ship` | Delivery | Idea to evidence to release |
33
+ | `/OMG:handoff` | Collaboration | Session transfer and continuity |
36
34
 
37
- ## Plugin Architecture
35
+ ## Plugin Layout
38
36
 
39
- Commands are organized as plugins:
40
-
41
- ```
37
+ ```text
42
38
  plugins/
43
- ├── core/ # Essential commands
44
- │ ├── commands/ # Command definitions
45
- │ └── plugin.json # Plugin manifest
46
- └── advanced/ # Extended commands
47
- ├── commands/
48
- └── plugin.json
49
- ```
50
-
51
- ### Using Advanced Commands
52
-
53
- Advanced commands work the same as core commands:
54
-
55
- ```
56
- /OMG:deep-plan implement OAuth2 flow
57
- /OMG:learn from this session
58
- /OMG:code-review src/auth.ts
39
+ core/
40
+ commands/
41
+ plugin.json
42
+ advanced/
43
+ commands/
44
+ plugin.json
59
45
  ```
60
46
 
61
- ### Creating Custom Plugins
62
-
63
- 1. Create `plugins/my-plugin/plugin.json`
64
- 2. Add commands to `plugins/my-plugin/commands/`
65
- 3. OMG auto-discovers plugins on startup
66
-
67
- See `plugins/advanced/` for examples.
68
-
69
- ## Migration from Legacy Plugins
47
+ ## Adoption Notes
70
48
 
71
- Advanced commands are OMG-native equivalents of legacy plugin capabilities:
49
+ Public migration commands are intentionally avoided. OMG uses `/OMG:setup` and `OMG-setup.sh` to detect and adopt older ecosystems internally, while `compat` remains focused on legacy skill routing.
72
50
 
73
- | Legacy Plugin | OMG Advanced |
74
- |-------------|--------------|
75
- | `writing-plans` | `/OMG:deep-plan` |
76
- | `learner` | `/OMG:learn` |
77
- | `requesting-code-review` | `/OMG:code-review` |
78
- | `security-review` | `/OMG:security-review` |
79
- | `finishing-a-development-branch` | `/OMG:ship` |
80
- | `handoff` | `/OMG:handoff` |
51
+ ## Public Docs
81
52
 
82
- OMG advanced commands are designed for OMG standalone mode without requiring external plugins.
53
+ - Install guides live in [docs/install/claude-code.md](../docs/install/claude-code.md), [docs/install/codex.md](../docs/install/codex.md), and [docs/install/opencode.md](../docs/install/opencode.md).
54
+ - Proof surface lives in [docs/proof.md](../docs/proof.md).
@@ -37,10 +37,10 @@ Examples of GOOD questions:
37
37
  Read the codebase to understand the CURRENT state:
38
38
  ```bash
39
39
  # Directory structure
40
- find . -type f \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" -o -name "*.go" \) | head -50
40
+ find . -type f -name "*.ts" -o -name "*.py" -o -name "*.go" | head -50
41
41
 
42
42
  # Key architectural patterns
43
- grep -rn "export class\|export function\|function \|const .*=\|func \|struct " src/ --include="*.{ts,tsx,js,jsx,go}" | head -30
43
+ grep -rn "export class\|export function\|def \|func \|struct " src/ --include="*.{ts,py,go}" | head -30
44
44
 
45
45
  # Existing domain boundaries
46
46
  ls -la src/*/ # or app/*/ or packages/*/
@@ -140,7 +140,7 @@ After validation, launch exactly 5 planning tracks with mixed-model intent using
140
140
 
141
141
  Dispatch pattern is mandatory: all 5 tracks launch in parallel as background sub-agents.
142
142
 
143
- ```text
143
+ ```python
144
144
  task(subagent_type="explore", run_in_background=true, load_skills=[], description="Architect planning track", prompt="...")
145
145
  task(subagent_type="explore", run_in_background=true, load_skills=[], description="Backend planning track", prompt="...")
146
146
  task(subagent_type="explore", run_in_background=true, load_skills=[], description="Frontend planning track", prompt="...")
@@ -99,7 +99,7 @@ When detecting patterns, especially look for:
99
99
  ## Aggregated Patterns (Auto)
100
100
  When you run `/OMG:learn auto`, OMG reads all learning files from `.omg/state/learnings/` and generates `.omg/knowledge/critical-patterns.md` with your top tool and file patterns.
101
101
 
102
- Regenerate by rerunning `/OMG:learn auto` after a representative session.
102
+ Run: `python3 -c "import sys; sys.path.insert(0,'hooks'); from _learnings import save_critical_patterns; save_critical_patterns('.')"`
103
103
  ## File Write Fallback
104
104
  If `Write` fails (file exists), use `Edit` or Bash heredoc:
105
105
  ```bash
@@ -16,13 +16,13 @@ Determine what to scan:
16
16
  Identify security-critical files automatically:
17
17
  ```bash
18
18
  # Auth/session
19
- find . -type f \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" -o -name "*.go" -o -name "*.rs" \) | xargs grep -li "auth\|login\|session\|token\|password\|jwt\|oauth" 2>/dev/null
19
+ find . -type f \( -name "*.ts" -o -name "*.js" -o -name "*.py" -o -name "*.go" -o -name "*.rs" \) | xargs grep -li "auth\|login\|session\|token\|password\|jwt\|oauth" 2>/dev/null
20
20
 
21
21
  # Payment
22
- find . -type f \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" -o -name "*.go" \) | xargs grep -li "payment\|billing\|stripe\|checkout\|card\|price" 2>/dev/null
22
+ find . -type f -name "*.{ts,js,py,go}" | xargs grep -li "payment\|billing\|stripe\|checkout\|card\|price" 2>/dev/null
23
23
 
24
24
  # Database
25
- find . -type f \( -name "*.ts" -o -name "*.tsx" -o -name "*.js" -o -name "*.jsx" -o -name "*.go" \) | xargs grep -li "query\|SELECT\|INSERT\|UPDATE\|DELETE\|migration\|schema" 2>/dev/null
25
+ find . -type f -name "*.{ts,js,py,go}" | xargs grep -li "query\|SELECT\|INSERT\|UPDATE\|DELETE\|migration\|schema" 2>/dev/null
26
26
  ```
27
27
 
28
28
  ## Step 2: Automated Vulnerability Scan
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  description: Ship pipeline — Idea -> Plan -> Execute -> Evidence -> PR-ready summary
3
- allowed-tools: Read, Write, Edit, MultiEdit, Grep, Glob, Bash(git:*), Bash(rg:*), Bash(find:*), Bash(cat:*), Bash(bun:*), Bash(npm test:*), Bash(go test:*), Bash(cargo test:*), Bash(jest:*), Bash(vitest:*)
3
+ allowed-tools: Read, Write, Edit, MultiEdit, Grep, Glob, Bash(git:*), Bash(rg:*), Bash(find:*), Bash(cat:*), Bash(python3:*), Bash(pytest:*), Bash(npm test:*), Bash(go test:*), Bash(cargo test:*), Bash(jest:*), Bash(vitest:*)
4
4
  argument-hint: "[goal or optional path to .omg/idea.yml]"
5
5
  ---
6
6
 
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omg-advanced",
3
- "version": "2.0.0",
3
+ "version": "1.0.5",
4
4
  "description": "Advanced OMG commands - deep planning, learning, code review, security review, and specialized workflows",
5
5
  "type": "omg-plugin",
6
6
  "commands": {
@@ -1,9 +1,14 @@
1
1
  {
2
2
  "name": "omg-core",
3
- "version": "2.0.0",
4
- "description": "Core OMG commands - essential functionality for routing, initialization, and multi-agent orchestration",
3
+ "version": "2.0.2",
4
+ "description": "Core OMG commands - native setup, routing, orchestration, and verification surfaces",
5
5
  "type": "omg-plugin",
6
6
  "commands": {
7
+ "setup": {
8
+ "path": "commands/OMG:setup.md",
9
+ "description": "Native OMG setup and adoption flow for supported hosts",
10
+ "category": "setup"
11
+ },
7
12
  "init": {
8
13
  "path": "commands/OMG:init.md",
9
14
  "description": "Unified initializer for project setup and domain scaffolding",
@@ -81,7 +86,7 @@
81
86
  "categories": {
82
87
  "setup": {
83
88
  "description": "Project initialization and setup",
84
- "commands": ["init", "health-check"]
89
+ "commands": ["setup", "init", "health-check"]
85
90
  },
86
91
  "routing": {
87
92
  "description": "Model routing and escalation",
File without changes
@@ -0,0 +1,188 @@
1
+ from __future__ import annotations
2
+
3
+ import json
4
+ import os
5
+ from datetime import datetime, timedelta, timezone
6
+ from pathlib import Path
7
+ from typing import Any
8
+ import urllib.error
9
+ import urllib.request
10
+
11
+
12
+ OSV_BATCH_URL = "https://api.osv.dev/v1/querybatch"
13
+ CACHE_REL_PATH = Path(".omg") / "state" / "cve-cache.json"
14
+ CACHE_TTL_HOURS = 24
15
+
16
+
17
+ def _dep_health_enabled() -> bool:
18
+ env_val = os.environ.get("OMG_DEP_HEALTH_ENABLED", "").lower()
19
+ if env_val in ("1", "true", "yes"):
20
+ return True
21
+ if env_val in ("0", "false", "no"):
22
+ return False
23
+ try:
24
+ import sys
25
+ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
26
+ from hooks._common import get_feature_flag
27
+ return get_feature_flag("DEP_HEALTH", default=False)
28
+ except Exception:
29
+ return False
30
+
31
+
32
+ def scan_for_cves(dependency_list: list[dict[str, str]], project_dir: str = ".") -> dict[str, Any]:
33
+ if not _dep_health_enabled():
34
+ return {"results": {}, "cached": False, "scan_ts": datetime.now(timezone.utc).isoformat()}
35
+
36
+ now = datetime.now(timezone.utc)
37
+ cache_path = Path(project_dir) / CACHE_REL_PATH
38
+ cached_payload = _load_cache(cache_path)
39
+
40
+ if not dependency_list:
41
+ return {
42
+ "results": {},
43
+ "cached": False,
44
+ "scan_ts": now.isoformat(),
45
+ }
46
+
47
+ if cached_payload and _is_cache_fresh(cached_payload.get("scan_ts")):
48
+ return {
49
+ "results": cached_payload.get("results", {}),
50
+ "cached": True,
51
+ "scan_ts": cached_payload.get("scan_ts", now.isoformat()),
52
+ }
53
+
54
+ try:
55
+ osv_response = _query_osv_batch(dependency_list)
56
+ except urllib.error.URLError:
57
+ if cached_payload:
58
+ return {
59
+ "results": cached_payload.get("results", {}),
60
+ "cached": True,
61
+ "scan_ts": cached_payload.get("scan_ts", now.isoformat()),
62
+ }
63
+ return {"status": "offline", "results": {}, "cached": False}
64
+
65
+ structured_results = _normalize_results(dependency_list, osv_response)
66
+ scan_result = {
67
+ "results": structured_results,
68
+ "cached": False,
69
+ "scan_ts": now.isoformat(),
70
+ }
71
+ _save_cache(cache_path, scan_result)
72
+ return scan_result
73
+
74
+
75
+ def _query_osv_batch(dependency_list: list[dict[str, str]]) -> dict[str, Any]:
76
+ payload = {
77
+ "queries": [
78
+ {
79
+ "package": {
80
+ "name": dependency["name"],
81
+ "ecosystem": dependency["ecosystem"],
82
+ },
83
+ "version": dependency["version"],
84
+ }
85
+ for dependency in dependency_list
86
+ ]
87
+ }
88
+
89
+ request = urllib.request.Request(
90
+ OSV_BATCH_URL,
91
+ data=json.dumps(payload).encode("utf-8"),
92
+ headers={"Content-Type": "application/json"},
93
+ method="POST",
94
+ )
95
+
96
+ with urllib.request.urlopen(request) as response:
97
+ body = response.read().decode("utf-8")
98
+ return json.loads(body)
99
+
100
+
101
+ def _normalize_results(
102
+ dependency_list: list[dict[str, str]], osv_response: dict[str, Any]
103
+ ) -> dict[str, list[dict[str, Any]]]:
104
+ output: dict[str, list[dict[str, Any]]] = {}
105
+ response_results = osv_response.get("results", [])
106
+
107
+ for index, dependency in enumerate(dependency_list):
108
+ pkg_name = dependency.get("name", "")
109
+ query_result = response_results[index] if index < len(response_results) else {}
110
+ vulns = query_result.get("vulns", [])
111
+
112
+ normalized_vulns: list[dict[str, Any]] = []
113
+ for vuln in vulns:
114
+ affected_versions, fixed_version = _extract_affected(vuln)
115
+ normalized_vulns.append(
116
+ {
117
+ "id": vuln.get("id", ""),
118
+ "severity": _extract_severity(vuln),
119
+ "summary": vuln.get("summary", ""),
120
+ "affected_versions": affected_versions,
121
+ "fixed_version": fixed_version,
122
+ }
123
+ )
124
+
125
+ output[pkg_name] = normalized_vulns
126
+
127
+ return output
128
+
129
+
130
+ def _extract_severity(vuln: dict[str, Any]) -> str:
131
+ severities = vuln.get("severity") or []
132
+ if severities and isinstance(severities[0], dict):
133
+ score = severities[0].get("score")
134
+ if score:
135
+ return str(score)
136
+ return "UNKNOWN"
137
+
138
+
139
+ def _extract_affected(vuln: dict[str, Any]) -> tuple[list[str], str]:
140
+ affected_versions: list[str] = []
141
+ fixed_version = ""
142
+
143
+ for affected in vuln.get("affected", []) or []:
144
+ for version in affected.get("versions", []) or []:
145
+ affected_versions.append(str(version))
146
+
147
+ for version_range in affected.get("ranges", []) or []:
148
+ for event in version_range.get("events", []) or []:
149
+ introduced = event.get("introduced")
150
+ fixed = event.get("fixed")
151
+ if introduced:
152
+ affected_versions.append(str(introduced))
153
+ if fixed and not fixed_version:
154
+ fixed_version = str(fixed)
155
+
156
+ deduped_versions = list(dict.fromkeys(affected_versions))
157
+ return deduped_versions, fixed_version
158
+
159
+
160
+ def _load_cache(cache_path: Path) -> dict[str, Any] | None:
161
+ if not cache_path.exists():
162
+ return None
163
+ try:
164
+ return json.loads(cache_path.read_text(encoding="utf-8"))
165
+ except (OSError, json.JSONDecodeError):
166
+ return None
167
+
168
+
169
+ def _save_cache(cache_path: Path, payload: dict[str, Any]) -> None:
170
+ try:
171
+ cache_path.parent.mkdir(parents=True, exist_ok=True)
172
+ cache_path.write_text(json.dumps(payload, separators=(",", ":")), encoding="utf-8")
173
+ except OSError:
174
+ return
175
+
176
+
177
+ def _is_cache_fresh(scan_ts: str | None) -> bool:
178
+ if not scan_ts:
179
+ return False
180
+ try:
181
+ scanned_at = datetime.fromisoformat(scan_ts)
182
+ except ValueError:
183
+ return False
184
+
185
+ if scanned_at.tzinfo is None:
186
+ scanned_at = scanned_at.replace(tzinfo=timezone.utc)
187
+
188
+ return datetime.now(timezone.utc) - scanned_at < timedelta(hours=CACHE_TTL_HOURS)
@@ -0,0 +1,135 @@
1
+ """License compatibility checker for dependency health analysis.
2
+
3
+ Checks whether project dependencies have licenses compatible with
4
+ the project's own license using a static compatibility matrix.
5
+ No network access required.
6
+ """
7
+
8
+ from __future__ import annotations
9
+ import os
10
+ from typing import Any
11
+
12
+ # License categories (restrictiveness increases top to bottom)
13
+ _PERMISSIVE = frozenset({
14
+ "MIT", "BSD-2-Clause", "BSD-3-Clause", "ISC", "Unlicense", "CC0-1.0",
15
+ })
16
+
17
+ _WEAK_COPYLEFT = frozenset({
18
+ "Apache-2.0", "LGPL-2.1", "LGPL-3.0", "MPL-2.0",
19
+ })
20
+
21
+ _STRONG_COPYLEFT = frozenset({
22
+ "GPL-2.0", "GPL-3.0",
23
+ })
24
+
25
+ _NETWORK_COPYLEFT = frozenset({
26
+ "AGPL-3.0",
27
+ })
28
+
29
+ _ALL_KNOWN = _PERMISSIVE | _WEAK_COPYLEFT | _STRONG_COPYLEFT | _NETWORK_COPYLEFT
30
+
31
+
32
+ def _dep_health_enabled() -> bool:
33
+ env_val = os.environ.get("OMG_DEP_HEALTH_ENABLED", "").lower()
34
+ if env_val in ("1", "true", "yes"):
35
+ return True
36
+ if env_val in ("0", "false", "no"):
37
+ return False
38
+ try:
39
+ import sys
40
+ sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))
41
+ from hooks._common import get_feature_flag
42
+ return get_feature_flag("DEP_HEALTH", default=False)
43
+ except Exception:
44
+ return False
45
+
46
+
47
+ def _license_tier(license_id: str) -> int:
48
+ """Return restrictiveness tier: 0=permissive, 1=weak, 2=strong, 3=network."""
49
+ if license_id in _PERMISSIVE:
50
+ return 0
51
+ if license_id in _WEAK_COPYLEFT:
52
+ return 1
53
+ if license_id in _STRONG_COPYLEFT:
54
+ return 2
55
+ if license_id in _NETWORK_COPYLEFT:
56
+ return 3
57
+ return -1 # unknown
58
+
59
+
60
+ def check_license_compatibility(
61
+ project_license: str,
62
+ dependencies: list[dict[str, Any]],
63
+ ) -> dict[str, list[dict[str, str]]]:
64
+ """Check license compatibility between project and its dependencies.
65
+
66
+ Args:
67
+ project_license: SPDX identifier for the project license (e.g. "MIT").
68
+ dependencies: List of dicts with "name" and "license" keys.
69
+ License may be None or "UNKNOWN".
70
+
71
+ Returns:
72
+ Dict with three lists:
73
+ compatible: [{"pkg": str, "license": str}]
74
+ incompatible: [{"pkg": str, "license": str, "reason": str}]
75
+ unknown: [{"pkg": str}]
76
+ """
77
+ if not _dep_health_enabled():
78
+ return {"compatible": [], "incompatible": [], "unknown": []}
79
+
80
+ compatible: list[dict[str, str]] = []
81
+ incompatible: list[dict[str, str]] = []
82
+ unknown: list[dict[str, str]] = []
83
+
84
+ project_tier = _license_tier(project_license)
85
+
86
+ for dep in dependencies:
87
+ name = dep.get("name", "")
88
+ dep_license = dep.get("license")
89
+
90
+ # Unknown / missing license
91
+ if not dep_license or dep_license == "UNKNOWN":
92
+ unknown.append({"pkg": name})
93
+ continue
94
+
95
+ dep_tier = _license_tier(dep_license)
96
+
97
+ # Unrecognized license string
98
+ if dep_tier == -1:
99
+ unknown.append({"pkg": name})
100
+ continue
101
+
102
+ # AGPL dep in non-AGPL project is always incompatible
103
+ if dep_tier == 3 and project_tier != 3:
104
+ incompatible.append({
105
+ "pkg": name,
106
+ "license": dep_license,
107
+ "reason": (
108
+ f"AGPL-3.0 dependency in {project_license} project: "
109
+ f"network copyleft requires entire project to be AGPL-3.0"
110
+ ),
111
+ })
112
+ continue
113
+
114
+ # Strong copyleft dep in permissive/weak-copyleft project
115
+ if dep_tier == 2 and project_tier < 2:
116
+ incompatible.append({
117
+ "pkg": name,
118
+ "license": dep_license,
119
+ "reason": (
120
+ f"{dep_license} dependency in {project_license} project: "
121
+ f"copyleft contamination requires project to adopt {dep_license}"
122
+ ),
123
+ })
124
+ continue
125
+
126
+ # Everything else: permissive deps are always OK,
127
+ # weak copyleft in permissive is OK (dynamic linking),
128
+ # same-tier or higher-tier project can use lower-tier deps
129
+ compatible.append({"pkg": name, "license": dep_license})
130
+
131
+ return {
132
+ "compatible": compatible,
133
+ "incompatible": incompatible,
134
+ "unknown": unknown,
135
+ }