@trac3er/oh-my-god 1.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 (229) hide show
  1. package/.claude-plugin/marketplace.json +36 -0
  2. package/.claude-plugin/plugin.json +23 -0
  3. package/.claude-plugin/scripts/install.sh +49 -0
  4. package/.claude-plugin/scripts/uninstall.sh +80 -0
  5. package/.claude-plugin/scripts/update.sh +84 -0
  6. package/.mcp.json +20 -0
  7. package/LICENSE +21 -0
  8. package/OMG-setup.sh +1093 -0
  9. package/README.md +335 -0
  10. package/THIRD_PARTY_NOTICES.md +24 -0
  11. package/UPSTREAM_DIFF.md +20 -0
  12. package/agents/__init__.py +1 -0
  13. package/agents/_model_roles.yaml +26 -0
  14. package/agents/designer.md +67 -0
  15. package/agents/explore.md +60 -0
  16. package/agents/model_roles.py +196 -0
  17. package/agents/omg-api-builder.md +23 -0
  18. package/agents/omg-architect-mode.md +43 -0
  19. package/agents/omg-architect.md +13 -0
  20. package/agents/omg-backend-engineer.md +43 -0
  21. package/agents/omg-critic.md +16 -0
  22. package/agents/omg-database-engineer.md +43 -0
  23. package/agents/omg-escalation-router.md +17 -0
  24. package/agents/omg-executor.md +12 -0
  25. package/agents/omg-frontend-designer.md +42 -0
  26. package/agents/omg-implement-mode.md +50 -0
  27. package/agents/omg-infra-engineer.md +43 -0
  28. package/agents/omg-qa-tester.md +16 -0
  29. package/agents/omg-research-mode.md +43 -0
  30. package/agents/omg-security-auditor.md +43 -0
  31. package/agents/omg-testing-engineer.md +43 -0
  32. package/agents/plan.md +80 -0
  33. package/agents/quick_task.md +64 -0
  34. package/agents/reviewer.md +83 -0
  35. package/agents/task.md +71 -0
  36. package/commands/OMG:ccg.md +22 -0
  37. package/commands/OMG:compat.md +57 -0
  38. package/commands/OMG:crazy.md +125 -0
  39. package/commands/OMG:domain-init.md +11 -0
  40. package/commands/OMG:escalate.md +52 -0
  41. package/commands/OMG:health-check.md +45 -0
  42. package/commands/OMG:init.md +134 -0
  43. package/commands/OMG:mode.md +44 -0
  44. package/commands/OMG:project-init.md +11 -0
  45. package/commands/OMG:ralph-start.md +43 -0
  46. package/commands/OMG:ralph-stop.md +23 -0
  47. package/commands/OMG:teams.md +39 -0
  48. package/commands/ai-commit.md +113 -0
  49. package/commands/ccg.md +9 -0
  50. package/commands/create-agent.md +183 -0
  51. package/commands/omc-teams.md +9 -0
  52. package/commands/session-branch.md +85 -0
  53. package/commands/session-fork.md +53 -0
  54. package/commands/session-merge.md +134 -0
  55. package/commands/theme.md +44 -0
  56. package/config/lsp_languages.yaml +324 -0
  57. package/config/themes/catppuccin-frappe.yaml +14 -0
  58. package/config/themes/catppuccin-latte.yaml +14 -0
  59. package/config/themes/catppuccin-macchiato.yaml +14 -0
  60. package/config/themes/catppuccin-mocha.yaml +14 -0
  61. package/config/themes/dracula.yaml +14 -0
  62. package/config/themes/gruvbox-dark.yaml +14 -0
  63. package/config/themes/nord.yaml +14 -0
  64. package/config/themes/one-dark.yaml +14 -0
  65. package/config/themes/solarized-dark.yaml +14 -0
  66. package/config/themes/tokyo-night.yaml +14 -0
  67. package/control_plane/__init__.py +2 -0
  68. package/control_plane/openapi.yaml +109 -0
  69. package/control_plane/server.py +107 -0
  70. package/control_plane/service.py +148 -0
  71. package/crates/omg-natives/Cargo.toml +17 -0
  72. package/crates/omg-natives/src/clipboard.rs +5 -0
  73. package/crates/omg-natives/src/glob.rs +15 -0
  74. package/crates/omg-natives/src/grep.rs +15 -0
  75. package/crates/omg-natives/src/highlight.rs +15 -0
  76. package/crates/omg-natives/src/html.rs +14 -0
  77. package/crates/omg-natives/src/image.rs +5 -0
  78. package/crates/omg-natives/src/keys.rs +5 -0
  79. package/crates/omg-natives/src/lib.rs +36 -0
  80. package/crates/omg-natives/src/prof.rs +5 -0
  81. package/crates/omg-natives/src/ps.rs +5 -0
  82. package/crates/omg-natives/src/shell.rs +5 -0
  83. package/crates/omg-natives/src/task.rs +5 -0
  84. package/crates/omg-natives/src/text.rs +14 -0
  85. package/hooks/_agent_registry.py +421 -0
  86. package/hooks/_budget.py +31 -0
  87. package/hooks/_common.py +476 -0
  88. package/hooks/_learnings.py +126 -0
  89. package/hooks/_memory.py +103 -0
  90. package/hooks/circuit-breaker.py +270 -0
  91. package/hooks/config-guard.py +163 -0
  92. package/hooks/context_pressure.py +53 -0
  93. package/hooks/credential_store.py +801 -0
  94. package/hooks/fetch-rate-limits.py +212 -0
  95. package/hooks/firewall.py +48 -0
  96. package/hooks/hashline-formatter-bridge.py +224 -0
  97. package/hooks/hashline-injector.py +273 -0
  98. package/hooks/hashline-validator.py +216 -0
  99. package/hooks/idle-detector.py +95 -0
  100. package/hooks/intentgate-keyword-detector.py +188 -0
  101. package/hooks/magic-keyword-router.py +195 -0
  102. package/hooks/policy_engine.py +310 -0
  103. package/hooks/post-tool-failure.py +19 -0
  104. package/hooks/post-write.py +199 -0
  105. package/hooks/pre-compact.py +204 -0
  106. package/hooks/pre-tool-inject.py +98 -0
  107. package/hooks/prompt-enhancer.py +672 -0
  108. package/hooks/quality-runner.py +191 -0
  109. package/hooks/secret-guard.py +47 -0
  110. package/hooks/session-end-capture.py +137 -0
  111. package/hooks/session-start.py +275 -0
  112. package/hooks/shadow_manager.py +297 -0
  113. package/hooks/state_migration.py +209 -0
  114. package/hooks/stop-gate.py +7 -0
  115. package/hooks/stop_dispatcher.py +929 -0
  116. package/hooks/test-validator.py +138 -0
  117. package/hooks/todo-state-tracker.py +114 -0
  118. package/hooks/tool-ledger.py +126 -0
  119. package/hooks/trust_review.py +524 -0
  120. package/install.sh +9 -0
  121. package/omg_natives/__init__.py +186 -0
  122. package/omg_natives/_bindings.py +165 -0
  123. package/omg_natives/clipboard.py +36 -0
  124. package/omg_natives/glob.py +42 -0
  125. package/omg_natives/grep.py +61 -0
  126. package/omg_natives/highlight.py +54 -0
  127. package/omg_natives/html.py +157 -0
  128. package/omg_natives/image.py +51 -0
  129. package/omg_natives/keys.py +46 -0
  130. package/omg_natives/prof.py +39 -0
  131. package/omg_natives/ps.py +93 -0
  132. package/omg_natives/shell.py +58 -0
  133. package/omg_natives/task.py +41 -0
  134. package/omg_natives/text.py +50 -0
  135. package/package.json +26 -0
  136. package/plugins/README.md +82 -0
  137. package/plugins/advanced/commands/OMG:code-review.md +114 -0
  138. package/plugins/advanced/commands/OMG:deep-plan.md +221 -0
  139. package/plugins/advanced/commands/OMG:handoff.md +115 -0
  140. package/plugins/advanced/commands/OMG:learn.md +110 -0
  141. package/plugins/advanced/commands/OMG:maintainer.md +31 -0
  142. package/plugins/advanced/commands/OMG:ralph-start.md +43 -0
  143. package/plugins/advanced/commands/OMG:ralph-stop.md +23 -0
  144. package/plugins/advanced/commands/OMG:security-review.md +119 -0
  145. package/plugins/advanced/commands/OMG:sequential-thinking.md +20 -0
  146. package/plugins/advanced/commands/OMG:ship.md +46 -0
  147. package/plugins/advanced/plugin.json +96 -0
  148. package/plugins/core/plugin.json +82 -0
  149. package/pytest.ini +5 -0
  150. package/registry/__init__.py +1 -0
  151. package/registry/verify_artifact.py +90 -0
  152. package/rules/contextual/architect-mode.md +9 -0
  153. package/rules/contextual/big-picture.md +20 -0
  154. package/rules/contextual/code-hygiene.md +26 -0
  155. package/rules/contextual/context-management.md +19 -0
  156. package/rules/contextual/context-minimization.md +32 -0
  157. package/rules/contextual/ddd-sdd.md +28 -0
  158. package/rules/contextual/dependency-safety.md +16 -0
  159. package/rules/contextual/doc-check.md +13 -0
  160. package/rules/contextual/implement-mode.md +9 -0
  161. package/rules/contextual/infra-safety.md +14 -0
  162. package/rules/contextual/outside-in.md +13 -0
  163. package/rules/contextual/persistent-mode.md +24 -0
  164. package/rules/contextual/research-mode.md +9 -0
  165. package/rules/contextual/security-domains.md +25 -0
  166. package/rules/contextual/vision-detection.md +27 -0
  167. package/rules/contextual/web-search.md +25 -0
  168. package/rules/contextual/write-verify.md +23 -0
  169. package/rules/core/00-truth.md +20 -0
  170. package/rules/core/01-surgical.md +19 -0
  171. package/rules/core/02-circuit-breaker.md +22 -0
  172. package/rules/core/03-ensemble.md +28 -0
  173. package/rules/core/04-testing.md +30 -0
  174. package/runtime/__init__.py +32 -0
  175. package/runtime/adapters/__init__.py +13 -0
  176. package/runtime/adapters/claude.py +60 -0
  177. package/runtime/adapters/gpt.py +53 -0
  178. package/runtime/adapters/local.py +53 -0
  179. package/runtime/business_workflow.py +220 -0
  180. package/runtime/compat.py +1299 -0
  181. package/runtime/custom_agent_loader.py +366 -0
  182. package/runtime/dispatcher.py +47 -0
  183. package/runtime/ecosystem.py +371 -0
  184. package/runtime/legacy_compat.py +7 -0
  185. package/runtime/omc_compat.py +7 -0
  186. package/runtime/omc_contract_snapshot.json +916 -0
  187. package/runtime/omg_compat_contract_snapshot.json +916 -0
  188. package/runtime/subagent_dispatcher.py +362 -0
  189. package/runtime/team_router.py +838 -0
  190. package/scripts/check-omc-contract-snapshot.py +12 -0
  191. package/scripts/check-omg-compat-contract-snapshot.py +137 -0
  192. package/scripts/check-omg-standalone-clean.py +102 -0
  193. package/scripts/legacy_to_omg_migrate.py +29 -0
  194. package/scripts/migrate-omc.py +464 -0
  195. package/scripts/omc_to_omg_migrate.py +12 -0
  196. package/scripts/omg.py +493 -0
  197. package/scripts/settings-merge.py +224 -0
  198. package/scripts/verify-no-omc.sh +5 -0
  199. package/scripts/verify-standalone.sh +21 -0
  200. package/templates/idea.yml +30 -0
  201. package/templates/policy.yaml +15 -0
  202. package/templates/profile.yaml +25 -0
  203. package/templates/runtime.yaml +12 -0
  204. package/templates/working-memory.md +17 -0
  205. package/tools/__init__.py +2 -0
  206. package/tools/browser_consent.py +289 -0
  207. package/tools/browser_stealth.py +481 -0
  208. package/tools/browser_tool.py +448 -0
  209. package/tools/changelog_generator.py +268 -0
  210. package/tools/commit_splitter.py +361 -0
  211. package/tools/config_discovery.py +151 -0
  212. package/tools/config_merger.py +449 -0
  213. package/tools/git_inspector.py +298 -0
  214. package/tools/lsp_client.py +275 -0
  215. package/tools/lsp_discovery.py +231 -0
  216. package/tools/lsp_operations.py +392 -0
  217. package/tools/python_repl.py +656 -0
  218. package/tools/python_sandbox.py +609 -0
  219. package/tools/search_providers/__init__.py +77 -0
  220. package/tools/search_providers/brave.py +115 -0
  221. package/tools/search_providers/exa.py +116 -0
  222. package/tools/search_providers/jina.py +104 -0
  223. package/tools/search_providers/perplexity.py +139 -0
  224. package/tools/search_providers/synthetic.py +74 -0
  225. package/tools/session_snapshot.py +736 -0
  226. package/tools/ssh_manager.py +912 -0
  227. package/tools/theme_engine.py +294 -0
  228. package/tools/theme_selector.py +137 -0
  229. package/tools/web_search.py +622 -0
