@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
package/scripts/omg.py ADDED
@@ -0,0 +1,492 @@
1
+ #!/usr/bin/env python3
2
+ """OMG 2.0.2 CLI entrypoint.
3
+
4
+ Implements practical command-line flows for:
5
+ - omg ship
6
+ - omg fix --issue
7
+ - omg secure
8
+ - omg maintainer
9
+ - omg trust review
10
+ - omg runtime dispatch
11
+ - omg lab train / omg lab eval
12
+ """
13
+ from __future__ import annotations
14
+
15
+ import argparse
16
+ from datetime import datetime, timezone
17
+ import json
18
+ import os
19
+ from pathlib import Path
20
+ import sys
21
+ from typing import Any
22
+
23
+ # --- Path resolution (never relies on CWD) ---
24
+ SCRIPTS_DIR = os.path.dirname(os.path.abspath(__file__))
25
+ ROOT_DIR = Path(SCRIPTS_DIR).resolve().parent
26
+ if str(ROOT_DIR) not in sys.path:
27
+ sys.path.insert(0, str(ROOT_DIR))
28
+
29
+ from hooks.policy_engine import evaluate_bash_command
30
+ from hooks.shadow_manager import create_evidence_pack
31
+ from hooks.trust_review import review_config_change, write_trust_manifest
32
+ from lab.pipeline import publish_artifact, run_pipeline
33
+ from runtime.dispatcher import dispatch_runtime
34
+ from runtime.compat import (
35
+ DEFAULT_CONTRACT_SNAPSHOT_PATH,
36
+ DEFAULT_GAP_REPORT_PATH,
37
+ build_contract_snapshot_payload,
38
+ build_compat_gap_report,
39
+ dispatch_compat_skill,
40
+ get_compat_skill_contract,
41
+ list_compat_skill_contracts,
42
+ list_compat_skills,
43
+ )
44
+ from runtime.adoption import CANONICAL_VERSION
45
+ from runtime.ecosystem import ecosystem_status, list_ecosystem_repos, sync_ecosystem_repos
46
+ from runtime.team_router import TeamDispatchRequest, dispatch_team, execute_ccg_mode, execute_crazy_mode
47
+
48
+
49
+ def _now_run_id() -> str:
50
+ return datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%S%fZ")
51
+
52
+
53
+ def _parse_simple_idea_yaml(path: str) -> dict[str, Any]:
54
+ """Minimal parser for `.omg/idea.yml` template shape."""
55
+ idea: dict[str, Any] = {
56
+ "goal": "",
57
+ "constraints": [],
58
+ "acceptance": [],
59
+ "risk": {"security": [], "performance": [], "compatibility": []},
60
+ "evidence_required": {"tests": [], "security_scans": [], "reproducibility": [], "artifacts": []},
61
+ }
62
+ section: str | None = None
63
+ subsection: str | None = None
64
+
65
+ with open(path, "r", encoding="utf-8") as f:
66
+ for raw in f:
67
+ line = raw.rstrip("\n")
68
+ stripped = line.strip()
69
+ if not stripped or stripped.startswith("#"):
70
+ continue
71
+
72
+ if stripped.startswith("goal:"):
73
+ idea["goal"] = stripped.split(":", 1)[1].strip().strip("\"'")
74
+ section = None
75
+ subsection = None
76
+ continue
77
+
78
+ if stripped in {"constraints:", "acceptance:", "risk:", "evidence_required:"}:
79
+ section = stripped[:-1]
80
+ subsection = None
81
+ continue
82
+
83
+ if section in {"risk", "evidence_required"} and stripped.endswith(":") and not stripped.startswith("- "):
84
+ subsection = stripped[:-1]
85
+ continue
86
+
87
+ if stripped.startswith("- "):
88
+ value = stripped[2:].strip().strip("\"'")
89
+ if section in {"constraints", "acceptance"}:
90
+ idea[section].append(value)
91
+ elif section in {"risk", "evidence_required"} and subsection:
92
+ idea[section].setdefault(subsection, []).append(value)
93
+
94
+ return idea
95
+
96
+
97
+ def _load_json(path: str) -> dict[str, Any]:
98
+ with open(path, "r", encoding="utf-8") as f:
99
+ data = json.load(f)
100
+ if not isinstance(data, dict):
101
+ raise ValueError(f"Expected object JSON in {path}")
102
+ return data
103
+
104
+
105
+ def _ensure_project_dir() -> str:
106
+ return os.environ.get("CLAUDE_PROJECT_DIR", os.getcwd())
107
+
108
+
109
+ def cmd_ship(args: argparse.Namespace) -> int:
110
+ project_dir = _ensure_project_dir()
111
+ idea_path = args.idea
112
+ idea = _parse_simple_idea_yaml(idea_path) if idea_path.endswith((".yml", ".yaml")) else _load_json(idea_path)
113
+
114
+ runtime = args.runtime
115
+ dispatched = dispatch_runtime(runtime, idea)
116
+ if dispatched.get("status") != "ok":
117
+ print(json.dumps(dispatched, indent=2))
118
+ return 2
119
+
120
+ run_id = args.run_id or _now_run_id()
121
+ verification = dispatched.get("verification", {})
122
+ checks = verification.get("checks", []) if isinstance(verification, dict) else []
123
+ evidence_path = create_evidence_pack(
124
+ project_dir,
125
+ run_id,
126
+ tests=checks if isinstance(checks, list) else [],
127
+ security_scans=[],
128
+ diff_summary={"runtime": runtime, "goal": idea.get("goal", "")},
129
+ reproducibility={"command": f"omg ship --runtime {runtime} --idea {idea_path}"},
130
+ unresolved_risks=[],
131
+ )
132
+
133
+ out = {
134
+ "status": "ok",
135
+ "command": "ship",
136
+ "runtime": runtime,
137
+ "run_id": run_id,
138
+ "goal": idea.get("goal", ""),
139
+ "evidence_path": os.path.relpath(evidence_path, project_dir),
140
+ }
141
+ print(json.dumps(out, indent=2))
142
+ return 0
143
+
144
+
145
+ def cmd_fix(args: argparse.Namespace) -> int:
146
+ goal = f"Fix issue {args.issue}"
147
+ dispatched = dispatch_runtime(args.runtime, {"goal": goal, "acceptance": [f"issue-{args.issue}-resolved"]})
148
+ print(json.dumps(dispatched, indent=2))
149
+ return 0 if dispatched.get("status") == "ok" else 2
150
+
151
+
152
+ def cmd_secure(args: argparse.Namespace) -> int:
153
+ decision = evaluate_bash_command(args.command)
154
+ print(json.dumps(decision.to_dict(), indent=2))
155
+ return 0 if decision.action != "deny" else 3
156
+
157
+
158
+ def cmd_maintainer(args: argparse.Namespace) -> int:
159
+ project_dir = _ensure_project_dir()
160
+ out_dir = Path(project_dir) / ".omg" / "evidence"
161
+ out_dir.mkdir(parents=True, exist_ok=True)
162
+ out_file = out_dir / "oss-impact.json"
163
+ payload = {
164
+ "generated_at": datetime.now(timezone.utc).isoformat(),
165
+ "mode": args.mode,
166
+ "activity": {"commits": "unverified", "reviews": "unverified", "releases": "unverified"},
167
+ "dependents": {"direct": "unverified", "transitive": "unverified"},
168
+ "adoption_signals": {"downloads": "unverified", "stars": "unverified"},
169
+ "summary_500_words": "",
170
+ "integrity": {"metric_manipulation": "forbidden"},
171
+ }
172
+ out_file.write_text(json.dumps(payload, indent=2), encoding="utf-8")
173
+ print(json.dumps({"status": "ok", "path": str(out_file)}, indent=2))
174
+ return 0
175
+
176
+
177
+ def cmd_trust_review(args: argparse.Namespace) -> int:
178
+ old_cfg = _load_json(args.old)
179
+ new_cfg = _load_json(args.new)
180
+ review = review_config_change(args.file, old_cfg, new_cfg)
181
+ manifest = write_trust_manifest(_ensure_project_dir(), review)
182
+ print(json.dumps({"review": review, "manifest": manifest}, indent=2))
183
+ return 0
184
+
185
+
186
+ def cmd_runtime_dispatch(args: argparse.Namespace) -> int:
187
+ if args.idea_json:
188
+ idea = json.loads(args.idea_json)
189
+ elif args.idea:
190
+ idea = _load_json(args.idea)
191
+ else:
192
+ idea = {"goal": "unspecified"}
193
+ result = dispatch_runtime(args.runtime, idea)
194
+ print(json.dumps(result, indent=2))
195
+ return 0 if result.get("status") == "ok" else 2
196
+
197
+
198
+ def cmd_lab_train(args: argparse.Namespace) -> int:
199
+ job = json.loads(args.job_json) if args.job_json else _load_json(args.job)
200
+ result = run_pipeline(job)
201
+ print(json.dumps(result, indent=2))
202
+ return 0 if result.get("status") in {"ready", "failed_evaluation"} else 2
203
+
204
+
205
+ def cmd_lab_eval(args: argparse.Namespace) -> int:
206
+ result = json.loads(args.result_json) if args.result_json else _load_json(args.result)
207
+ out = publish_artifact(result)
208
+ print(json.dumps(out, indent=2))
209
+ return 0 if out.get("status") == "published" else 2
210
+
211
+
212
+ def cmd_teams(args: argparse.Namespace) -> int:
213
+ files = [f.strip() for f in args.files.split(",") if f.strip()] if args.files else []
214
+ req = TeamDispatchRequest(
215
+ target=args.target,
216
+ problem=args.problem,
217
+ context=args.context,
218
+ files=files,
219
+ expected_outcome=args.expected_outcome,
220
+ )
221
+ result = dispatch_team(req).to_dict()
222
+ print(json.dumps(result, indent=2))
223
+ return 0
224
+
225
+
226
+ def cmd_ccg(args: argparse.Namespace) -> int:
227
+ files = [f.strip() for f in args.files.split(",") if f.strip()] if args.files else []
228
+ result = execute_ccg_mode(
229
+ problem=args.problem,
230
+ project_dir=_ensure_project_dir(),
231
+ context=args.context,
232
+ files=files,
233
+ )
234
+ print(json.dumps(result, indent=2))
235
+ return 0
236
+
237
+
238
+ def cmd_crazy(args: argparse.Namespace) -> int:
239
+ files = [f.strip() for f in args.files.split(",") if f.strip()] if args.files else []
240
+ result = execute_crazy_mode(
241
+ problem=args.problem,
242
+ project_dir=_ensure_project_dir(),
243
+ context=args.context,
244
+ files=files,
245
+ )
246
+ print(json.dumps(result, indent=2))
247
+ return 0
248
+
249
+
250
+ def cmd_compat_list(args: argparse.Namespace) -> int:
251
+ skills = list_compat_skills()
252
+ print(json.dumps({"status": "ok", "count": len(skills), "skills": skills}, indent=2))
253
+ return 0
254
+
255
+
256
+ def cmd_compat_contract(args: argparse.Namespace) -> int:
257
+ if args.all:
258
+ contracts = list_compat_skill_contracts()
259
+ print(json.dumps({"status": "ok", "count": len(contracts), "contracts": contracts}, indent=2))
260
+ return 0
261
+ if not args.skill:
262
+ print(json.dumps({"status": "error", "message": "Provide --skill or --all"}, indent=2))
263
+ return 2
264
+ contract = get_compat_skill_contract(args.skill)
265
+ if not contract:
266
+ print(json.dumps({"status": "error", "message": f"Unknown skill: {args.skill}"}, indent=2))
267
+ return 2
268
+ print(json.dumps({"status": "ok", "contract": contract}, indent=2))
269
+ return 0
270
+
271
+
272
+ def cmd_compat_gap_report(args: argparse.Namespace) -> int:
273
+ report = build_compat_gap_report(_ensure_project_dir())
274
+ if args.output:
275
+ with open(args.output, "w", encoding="utf-8") as f:
276
+ json.dump(report, f, indent=2)
277
+ print(json.dumps({"status": "ok", "report": report}, indent=2))
278
+ return 0
279
+
280
+
281
+ def cmd_compat_snapshot(args: argparse.Namespace) -> int:
282
+ payload = build_contract_snapshot_payload(include_generated_at=True)
283
+ out_path = args.output or DEFAULT_CONTRACT_SNAPSHOT_PATH
284
+ with open(out_path, "w", encoding="utf-8") as f:
285
+ json.dump(payload, f, indent=2)
286
+ print(json.dumps({"status": "ok", "output": out_path, "count": payload["count"]}, indent=2))
287
+ return 0
288
+
289
+
290
+ def cmd_compat_gate(args: argparse.Namespace) -> int:
291
+ report = build_compat_gap_report(_ensure_project_dir())
292
+ if args.output:
293
+ with open(args.output, "w", encoding="utf-8") as f:
294
+ json.dump(report, f, indent=2)
295
+ bridge_count = int(report.get("maturity_counts", {}).get("bridge", 0))
296
+ if bridge_count > args.max_bridge:
297
+ print(
298
+ json.dumps(
299
+ {
300
+ "status": "error",
301
+ "message": f"OMG compat gate failed: bridge={bridge_count} > max_bridge={args.max_bridge}",
302
+ "report": report,
303
+ },
304
+ indent=2,
305
+ )
306
+ )
307
+ return 3
308
+ print(
309
+ json.dumps(
310
+ {
311
+ "status": "ok",
312
+ "message": f"OMG compat gate passed: bridge={bridge_count} <= max_bridge={args.max_bridge}",
313
+ "report": report,
314
+ },
315
+ indent=2,
316
+ )
317
+ )
318
+ return 0
319
+
320
+
321
+ def cmd_compat_run(args: argparse.Namespace) -> int:
322
+ files = [f.strip() for f in args.files.split(",") if f.strip()] if args.files else []
323
+ result = dispatch_compat_skill(
324
+ skill=args.skill,
325
+ problem=args.problem,
326
+ context=args.context,
327
+ files=files,
328
+ expected_outcome=args.expected_outcome,
329
+ project_dir=_ensure_project_dir(),
330
+ )
331
+ print(json.dumps(result, indent=2))
332
+ return 0 if result.get("status") == "ok" else 2
333
+
334
+
335
+ def cmd_ecosystem_list(args: argparse.Namespace) -> int:
336
+ repos = list_ecosystem_repos()
337
+ print(json.dumps({"status": "ok", "count": len(repos), "repos": repos}, indent=2))
338
+ return 0
339
+
340
+
341
+ def cmd_ecosystem_status(args: argparse.Namespace) -> int:
342
+ result = ecosystem_status(project_dir=_ensure_project_dir())
343
+ print(json.dumps(result, indent=2))
344
+ return 0
345
+
346
+
347
+ def cmd_ecosystem_sync(args: argparse.Namespace) -> int:
348
+ names = [name.strip() for name in args.names.split(",") if name.strip()] if args.names else []
349
+ result = sync_ecosystem_repos(
350
+ project_dir=_ensure_project_dir(),
351
+ names=names,
352
+ update=bool(args.update),
353
+ depth=int(args.depth),
354
+ )
355
+ print(json.dumps(result, indent=2))
356
+ errors = [entry for entry in result.get("entries", []) if entry.get("status") == "error"]
357
+ return 0 if not errors else 2
358
+
359
+
360
+ def _add_compat_subcommands(parent: argparse.ArgumentParser, *, dest: str) -> None:
361
+ compat_sub = parent.add_subparsers(dest=dest, required=True)
362
+ compat_list = compat_sub.add_parser("list", help="List supported legacy skill names")
363
+ compat_list.set_defaults(func=cmd_compat_list)
364
+ compat_contract = compat_sub.add_parser("contract", help="Show skill contract schema")
365
+ compat_contract.add_argument("--skill", default="")
366
+ compat_contract.add_argument("--all", action="store_true")
367
+ compat_contract.set_defaults(func=cmd_compat_contract)
368
+ compat_gap = compat_sub.add_parser("gap-report", help="Write compatibility maturity report")
369
+ compat_gap.add_argument("--output", default=DEFAULT_GAP_REPORT_PATH)
370
+ compat_gap.set_defaults(func=cmd_compat_gap_report)
371
+ compat_snapshot = compat_sub.add_parser("snapshot", help="Write current skill contracts snapshot")
372
+ compat_snapshot.add_argument("--output", default=DEFAULT_CONTRACT_SNAPSHOT_PATH)
373
+ compat_snapshot.set_defaults(func=cmd_compat_snapshot)
374
+ compat_gate = compat_sub.add_parser("gate", help="Fail if bridge skill count exceeds threshold")
375
+ compat_gate.add_argument("--max-bridge", type=int, default=0)
376
+ compat_gate.add_argument("--output", default=DEFAULT_GAP_REPORT_PATH)
377
+ compat_gate.set_defaults(func=cmd_compat_gate)
378
+ compat_run = compat_sub.add_parser("run", help="Run a legacy skill through OMG router")
379
+ compat_run.add_argument("--skill", required=True)
380
+ compat_run.add_argument("--problem", default="")
381
+ compat_run.add_argument("--context", default="")
382
+ compat_run.add_argument("--files", default="")
383
+ compat_run.add_argument("--expected-outcome", default="")
384
+ compat_run.set_defaults(func=cmd_compat_run)
385
+
386
+
387
+ def _add_ecosystem_subcommands(parent: argparse.ArgumentParser, *, dest: str) -> None:
388
+ ecosystem_sub = parent.add_subparsers(dest=dest, required=True)
389
+ ecosystem_list = ecosystem_sub.add_parser("list", help="List OMG ecosystem integration targets")
390
+ ecosystem_list.set_defaults(func=cmd_ecosystem_list)
391
+
392
+ ecosystem_status_cmd = ecosystem_sub.add_parser("status", help="Show current ecosystem install status")
393
+ ecosystem_status_cmd.set_defaults(func=cmd_ecosystem_status)
394
+
395
+ ecosystem_sync = ecosystem_sub.add_parser("sync", help="Clone or refresh ecosystem repositories")
396
+ ecosystem_sync.add_argument("--names", default="", help="Comma-separated repo names or aliases")
397
+ ecosystem_sync.add_argument("--update", action="store_true", help="Fetch latest refs for existing clones")
398
+ ecosystem_sync.add_argument("--depth", type=int, default=1, help="Git depth for shallow clone/fetch")
399
+ ecosystem_sync.set_defaults(func=cmd_ecosystem_sync)
400
+
401
+
402
+ def build_parser() -> argparse.ArgumentParser:
403
+ parser = argparse.ArgumentParser(prog="omg", description=f"OMG {CANONICAL_VERSION} CLI")
404
+ sub = parser.add_subparsers(dest="command", required=True)
405
+
406
+ ship = sub.add_parser("ship", help="Idea -> Evidence -> PR flow")
407
+ ship.add_argument("--idea", default=".omg/idea.yml")
408
+ ship.add_argument("--runtime", default="claude", choices=["claude", "gpt", "local"])
409
+ ship.add_argument("--run-id", default="")
410
+ ship.set_defaults(func=cmd_ship)
411
+
412
+ fix = sub.add_parser("fix", help="Issue-driven fix flow")
413
+ fix.add_argument("--issue", required=True)
414
+ fix.add_argument("--runtime", default="claude", choices=["claude", "gpt", "local"])
415
+ fix.set_defaults(func=cmd_fix)
416
+
417
+ secure = sub.add_parser("secure", help="Evaluate command risk")
418
+ secure.add_argument("--command", required=True)
419
+ secure.set_defaults(func=cmd_secure)
420
+
421
+ maintainer = sub.add_parser("maintainer", help="OSS maintainer evidence helper")
422
+ maintainer.add_argument("--mode", default="impact", choices=["triage", "release", "review", "impact"])
423
+ maintainer.set_defaults(func=cmd_maintainer)
424
+
425
+ trust = sub.add_parser("trust", help="Trust review operations")
426
+ trust_sub = trust.add_subparsers(dest="trust_command", required=True)
427
+ trust_review = trust_sub.add_parser("review", help="Review config change")
428
+ trust_review.add_argument("--file", default="settings.json")
429
+ trust_review.add_argument("--old", required=True, help="Path to old config json")
430
+ trust_review.add_argument("--new", required=True, help="Path to new config json")
431
+ trust_review.set_defaults(func=cmd_trust_review)
432
+
433
+ runtime = sub.add_parser("runtime", help="Runtime operations")
434
+ runtime_sub = runtime.add_subparsers(dest="runtime_command", required=True)
435
+ runtime_dispatch = runtime_sub.add_parser("dispatch", help="Dispatch runtime job")
436
+ runtime_dispatch.add_argument("--runtime", required=True, choices=["claude", "gpt", "local"])
437
+ runtime_dispatch.add_argument("--idea", default="", help="Path to idea json")
438
+ runtime_dispatch.add_argument("--idea-json", default="", help="Inline idea json")
439
+ runtime_dispatch.set_defaults(func=cmd_runtime_dispatch)
440
+
441
+ lab = sub.add_parser("lab", help="Lab pipeline operations")
442
+ lab_sub = lab.add_subparsers(dest="lab_command", required=True)
443
+ lab_train = lab_sub.add_parser("train", help="Run lab pipeline job")
444
+ lab_train.add_argument("--job", default="", help="Path to job json")
445
+ lab_train.add_argument("--job-json", default="", help="Inline job json")
446
+ lab_train.set_defaults(func=cmd_lab_train)
447
+ lab_eval = lab_sub.add_parser("eval", help="Publish lab result when eligible")
448
+ lab_eval.add_argument("--result", default="", help="Path to result json")
449
+ lab_eval.add_argument("--result-json", default="", help="Inline result json")
450
+ lab_eval.set_defaults(func=cmd_lab_eval)
451
+
452
+ teams = sub.add_parser("teams", help="Internal OMG team routing")
453
+ teams.add_argument("--target", default="auto", choices=["auto", "codex", "gemini", "ccg"])
454
+ teams.add_argument("--problem", required=True)
455
+ teams.add_argument("--context", default="")
456
+ teams.add_argument("--files", default="")
457
+ teams.add_argument("--expected-outcome", default="")
458
+ teams.set_defaults(func=cmd_teams)
459
+
460
+ ccg = sub.add_parser("ccg", help="OMG CCG (tri-track) routing")
461
+ ccg.add_argument("--problem", required=True)
462
+ ccg.add_argument("--context", default="")
463
+ ccg.add_argument("--files", default="")
464
+ ccg.add_argument("--expected-outcome", default="")
465
+ ccg.set_defaults(func=cmd_ccg)
466
+
467
+ crazy = sub.add_parser("crazy", help="OMG CRAZY mode - parallel multi-agent orchestration")
468
+ crazy.add_argument("--problem", required=True, help="Task description")
469
+ crazy.add_argument("--context", default="", help="Additional context")
470
+ crazy.add_argument("--files", default="", help="Comma-separated focus files")
471
+ crazy.set_defaults(func=cmd_crazy)
472
+
473
+ compat = sub.add_parser("compat", help="OMG legacy compatibility bridge")
474
+ _add_compat_subcommands(compat, dest="compat_command")
475
+
476
+ omc = sub.add_parser("omc", help="Alias of `compat` for legacy scripts")
477
+ _add_compat_subcommands(omc, dest="omc_command")
478
+
479
+ ecosystem = sub.add_parser("ecosystem", help="Upstream ecosystem sync and status")
480
+ _add_ecosystem_subcommands(ecosystem, dest="ecosystem_command")
481
+
482
+ return parser
483
+
484
+
485
+ def main(argv: list[str] | None = None) -> int:
486
+ parser = build_parser()
487
+ args = parser.parse_args(argv)
488
+ return int(args.func(args))
489
+
490
+
491
+ if __name__ == "__main__":
492
+ raise SystemExit(main())