@@ -0,0 +1,224 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ settings-merge.py
4
+ Merges v2 hooks + permissions INTO existing ~/.claude/settings.json
5
+ without destroying existing non-OMG configuration.
6
+
7
+ Strategy:
8
+ - hooks{}: APPEND our matchers to each event (never replace existing)
9
+ - permissions.allow[]: UNION (add ours, keep theirs)
10
+ - permissions.deny[]: UNION
11
+ - permissions.ask[]: UNION
12
+ - Everything else: PRESERVE as-is
13
+ """
14
+ import json
15
+ import sys
16
+ import os
17
+ import shutil
18
+ from datetime import datetime
19
+
20
+ def load_json(path):
21
+ if not os.path.exists(path):
22
+ return {}
23
+ try:
24
+ with open(path, "r") as f:
25
+ return json.load(f)
26
+ except json.JSONDecodeError as e:
27
+ print(f"ERROR: {path} contains invalid JSON (line {e.lineno}, col {e.colno}):", file=sys.stderr)
28
+ print(f" {e.msg}", file=sys.stderr)
29
+ print(f" Fix the file manually or delete it to start fresh.", file=sys.stderr)
30
+ sys.exit(1)
31
+ except PermissionError:
32
+ print(f"ERROR: Cannot read {path} — permission denied.", file=sys.stderr)
33
+ sys.exit(1)
34
+ except Exception as e:
35
+ print(f"ERROR: Failed to read {path}: {e}", file=sys.stderr)
36
+ sys.exit(1)
37
+
38
+ def merge_hooks(existing_hooks, new_hooks):
39
+ """Append new hook matchers to existing, avoiding duplicates."""
40
+ merged = dict(existing_hooks) # shallow copy
41
+
42
+ def extract_commands(entry):
43
+ commands = set()
44
+ if not isinstance(entry, dict):
45
+ return commands
46
+ hooks = entry.get("hooks")
47
+ if isinstance(hooks, list):
48
+ for hook in hooks:
49
+ if not isinstance(hook, dict):
50
+ continue
51
+ cmd = hook.get("command", "") or hook.get("prompt", "")
52
+ if cmd:
53
+ commands.add(cmd)
54
+ return commands
55
+ cmd = entry.get("command", "") or entry.get("prompt", "")
56
+ if cmd:
57
+ commands.add(cmd)
58
+ return commands
59
+
60
+ for event, matchers in new_hooks.items():
61
+ if event not in merged:
62
+ merged[event] = matchers
63
+ continue
64
+
65
+ existing_matchers = merged[event]
66
+
67
+ for new_matcher in matchers:
68
+ new_cmds = extract_commands(new_matcher)
69
+
70
+ # Check if this exact matcher+command combo already exists
71
+ already_exists = False
72
+ for em in existing_matchers:
73
+ existing_cmds = extract_commands(em)
74
+ same_matcher = em.get("matcher") == new_matcher.get("matcher")
75
+ if new_cmds and same_matcher and (new_cmds & existing_cmds):
76
+ already_exists = True
77
+ break
78
+ if not new_cmds and em == new_matcher:
79
+ already_exists = True
80
+ break
81
+
82
+ if not already_exists:
83
+ existing_matchers.append(new_matcher)
84
+
85
+ return merged
86
+
87
+ def merge_permission_list(existing, new):
88
+ """Union two permission lists, preserving order (existing first)."""
89
+ seen = set(existing)
90
+ merged = list(existing)
91
+ for item in new:
92
+ if item not in seen:
93
+ merged.append(item)
94
+ seen.add(item)
95
+ return merged
96
+
97
+
98
+ def merge_mcp_servers(existing, new):
99
+ merged = dict(existing or {})
100
+ for name, config in (new or {}).items():
101
+ if name not in merged:
102
+ merged[name] = config
103
+ continue
104
+ existing_cfg = merged.get(name)
105
+ if isinstance(existing_cfg, dict) and isinstance(config, dict):
106
+ merged_cfg = dict(existing_cfg)
107
+ if "args" in config:
108
+ existing_args = merged_cfg.get("args", []) if isinstance(merged_cfg.get("args", []), list) else []
109
+ new_args = config.get("args", []) if isinstance(config.get("args", []), list) else []
110
+ merged_args = list(existing_args)
111
+ for arg in new_args:
112
+ if arg not in merged_args:
113
+ merged_args.append(arg)
114
+ merged_cfg["args"] = merged_args
115
+ if "env" in config and isinstance(config.get("env"), dict):
116
+ env = dict(merged_cfg.get("env", {})) if isinstance(merged_cfg.get("env"), dict) else {}
117
+ for key, value in config["env"].items():
118
+ env.setdefault(key, value)
119
+ merged_cfg["env"] = env
120
+ for key, value in config.items():
121
+ merged_cfg.setdefault(key, value)
122
+ merged[name] = merged_cfg
123
+ return merged
124
+
125
+ def merge_settings(existing, new):
126
+ """
127
+ Merge strategy:
128
+ - hooks: append per-event
129
+ - permissions: union per-category
130
+ - everything else in existing: preserve
131
+ - $schema: use new if not present
132
+ """
133
+ merged = dict(existing)
134
+
135
+ # Schema
136
+ if "$schema" not in merged and "$schema" in new:
137
+ merged["$schema"] = new["$schema"]
138
+
139
+ # Hooks
140
+ if "hooks" in new:
141
+ existing_hooks = merged.get("hooks", {})
142
+ merged["hooks"] = merge_hooks(existing_hooks, new["hooks"])
143
+
144
+ # Permissions
145
+ if "permissions" in new:
146
+ existing_perms = merged.get("permissions", {})
147
+ new_perms = new["permissions"]
148
+ merged_perms = dict(existing_perms)
149
+
150
+ for category in ("allow", "deny", "ask"):
151
+ if category in new_perms:
152
+ existing_list = existing_perms.get(category, [])
153
+ merged_perms[category] = merge_permission_list(
154
+ existing_list, new_perms[category]
155
+ )
156
+
157
+ merged["permissions"] = merged_perms
158
+
159
+ if "mcpServers" in new:
160
+ merged["mcpServers"] = merge_mcp_servers(merged.get("mcpServers", {}), new.get("mcpServers", {}))
161
+
162
+ return merged
163
+
164
+ def main():
165
+ if len(sys.argv) < 3:
166
+ print("Usage: settings-merge.py <existing.json> <new.json> [--dry-run]")
167
+ sys.exit(1)
168
+
169
+ existing_path = sys.argv[1]
170
+ new_path = sys.argv[2]
171
+ dry_run = "--dry-run" in sys.argv
172
+
173
+ existing = load_json(existing_path)
174
+ new = load_json(new_path)
175
+
176
+ merged = merge_settings(existing, new)
177
+
178
+ if dry_run:
179
+ print(json.dumps(merged, indent=2))
180
+ print(f"\n--- DRY RUN ---", file=sys.stderr)
181
+ # Show what was added
182
+ new_hooks = set()
183
+ for event, matchers in new.get("hooks", {}).items():
184
+ for m in matchers:
185
+ for h in m.get("hooks", []):
186
+ cmd = h.get("command", "")
187
+ if cmd:
188
+ new_hooks.add(f" {event}: {os.path.basename(cmd.split()[-1])}")
189
+ if new_hooks:
190
+ print(f"Hooks to add:", file=sys.stderr)
191
+ for h in sorted(new_hooks):
192
+ print(h, file=sys.stderr)
193
+
194
+ for cat in ("allow", "deny", "ask"):
195
+ existing_set = set(existing.get("permissions", {}).get(cat, []))
196
+ new_set = set(new.get("permissions", {}).get(cat, []))
197
+ added = new_set - existing_set
198
+ if added:
199
+ print(f"permissions.{cat} to add: {len(added)} rules", file=sys.stderr)
200
+ return
201
+
202
+ # Backup existing
203
+ if os.path.exists(existing_path):
204
+ ts = datetime.now().strftime("%Y%m%d_%H%M%S")
205
+ backup = f"{existing_path}.bak.{ts}"
206
+ shutil.copy2(existing_path, backup)
207
+ print(f"📦 Backed up: {backup}")
208
+
209
+ with open(existing_path, "w") as f:
210
+ json.dump(merged, f, indent=2)
211
+ f.write("\n")
212
+
213
+ print(f"✅ Merged into: {existing_path}")
214
+
215
+ # Summary
216
+ hook_events = list(merged.get("hooks", {}).keys())
217
+ allow_count = len(merged.get("permissions", {}).get("allow", []))
218
+ deny_count = len(merged.get("permissions", {}).get("deny", []))
219
+ ask_count = len(merged.get("permissions", {}).get("ask", []))
220
+ print(f" Hooks: {', '.join(hook_events)}")
221
+ print(f" Permissions: {allow_count} allow, {deny_count} deny, {ask_count} ask")
222
+
223
+ if __name__ == "__main__":
224
+ main()
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
5
+ exec "$SCRIPT_DIR/verify-standalone.sh" "$@"
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
5
+ TMP_DIR="${1:-$(mktemp -d)}"
6
+
7
+ echo "[verify-standalone] source: $ROOT_DIR"
8
+ echo "[verify-standalone] workdir: $TMP_DIR"
9
+
10
+ tar --exclude="./.omc" --exclude="./.pytest_cache" -cf - -C "$ROOT_DIR" . | (cd "$TMP_DIR" && tar -xf -)
11
+
12
+ cd "$TMP_DIR"
13
+ python3 scripts/omg.py compat gate --max-bridge 0 --output .omg/evidence/omg-compat-gap.json
14
+
15
+ if command -v pyenv >/dev/null 2>&1 && pyenv prefix 3.12.7 >/dev/null 2>&1; then
16
+ PYENV_VERSION=3.12.7 python -m pytest -q
17
+ else
18
+ python3 -m pytest -q
19
+ fi
20
+
21
+ echo "[verify-standalone] passed"
@@ -0,0 +1,30 @@
1
+ # OMG Idea Contract
2
+ # Single source of intent for Idea -> Evidence -> PR automation.
3
+
4
+ goal: ""
5
+ constraints:
6
+ - ""
7
+ acceptance:
8
+ - ""
9
+ risk:
10
+ security:
11
+ - ""
12
+ performance:
13
+ - ""
14
+ compatibility:
15
+ - ""
16
+ evidence_required:
17
+ tests:
18
+ - ""
19
+ security_scans:
20
+ - ""
21
+ reproducibility:
22
+ - ""
23
+ artifacts:
24
+ - "diff"
25
+ - "summary"
26
+ metadata:
27
+ owner: ""
28
+ priority: "medium" # low | medium | high | critical
29
+ target_branch: ""
30
+ created_at: ""
@@ -0,0 +1,15 @@
1
+ version: omg-v1
2
+ mode: warn_and_run
3
+ critical_always_block: true
4
+ require_evidence_pack: true
5
+ trust:
6
+ distrust_paths:
7
+ - ".claude/"
8
+ - ".omc/"
9
+ - ".omg/"
10
+ review_mcp_changes: true
11
+ review_hook_changes: true
12
+ supply_chain:
13
+ require_signature: false
14
+ require_checksum: false
15
+ enforce_sandbox: true
@@ -0,0 +1,25 @@
1
+ # .omc/profile.yaml — Project identity (injected every session)
2
+ # Keep under 20 lines. This is a quick-reference, not documentation.
3
+
4
+ name: ""
5
+ description: ""
6
+ repo: ""
7
+
8
+ language: ""
9
+ framework: ""
10
+ database: ""
11
+ infra: ""
12
+ key_deps: []
13
+
14
+ conventions:
15
+ naming: "" # camelCase / snake_case / etc
16
+ test_cmd: "" # npm test / pytest / cargo test
17
+ lint_cmd: "" # eslint / ruff / clippy
18
+ format_cmd: "" # prettier / ruff format / rustfmt
19
+
20
+ ai_behavior:
21
+ communication: "direct, bilingual OK"
22
+ locale_hint: "auto" # auto | ko | en | ja | zh — helps keyword detection
23
+ when_stuck: "Ask user after 2 failed attempts, or /escalate"
24
+ testing: "User-journey focused. No boilerplate."
25
+ code_style: "Match existing patterns. Don't introduce new frameworks."
@@ -0,0 +1,12 @@
1
+ version: omg-v1
2
+ runtime_order:
3
+ - claude
4
+ - gpt
5
+ - local
6
+ parity:
7
+ enforce_common_output_schema: true
8
+ fail_on_schema_mismatch: true
9
+ timeouts:
10
+ plan_sec: 60
11
+ execute_sec: 900
12
+ verify_sec: 600
@@ -0,0 +1,17 @@
1
+ # Working Memory
2
+ Last updated: [date]
3
+
4
+ ## Current Gomg
5
+ [What we're trying to achieve right now]
6
+
7
+ ## Progress
8
+ [N/M steps] | Branch: [name]
9
+
10
+ ## Active Decisions
11
+ - [Decision]: [rationale] (date)
12
+
13
+ ## Blockers
14
+ - [None]
15
+
16
+ ## Don't Repeat (failed approaches)
17
+ - [None yet]
@@ -0,0 +1,2 @@
1
+ # tools package
2
+ """OMG tools — LSP client, language configs, and related utilities."""
@@ -0,0 +1,289 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Browser Consent Manager for OMG
4
+
5
+ Manages explicit user consent for browser stealth mode. Provides a ToS warning
6
+ display, consent recording with timestamps, and persistent consent state.
7
+
8
+ Consent file: .omg/state/browser_consent.json
9
+ Format: {"consented": true/false, "acknowledged_at": "ISO timestamp", "version": "1.0"}
10
+
11
+ IMPORTANT:
12
+ - show_warning() returns text; caller decides how to display
13
+ - record_consent() is the ONLY function that writes consent state
14
+ - No consent is stored without explicit user action
15
+ - import alone does NOT trigger any side effects
16
+ """
17
+
18
+ import json
19
+ import os
20
+ import sys
21
+ from datetime import datetime, timezone
22
+ from typing import Any, Dict, Optional
23
+
24
+ # --- Consent version ---
25
+ CONSENT_VERSION = "1.0"
26
+
27
+ # --- Consent file relative path ---
28
+ CONSENT_REL_PATH = os.path.join(".omg", "state", "browser_consent.json")
29
+
30
+ # --- Warning text ---
31
+ _WARNING_TEXT = """\
32
+ ╔══════════════════════════════════════════════════════════════════╗
33
+ ║ ⚠ WARNING ⚠ ║
34
+ ╠══════════════════════════════════════════════════════════════════╣
35
+ ║ ║
36
+ ║ You are about to enable Browser Stealth Mode. ║
37
+ ║ ║
38
+ ║ This feature modifies browser fingerprints and injects ║
39
+ ║ JavaScript to evade bot-detection systems. Using stealth ║
40
+ ║ plugins may violate the Terms of Service of websites you ║
41
+ ║ visit. ║
42
+ ║ ║
43
+ ║ By granting explicit consent, you acknowledge that: ║
44
+ ║ ║
45
+ ║ 1. You understand the stealth plugins alter browser behavior ║
46
+ ║ 2. You accept responsibility for compliance with applicable ║
47
+ ║ Terms of Service and laws ║
48
+ ║ 3. OMG provides these tools as-is, without warranty ║
49
+ ║ 4. You may revoke consent at any time ║
50
+ ║ ║
51
+ ║ Consent is required before any stealth plugin can be applied. ║
52
+ ║ ║
53
+ ╚══════════════════════════════════════════════════════════════════╝"""
54
+
55
+ # --- Lazy imports for hooks/_common.py ---
56
+
57
+ _atomic_json_write = None
58
+
59
+
60
+ def _ensure_imports():
61
+ """Lazy import atomic_json_write from hooks/_common.py."""
62
+ global _atomic_json_write
63
+ if _atomic_json_write is not None:
64
+ return
65
+ repo_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
66
+ hooks_dir = os.path.join(repo_root, "hooks")
67
+ if hooks_dir not in sys.path:
68
+ sys.path.insert(0, hooks_dir)
69
+ try:
70
+ from _common import atomic_json_write as _ajw
71
+ _atomic_json_write = _ajw
72
+ except ImportError:
73
+ pass
74
+
75
+
76
+ def _write_consent_file(path: str, data: Dict[str, Any]) -> bool:
77
+ """Write consent data using atomic_json_write or fallback.
78
+
79
+ Returns True on success, False on failure.
80
+ """
81
+ _ensure_imports()
82
+ if _atomic_json_write is not None:
83
+ try:
84
+ _atomic_json_write(path, data)
85
+ return True
86
+ except Exception:
87
+ return False
88
+ # Fallback: direct write with makedirs
89
+ try:
90
+ parent = os.path.dirname(path)
91
+ if parent:
92
+ os.makedirs(parent, exist_ok=True)
93
+ with open(path, "w", encoding="utf-8") as f:
94
+ json.dump(data, f, separators=(",", ":"))
95
+ return True
96
+ except Exception:
97
+ return False
98
+
99
+
100
+ def _read_consent_file(path: str) -> Optional[Dict[str, Any]]:
101
+ """Read and parse consent file. Returns None on any failure."""
102
+ try:
103
+ if not os.path.exists(path):
104
+ return None
105
+ with open(path, "r", encoding="utf-8") as f:
106
+ data = json.load(f)
107
+ if isinstance(data, dict):
108
+ return data
109
+ return None
110
+ except (json.JSONDecodeError, OSError, TypeError):
111
+ return None
112
+
113
+
114
+ # =============================================================================
115
+ # ConsentManager — manages browser stealth consent lifecycle
116
+ # =============================================================================
117
+
118
+
119
+ class ConsentManager:
120
+ """Manages user consent for browser stealth mode.
121
+
122
+ All consent state is persisted to .omg/state/browser_consent.json.
123
+ No consent is recorded without explicit calls to record_consent().
124
+
125
+ Attributes:
126
+ project_dir: Root directory containing the .omg/ state folder.
127
+ """
128
+
129
+ def __init__(self, project_dir: Optional[str] = None):
130
+ self.project_dir = project_dir or os.environ.get(
131
+ "CLAUDE_PROJECT_DIR", os.getcwd()
132
+ )
133
+
134
+ @property
135
+ def consent_path(self) -> str:
136
+ """Full path to the consent file."""
137
+ return os.path.join(self.project_dir, CONSENT_REL_PATH)
138
+
139
+ def show_warning(self) -> str:
140
+ """Return the ToS warning text for browser stealth mode.
141
+
142
+ Returns the multi-line warning string. Does NOT print it —
143
+ the caller decides how to display the warning.
144
+
145
+ Returns:
146
+ Multi-line warning string containing Terms of Service notice.
147
+ """
148
+ return _WARNING_TEXT
149
+
150
+ def record_consent(self, acknowledged: bool = True) -> bool:
151
+ """Record the user's consent decision.
152
+
153
+ Saves consent state to .omg/state/browser_consent.json with
154
+ a timestamp and version identifier.
155
+
156
+ Args:
157
+ acknowledged: True if user explicitly consented, False otherwise.
158
+
159
+ Returns:
160
+ True if consent was successfully written, False on failure.
161
+ """
162
+ data = {
163
+ "consented": acknowledged,
164
+ "acknowledged_at": datetime.now(timezone.utc).isoformat(),
165
+ "version": CONSENT_VERSION,
166
+ }
167
+ return _write_consent_file(self.consent_path, data)
168
+
169
+ def is_consented(self) -> bool:
170
+ """Check if user has given explicit consent for stealth plugins.
171
+
172
+ Reads .omg/state/browser_consent.json and checks for
173
+ ``{"consented": true}``.
174
+
175
+ Returns:
176
+ True if consent file exists and consented is True, False otherwise.
177
+ """
178
+ data = _read_consent_file(self.consent_path)
179
+ if data is None:
180
+ return False
181
+ return data.get("consented", False) is True
182
+
183
+ def revoke_consent(self) -> bool:
184
+ """Revoke previously granted consent.
185
+
186
+ Sets consented to False in the consent file while preserving
187
+ the timestamp of revocation.
188
+
189
+ Returns:
190
+ True if revocation was successfully written, False on failure.
191
+ """
192
+ data = {
193
+ "consented": False,
194
+ "acknowledged_at": datetime.now(timezone.utc).isoformat(),
195
+ "version": CONSENT_VERSION,
196
+ }
197
+ return _write_consent_file(self.consent_path, data)
198
+
199
+ def get_consent_status(self) -> Dict[str, Any]:
200
+ """Return the full consent record.
201
+
202
+ Returns:
203
+ Full consent dict if file exists and is valid,
204
+ otherwise {"consented": False}.
205
+ """
206
+ data = _read_consent_file(self.consent_path)
207
+ if data is None:
208
+ return {"consented": False}
209
+ return data
210
+
211
+
212
+ # =============================================================================
213
+ # Module-level convenience function
214
+ # =============================================================================
215
+
216
+
217
+ def is_consented(project_dir: Optional[str] = None) -> bool:
218
+ """Module-level convenience: check if consent has been granted.
219
+
220
+ Args:
221
+ project_dir: Root directory (auto-detected if None).
222
+
223
+ Returns:
224
+ True if consented, False otherwise.
225
+ """
226
+ return ConsentManager(project_dir=project_dir).is_consented()
227
+
228
+
229
+ # =============================================================================
230
+ # CLI Interface
231
+ # =============================================================================
232
+
233
+
234
+ def _cli_main():
235
+ """CLI entry point for browser_consent.py."""
236
+ import argparse
237
+
238
+ parser = argparse.ArgumentParser(
239
+ description="OMG Browser Consent — manage consent for browser stealth mode",
240
+ formatter_class=argparse.RawDescriptionHelpFormatter,
241
+ )
242
+ parser.add_argument(
243
+ "--status", action="store_true",
244
+ help="Show current consent status",
245
+ )
246
+ parser.add_argument(
247
+ "--show-warning", action="store_true",
248
+ help="Display the ToS warning text",
249
+ )
250
+ parser.add_argument(
251
+ "--grant", action="store_true",
252
+ help="Grant consent for stealth mode",
253
+ )
254
+ parser.add_argument(
255
+ "--revoke", action="store_true",
256
+ help="Revoke consent for stealth mode",
257
+ )
258
+ parser.add_argument(
259
+ "--project-dir", default=None,
260
+ help="Project directory (default: auto-detect)",
261
+ )
262
+
263
+ args = parser.parse_args()
264
+ manager = ConsentManager(project_dir=args.project_dir)
265
+
266
+ if args.show_warning:
267
+ print(manager.show_warning())
268
+ return
269
+
270
+ if args.grant:
271
+ success = manager.record_consent(acknowledged=True)
272
+ print(json.dumps({"granted": success}, indent=2))
273
+ return
274
+
275
+ if args.revoke:
276
+ success = manager.revoke_consent()
277
+ print(json.dumps({"revoked": success}, indent=2))
278
+ return
279
+
280
+ if args.status:
281
+ status = manager.get_consent_status()
282
+ print(json.dumps(status, indent=2))
283
+ return
284
+
285
+ parser.print_help()
286
+
287
+
288
+ if __name__ == "__main__":
289
+ _cli_main()