@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.
- package/.claude-plugin/marketplace.json +8 -8
- package/.claude-plugin/plugin.json +5 -4
- package/.claude-plugin/scripts/uninstall.sh +74 -3
- package/.claude-plugin/scripts/update.sh +78 -3
- package/.coveragerc +26 -0
- package/.mcp.json +4 -4
- package/CHANGELOG.md +14 -0
- package/CODE_OF_CONDUCT.md +27 -0
- package/CONTRIBUTING.md +62 -0
- package/OMG-setup.sh +1201 -355
- package/README.md +77 -56
- package/SECURITY.md +25 -0
- package/agents/__init__.py +1 -0
- package/agents/model_roles.py +196 -0
- package/agents/omg-architect-mode.md +3 -5
- package/agents/omg-backend-engineer.md +3 -5
- package/agents/omg-database-engineer.md +3 -5
- package/agents/omg-frontend-designer.md +4 -5
- package/agents/omg-implement-mode.md +4 -5
- package/agents/omg-infra-engineer.md +3 -5
- package/agents/omg-research-mode.md +4 -6
- package/agents/omg-security-auditor.md +3 -5
- package/agents/omg-testing-engineer.md +3 -5
- package/build/lib/yaml.py +321 -0
- package/commands/OMG:ai-commit.md +101 -14
- package/commands/OMG:arch.md +302 -19
- package/commands/OMG:ccg.md +12 -7
- package/commands/OMG:compat.md +25 -17
- package/commands/OMG:cost.md +173 -13
- package/commands/OMG:crazy.md +1 -1
- package/commands/OMG:create-agent.md +170 -20
- package/commands/OMG:deps.md +235 -17
- package/commands/OMG:domain-init.md +1 -1
- package/commands/OMG:escalate.md +41 -12
- package/commands/OMG:health-check.md +37 -13
- package/commands/OMG:init.md +122 -14
- package/commands/OMG:project-init.md +1 -1
- package/commands/OMG:session-branch.md +76 -9
- package/commands/OMG:session-fork.md +42 -5
- package/commands/OMG:session-merge.md +124 -8
- package/commands/OMG:setup.md +69 -12
- package/commands/OMG:stats.md +215 -14
- package/commands/OMG:teams.md +19 -10
- package/config/lsp_languages.yaml +8 -0
- package/hooks/__init__.py +0 -0
- package/hooks/_agent_registry.py +423 -0
- package/hooks/_analytics.py +291 -0
- package/hooks/_budget.py +31 -0
- package/hooks/_common.py +569 -0
- package/hooks/_compression_optimizer.py +119 -0
- package/hooks/_cost_ledger.py +176 -0
- package/hooks/_learnings.py +126 -0
- package/hooks/_memory.py +103 -0
- package/hooks/_protected_context.py +150 -0
- package/hooks/_token_counter.py +221 -0
- package/hooks/branch_manager.py +236 -0
- package/hooks/budget_governor.py +232 -0
- package/hooks/circuit-breaker.py +270 -0
- package/hooks/compression_feedback.py +254 -0
- package/hooks/config-guard.py +216 -0
- package/hooks/context_pressure.py +53 -0
- package/hooks/credential_store.py +1020 -0
- package/hooks/fetch-rate-limits.py +212 -0
- package/hooks/firewall.py +48 -0
- package/hooks/hashline-formatter-bridge.py +224 -0
- package/hooks/hashline-injector.py +273 -0
- package/hooks/hashline-validator.py +216 -0
- package/hooks/idle-detector.py +95 -0
- package/hooks/intentgate-keyword-detector.py +188 -0
- package/hooks/magic-keyword-router.py +195 -0
- package/hooks/policy_engine.py +505 -0
- package/hooks/post-tool-failure.py +19 -0
- package/hooks/post-write.py +219 -0
- package/hooks/post_write.py +46 -0
- package/hooks/pre-compact.py +398 -0
- package/hooks/pre-tool-inject.py +98 -0
- package/hooks/prompt-enhancer.py +672 -0
- package/hooks/quality-runner.py +191 -0
- package/hooks/query.py +512 -0
- package/hooks/secret-guard.py +61 -0
- package/hooks/secret_audit.py +144 -0
- package/hooks/session-end-capture.py +137 -0
- package/hooks/session-start.py +277 -0
- package/hooks/setup_wizard.py +582 -0
- package/hooks/shadow_manager.py +297 -0
- package/hooks/state_migration.py +225 -0
- package/hooks/stop-gate.py +7 -0
- package/hooks/stop_dispatcher.py +945 -0
- package/hooks/test-validator.py +361 -0
- package/hooks/test_generator_hook.py +123 -0
- package/hooks/todo-state-tracker.py +114 -0
- package/hooks/tool-ledger.py +149 -0
- package/hooks/trust_review.py +585 -0
- package/hud/omg-hud.mjs +31 -1
- package/lab/__init__.py +1 -0
- package/lab/pipeline.py +75 -0
- package/lab/policies.py +52 -0
- package/package.json +7 -18
- package/plugins/README.md +33 -61
- package/plugins/advanced/commands/OMG:deep-plan.md +3 -3
- package/plugins/advanced/commands/OMG:learn.md +1 -1
- package/plugins/advanced/commands/OMG:security-review.md +3 -3
- package/plugins/advanced/commands/OMG:ship.md +1 -1
- package/plugins/advanced/plugin.json +1 -1
- package/plugins/core/plugin.json +8 -3
- package/plugins/dephealth/__init__.py +0 -0
- package/plugins/dephealth/cve_scanner.py +188 -0
- package/plugins/dephealth/license_checker.py +135 -0
- package/plugins/dephealth/manifest_detector.py +423 -0
- package/plugins/dephealth/vuln_analyzer.py +169 -0
- package/plugins/testgen/__init__.py +0 -0
- package/plugins/testgen/codamosa_engine.py +402 -0
- package/plugins/testgen/edge_case_synthesizer.py +184 -0
- package/plugins/testgen/framework_detector.py +271 -0
- package/plugins/testgen/skeleton_generator.py +219 -0
- package/plugins/viz/__init__.py +0 -0
- package/plugins/viz/ast_parser.py +139 -0
- package/plugins/viz/diagram_generator.py +192 -0
- package/plugins/viz/graph_builder.py +444 -0
- package/plugins/viz/native_parsers.py +259 -0
- package/plugins/viz/regex_parser.py +112 -0
- package/pyproject.toml +81 -0
- package/rules/contextual/write-verify.md +2 -2
- package/rules/core/00-truth.md +1 -1
- package/rules/core/01-surgical.md +1 -1
- package/rules/core/02-circuit-breaker.md +2 -2
- package/rules/core/03-ensemble.md +3 -3
- package/rules/core/04-testing.md +3 -3
- package/runtime/__init__.py +32 -0
- package/runtime/adapters/__init__.py +13 -0
- package/runtime/adapters/claude.py +60 -0
- package/runtime/adapters/gpt.py +53 -0
- package/runtime/adapters/local.py +53 -0
- package/runtime/adoption.py +212 -0
- package/runtime/business_workflow.py +220 -0
- package/runtime/cli_provider.py +85 -0
- package/runtime/compat.py +1299 -0
- package/runtime/custom_agent_loader.py +366 -0
- package/runtime/dispatcher.py +47 -0
- package/runtime/ecosystem.py +371 -0
- package/runtime/legacy_compat.py +7 -0
- package/runtime/mcp_config_writers.py +115 -0
- package/runtime/mcp_lifecycle.py +153 -0
- package/runtime/mcp_memory_server.py +135 -0
- package/runtime/memory_parsers/__init__.py +0 -0
- package/runtime/memory_parsers/chatgpt_parser.py +257 -0
- package/runtime/memory_parsers/claude_import.py +107 -0
- package/runtime/memory_parsers/export.py +97 -0
- package/runtime/memory_parsers/gemini_import.py +91 -0
- package/runtime/memory_parsers/kimi_import.py +91 -0
- package/runtime/memory_store.py +215 -0
- package/runtime/omc_compat.py +7 -0
- package/runtime/providers/__init__.py +0 -0
- package/runtime/providers/codex_provider.py +112 -0
- package/runtime/providers/gemini_provider.py +128 -0
- package/runtime/providers/kimi_provider.py +151 -0
- package/runtime/providers/opencode_provider.py +144 -0
- package/runtime/subagent_dispatcher.py +362 -0
- package/runtime/team_router.py +1167 -0
- package/runtime/tmux_session_manager.py +169 -0
- package/scripts/check-omg-compat-contract-snapshot.py +137 -0
- package/scripts/check-omg-contract-snapshot.py +12 -0
- package/scripts/check-omg-public-ready.py +193 -0
- package/scripts/check-omg-standalone-clean.py +103 -0
- package/scripts/legacy_to_omg_migrate.py +29 -0
- package/scripts/migrate-legacy.py +464 -0
- package/scripts/omc_to_omg_migrate.py +12 -0
- package/scripts/omg.py +492 -0
- package/scripts/settings-merge.py +283 -0
- package/scripts/verify-standalone.sh +8 -4
- package/settings.json +126 -29
- package/templates/profile.yaml +1 -1
- package/tools/__init__.py +2 -0
- package/tools/browser_consent.py +289 -0
- package/tools/browser_stealth.py +481 -0
- package/tools/browser_tool.py +448 -0
- package/tools/changelog_generator.py +347 -0
- package/tools/commit_splitter.py +746 -0
- package/tools/config_discovery.py +151 -0
- package/tools/config_merger.py +449 -0
- package/tools/dashboard_generator.py +300 -0
- package/tools/git_inspector.py +298 -0
- package/tools/lsp_client.py +275 -0
- package/tools/lsp_discovery.py +231 -0
- package/tools/lsp_operations.py +392 -0
- package/tools/pr_generator.py +404 -0
- package/tools/python_repl.py +656 -0
- package/tools/python_sandbox.py +609 -0
- package/tools/search_providers/__init__.py +77 -0
- package/tools/search_providers/brave.py +115 -0
- package/tools/search_providers/exa.py +116 -0
- package/tools/search_providers/jina.py +104 -0
- package/tools/search_providers/perplexity.py +139 -0
- package/tools/search_providers/synthetic.py +74 -0
- package/tools/session_snapshot.py +736 -0
- package/tools/ssh_manager.py +912 -0
- package/tools/theme_engine.py +294 -0
- package/tools/theme_selector.py +137 -0
- package/tools/web_search.py +622 -0
- package/yaml.py +321 -0
- package/.claude-plugin/scripts/install.sh +0 -9
- package/bun.lock +0 -23
- package/bunfig.toml +0 -3
- package/hooks/_budget.ts +0 -1
- package/hooks/_common.ts +0 -63
- package/hooks/circuit-breaker.ts +0 -101
- package/hooks/config-guard.ts +0 -4
- package/hooks/firewall.ts +0 -20
- package/hooks/policy_engine.ts +0 -156
- package/hooks/post-tool-failure.ts +0 -22
- package/hooks/post-write.ts +0 -4
- package/hooks/pre-tool-inject.ts +0 -4
- package/hooks/prompt-enhancer.ts +0 -46
- package/hooks/quality-runner.ts +0 -24
- package/hooks/secret-guard.ts +0 -4
- package/hooks/session-end-capture.ts +0 -19
- package/hooks/session-start.ts +0 -19
- package/hooks/shadow_manager.ts +0 -81
- package/hooks/stop-gate.ts +0 -22
- package/hooks/stop_dispatcher.ts +0 -147
- package/hooks/test-generator-hook.ts +0 -4
- package/hooks/tool-ledger.ts +0 -27
- package/hooks/trust_review.ts +0 -175
- package/lab/pipeline.ts +0 -75
- package/lab/policies.ts +0 -68
- package/runtime/common.ts +0 -111
- package/runtime/compat.ts +0 -174
- package/runtime/dispatcher.ts +0 -25
- package/runtime/ecosystem.ts +0 -186
- package/runtime/provider_bootstrap.ts +0 -99
- package/runtime/provider_smoke.ts +0 -34
- package/runtime/release_readiness.ts +0 -186
- package/runtime/team_router.ts +0 -144
- package/scripts/check-omg-compat-contract-snapshot.ts +0 -20
- package/scripts/check-omg-standalone-clean.ts +0 -12
- package/scripts/check-runtime-clean.ts +0 -94
- package/scripts/omg.ts +0 -352
- package/scripts/settings-merge.ts +0 -93
- package/tools/commit_splitter.ts +0 -23
- package/tools/git_inspector.ts +0 -18
- package/tools/session_snapshot.ts +0 -47
- package/trac3er-oh-my-god-2.0.0.tgz +0 -0
- package/tsconfig.json +0 -15
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
"""Native toolchain dependency parsers for Go, TypeScript, and Rust.
|
|
2
|
+
|
|
3
|
+
Shells out to `go list -json`, `tsc --listFiles`, and `cargo metadata`
|
|
4
|
+
for higher-accuracy dependency graphs (~95%) compared to regex parsers.
|
|
5
|
+
|
|
6
|
+
Standalone extension — graph_builder.py can optionally import this module.
|
|
7
|
+
Feature-gated behind CODEBASE_VIZ.
|
|
8
|
+
|
|
9
|
+
All subprocess calls use argv lists (never shell=True) with timeout=30.
|
|
10
|
+
All functions handle exceptions gracefully and never raise to the caller.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
from __future__ import annotations
|
|
14
|
+
|
|
15
|
+
import json
|
|
16
|
+
import shutil
|
|
17
|
+
import subprocess
|
|
18
|
+
from typing import Any
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def is_toolchain_available(toolchain: str) -> bool:
|
|
22
|
+
"""Check if a toolchain binary is installed and on PATH.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
toolchain: Name of the binary (e.g. ``"go"``, ``"tsc"``, ``"cargo"``).
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
True if the binary is found, False otherwise.
|
|
29
|
+
"""
|
|
30
|
+
try:
|
|
31
|
+
return shutil.which(toolchain) is not None
|
|
32
|
+
except Exception:
|
|
33
|
+
return False
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _error_result(language: str, message: str) -> dict[str, Any]:
|
|
37
|
+
"""Build a standardised error result dict."""
|
|
38
|
+
return {
|
|
39
|
+
"error": message,
|
|
40
|
+
"accuracy": "N/A",
|
|
41
|
+
"graph": {},
|
|
42
|
+
"language": language,
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def _run_subprocess(
|
|
47
|
+
argv: list[str],
|
|
48
|
+
cwd: str,
|
|
49
|
+
) -> tuple[str | None, str | None]:
|
|
50
|
+
"""Run a subprocess safely with timeout.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
(stdout, None) on success, (None, error_message) on failure.
|
|
54
|
+
"""
|
|
55
|
+
try:
|
|
56
|
+
proc = subprocess.run(
|
|
57
|
+
argv,
|
|
58
|
+
capture_output=True,
|
|
59
|
+
text=True,
|
|
60
|
+
cwd=cwd,
|
|
61
|
+
timeout=30,
|
|
62
|
+
)
|
|
63
|
+
except subprocess.TimeoutExpired:
|
|
64
|
+
return None, f"timeout: {argv[0]} timed out after 30s"
|
|
65
|
+
except OSError as exc:
|
|
66
|
+
return None, f"os-error: {exc}"
|
|
67
|
+
except Exception as exc:
|
|
68
|
+
return None, f"unexpected-error: {exc}"
|
|
69
|
+
|
|
70
|
+
if proc.returncode != 0:
|
|
71
|
+
stderr_snippet = (proc.stderr or "").strip()[:200]
|
|
72
|
+
return None, f"{argv[0]} exited with code {proc.returncode}: {stderr_snippet}"
|
|
73
|
+
|
|
74
|
+
return proc.stdout, None
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
# ---------------------------------------------------------------------------
|
|
78
|
+
# Go: go list -json ./...
|
|
79
|
+
# ---------------------------------------------------------------------------
|
|
80
|
+
|
|
81
|
+
def _parse_concatenated_json(raw: str) -> list[dict[str, Any]]:
|
|
82
|
+
"""Parse concatenated JSON objects (go list -json output format).
|
|
83
|
+
|
|
84
|
+
``go list -json`` emits multiple JSON objects concatenated together,
|
|
85
|
+
not a JSON array. We use ``json.JSONDecoder.raw_decode`` to stream
|
|
86
|
+
through the buffer.
|
|
87
|
+
"""
|
|
88
|
+
decoder = json.JSONDecoder()
|
|
89
|
+
objects: list[dict[str, Any]] = []
|
|
90
|
+
idx = 0
|
|
91
|
+
length = len(raw)
|
|
92
|
+
|
|
93
|
+
while idx < length:
|
|
94
|
+
# Skip whitespace
|
|
95
|
+
while idx < length and raw[idx] in " \t\n\r":
|
|
96
|
+
idx += 1
|
|
97
|
+
if idx >= length:
|
|
98
|
+
break
|
|
99
|
+
try:
|
|
100
|
+
obj, end_idx = decoder.raw_decode(raw, idx)
|
|
101
|
+
objects.append(obj)
|
|
102
|
+
idx = end_idx
|
|
103
|
+
except json.JSONDecodeError:
|
|
104
|
+
break
|
|
105
|
+
|
|
106
|
+
return objects
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def parse_go_native(project_dir: str) -> dict[str, Any]:
|
|
110
|
+
"""Parse Go dependencies using ``go list -json ./...``.
|
|
111
|
+
|
|
112
|
+
Returns an adjacency list keyed by Go import path.
|
|
113
|
+
Accuracy: native-95% when Go toolchain is available.
|
|
114
|
+
"""
|
|
115
|
+
try:
|
|
116
|
+
if not is_toolchain_available("go"):
|
|
117
|
+
return _error_result("go", "go toolchain not found")
|
|
118
|
+
|
|
119
|
+
stdout, err = _run_subprocess(
|
|
120
|
+
["go", "list", "-json", "./..."],
|
|
121
|
+
cwd=project_dir,
|
|
122
|
+
)
|
|
123
|
+
if err is not None:
|
|
124
|
+
return _error_result("go", err)
|
|
125
|
+
|
|
126
|
+
packages = _parse_concatenated_json(stdout or "")
|
|
127
|
+
graph: dict[str, list[str]] = {}
|
|
128
|
+
|
|
129
|
+
for pkg in packages:
|
|
130
|
+
import_path = pkg.get("ImportPath", "")
|
|
131
|
+
imports = pkg.get("Imports") or []
|
|
132
|
+
if import_path:
|
|
133
|
+
graph[import_path] = list(imports)
|
|
134
|
+
|
|
135
|
+
return {
|
|
136
|
+
"graph": graph,
|
|
137
|
+
"accuracy": "native-95%",
|
|
138
|
+
"language": "go",
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
except Exception as exc:
|
|
142
|
+
return _error_result("go", f"unexpected-error: {exc}")
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
# ---------------------------------------------------------------------------
|
|
146
|
+
# TypeScript: tsc --listFiles --noEmit
|
|
147
|
+
# ---------------------------------------------------------------------------
|
|
148
|
+
|
|
149
|
+
def parse_typescript_native(project_dir: str) -> dict[str, Any]:
|
|
150
|
+
"""Parse TypeScript project files using ``tsc --listFiles --noEmit``.
|
|
151
|
+
|
|
152
|
+
Extracts module names from file paths, excluding ``node_modules``.
|
|
153
|
+
Accuracy: native-95% when tsc is available.
|
|
154
|
+
"""
|
|
155
|
+
try:
|
|
156
|
+
if not is_toolchain_available("tsc"):
|
|
157
|
+
return _error_result("typescript", "tsc toolchain not found")
|
|
158
|
+
|
|
159
|
+
stdout, err = _run_subprocess(
|
|
160
|
+
["tsc", "--listFiles", "--noEmit"],
|
|
161
|
+
cwd=project_dir,
|
|
162
|
+
)
|
|
163
|
+
if err is not None:
|
|
164
|
+
return _error_result("typescript", err)
|
|
165
|
+
|
|
166
|
+
graph: dict[str, list[str]] = {}
|
|
167
|
+
lines = (stdout or "").strip().splitlines()
|
|
168
|
+
|
|
169
|
+
for line in lines:
|
|
170
|
+
file_path = line.strip()
|
|
171
|
+
if not file_path:
|
|
172
|
+
continue
|
|
173
|
+
# Skip node_modules and .d.ts declaration files from stdlib
|
|
174
|
+
if "node_modules" in file_path:
|
|
175
|
+
continue
|
|
176
|
+
|
|
177
|
+
# Derive a module name from the file path relative to project_dir
|
|
178
|
+
module_name = _ts_module_name(file_path, project_dir)
|
|
179
|
+
if module_name:
|
|
180
|
+
graph[module_name] = []
|
|
181
|
+
|
|
182
|
+
return {
|
|
183
|
+
"graph": graph,
|
|
184
|
+
"accuracy": "native-95%",
|
|
185
|
+
"language": "typescript",
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
except Exception as exc:
|
|
189
|
+
return _error_result("typescript", f"unexpected-error: {exc}")
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def _ts_module_name(file_path: str, project_dir: str) -> str:
|
|
193
|
+
"""Derive a TypeScript module name from a file path."""
|
|
194
|
+
try:
|
|
195
|
+
# Normalise paths
|
|
196
|
+
fp = file_path.replace("\\", "/")
|
|
197
|
+
pd = project_dir.rstrip("/").replace("\\", "/") + "/"
|
|
198
|
+
|
|
199
|
+
if fp.startswith(pd):
|
|
200
|
+
rel = fp[len(pd):]
|
|
201
|
+
else:
|
|
202
|
+
rel = fp
|
|
203
|
+
|
|
204
|
+
# Strip extensions
|
|
205
|
+
for ext in (".tsx", ".ts", ".jsx", ".js", ".mjs", ".cjs"):
|
|
206
|
+
if rel.endswith(ext):
|
|
207
|
+
rel = rel[: -len(ext)]
|
|
208
|
+
break
|
|
209
|
+
|
|
210
|
+
# Convert path separators to dots
|
|
211
|
+
return rel.replace("/", ".")
|
|
212
|
+
except Exception:
|
|
213
|
+
return ""
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
# ---------------------------------------------------------------------------
|
|
217
|
+
# Rust: cargo metadata --format-version=1 --no-deps
|
|
218
|
+
# ---------------------------------------------------------------------------
|
|
219
|
+
|
|
220
|
+
def parse_rust_native(project_dir: str) -> dict[str, Any]:
|
|
221
|
+
"""Parse Rust dependencies using ``cargo metadata``.
|
|
222
|
+
|
|
223
|
+
Returns an adjacency list keyed by crate name.
|
|
224
|
+
Accuracy: native-95% when Cargo toolchain is available.
|
|
225
|
+
"""
|
|
226
|
+
try:
|
|
227
|
+
if not is_toolchain_available("cargo"):
|
|
228
|
+
return _error_result("rust", "cargo toolchain not found")
|
|
229
|
+
|
|
230
|
+
stdout, err = _run_subprocess(
|
|
231
|
+
["cargo", "metadata", "--format-version=1", "--no-deps"],
|
|
232
|
+
cwd=project_dir,
|
|
233
|
+
)
|
|
234
|
+
if err is not None:
|
|
235
|
+
return _error_result("rust", err)
|
|
236
|
+
|
|
237
|
+
try:
|
|
238
|
+
metadata = json.loads(stdout or "{}")
|
|
239
|
+
except json.JSONDecodeError as exc:
|
|
240
|
+
return _error_result("rust", f"json-parse-error: {exc}")
|
|
241
|
+
|
|
242
|
+
graph: dict[str, list[str]] = {}
|
|
243
|
+
packages = metadata.get("packages") or []
|
|
244
|
+
|
|
245
|
+
for pkg in packages:
|
|
246
|
+
name = pkg.get("name", "")
|
|
247
|
+
deps = pkg.get("dependencies") or []
|
|
248
|
+
dep_names = [d.get("name", "") for d in deps if d.get("name")]
|
|
249
|
+
if name:
|
|
250
|
+
graph[name] = dep_names
|
|
251
|
+
|
|
252
|
+
return {
|
|
253
|
+
"graph": graph,
|
|
254
|
+
"accuracy": "native-95%",
|
|
255
|
+
"language": "rust",
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
except Exception as exc:
|
|
259
|
+
return _error_result("rust", f"unexpected-error: {exc}")
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
"""Regex-based import parsers for JavaScript/TypeScript and Go.
|
|
2
|
+
|
|
3
|
+
These parsers are intentionally lightweight and best-effort.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
import re
|
|
8
|
+
from typing import NotRequired, TypedDict, cast
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class ParseResult(TypedDict):
|
|
12
|
+
imports: list[str]
|
|
13
|
+
accuracy: str
|
|
14
|
+
language: str
|
|
15
|
+
error: NotRequired[str]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def _read_text_file(file_path: str) -> tuple[str | None, str | None]:
|
|
19
|
+
"""Read UTF-8 text safely, returning (text, error)."""
|
|
20
|
+
try:
|
|
21
|
+
raw = Path(file_path).read_bytes()
|
|
22
|
+
except OSError as exc:
|
|
23
|
+
return None, f"file-read-error: {exc}"
|
|
24
|
+
|
|
25
|
+
if b"\x00" in raw:
|
|
26
|
+
return None, "unparseable-file: binary content detected"
|
|
27
|
+
|
|
28
|
+
try:
|
|
29
|
+
return raw.decode("utf-8"), None
|
|
30
|
+
except UnicodeDecodeError as exc:
|
|
31
|
+
return None, f"unparseable-file: {exc}"
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def _result(imports: list[str], accuracy: str, language: str, error: str | None) -> ParseResult:
|
|
35
|
+
result: ParseResult = {
|
|
36
|
+
"imports": imports,
|
|
37
|
+
"accuracy": accuracy,
|
|
38
|
+
"language": language,
|
|
39
|
+
}
|
|
40
|
+
if error:
|
|
41
|
+
result["error"] = error
|
|
42
|
+
return result
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def _unique(values: list[str]) -> list[str]:
|
|
46
|
+
seen: set[str] = set()
|
|
47
|
+
ordered: list[str] = []
|
|
48
|
+
for value in values:
|
|
49
|
+
if value not in seen:
|
|
50
|
+
seen.add(value)
|
|
51
|
+
ordered.append(value)
|
|
52
|
+
return ordered
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def parse_js_imports(file_path: str) -> ParseResult:
|
|
56
|
+
"""Parse JS/TS import specifiers from a file via regex (~70% accuracy).
|
|
57
|
+
|
|
58
|
+
Accuracy: ~70% ("regex-70%").
|
|
59
|
+
Known misses: dynamic imports with variables/template literals,
|
|
60
|
+
complex transpiler syntax, and imports hidden in non-UTF8 files.
|
|
61
|
+
"""
|
|
62
|
+
text, error = _read_text_file(file_path)
|
|
63
|
+
if text is None:
|
|
64
|
+
return _result([], "regex-70%", "javascript", error)
|
|
65
|
+
|
|
66
|
+
imports: list[str] = []
|
|
67
|
+
|
|
68
|
+
static_import_re = re.compile(
|
|
69
|
+
r"^\s*import\s+(?:[\w*$\s{},]+\s+from\s+)?['\"]([^'\"]+)['\"]",
|
|
70
|
+
re.MULTILINE,
|
|
71
|
+
)
|
|
72
|
+
require_re = re.compile(r"require\s*\(\s*['\"]([^'\"]+)['\"]\s*\)")
|
|
73
|
+
export_from_re = re.compile(
|
|
74
|
+
r"^\s*export\s+\*\s+from\s+['\"]([^'\"]+)['\"]",
|
|
75
|
+
re.MULTILINE,
|
|
76
|
+
)
|
|
77
|
+
dynamic_import_re = re.compile(r"import\s*\(\s*['\"]([^'\"]+)['\"]\s*\)")
|
|
78
|
+
|
|
79
|
+
imports.extend(static_import_re.findall(text))
|
|
80
|
+
imports.extend(require_re.findall(text))
|
|
81
|
+
imports.extend(export_from_re.findall(text))
|
|
82
|
+
imports.extend(dynamic_import_re.findall(text))
|
|
83
|
+
|
|
84
|
+
return _result(_unique(imports), "regex-70%", "javascript", None)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def parse_go_imports(file_path: str) -> ParseResult:
|
|
88
|
+
"""Parse Go import paths from a file via regex (~80% accuracy).
|
|
89
|
+
|
|
90
|
+
Accuracy: ~80% ("regex-80%").
|
|
91
|
+
Known misses: imports gated by build tags/conditional file inclusion,
|
|
92
|
+
and non-UTF8 or unparseable files.
|
|
93
|
+
"""
|
|
94
|
+
text, error = _read_text_file(file_path)
|
|
95
|
+
if text is None:
|
|
96
|
+
return _result([], "regex-80%", "go", error)
|
|
97
|
+
|
|
98
|
+
imports: list[str] = []
|
|
99
|
+
|
|
100
|
+
single_or_alias_re = re.compile(
|
|
101
|
+
r'^\s*import\s+(?:[A-Za-z_][\w.]*)?\s*"([^"]+)"',
|
|
102
|
+
re.MULTILINE,
|
|
103
|
+
)
|
|
104
|
+
block_re = re.compile(r"import\s*\((.*?)\)", re.DOTALL)
|
|
105
|
+
block_entry_re = re.compile(r'(?:[A-Za-z_][\w.]*)?\s*"([^"]+)"')
|
|
106
|
+
|
|
107
|
+
imports.extend(single_or_alias_re.findall(text))
|
|
108
|
+
|
|
109
|
+
for block in cast(list[str], block_re.findall(text)):
|
|
110
|
+
imports.extend(block_entry_re.findall(block))
|
|
111
|
+
|
|
112
|
+
return _result(_unique(imports), "regex-80%", "go", None)
|
package/pyproject.toml
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=65.0", "wheel"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "oh-my-god"
|
|
7
|
+
version = "2.0.0b1"
|
|
8
|
+
description = "OMG (Oh My God) — Multi-agent orchestration, intelligent model routing, and durable session state for Claude Code"
|
|
9
|
+
readme = "README.md"
|
|
10
|
+
requires-python = ">=3.10"
|
|
11
|
+
license = {text = "MIT"}
|
|
12
|
+
authors = [
|
|
13
|
+
{name = "trac3er00", email = "trac3er00@example.com"}
|
|
14
|
+
]
|
|
15
|
+
keywords = ["claude", "claude-code", "orchestration", "multi-agent", "ai", "llm", "codex", "gemini"]
|
|
16
|
+
classifiers = [
|
|
17
|
+
"Development Status :: 4 - Beta",
|
|
18
|
+
"Intended Audience :: Developers",
|
|
19
|
+
"License :: OSI Approved :: MIT License",
|
|
20
|
+
"Programming Language :: Python :: 3",
|
|
21
|
+
"Programming Language :: Python :: 3.10",
|
|
22
|
+
"Programming Language :: Python :: 3.11",
|
|
23
|
+
"Programming Language :: Python :: 3.12",
|
|
24
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
25
|
+
]
|
|
26
|
+
dependencies = [
|
|
27
|
+
"fastmcp>=2.0",
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[project.optional-dependencies]
|
|
31
|
+
test = [
|
|
32
|
+
"pytest>=7.0",
|
|
33
|
+
"pytest-cov>=4.0",
|
|
34
|
+
]
|
|
35
|
+
mcp = [
|
|
36
|
+
"fastmcp>=2.0",
|
|
37
|
+
]
|
|
38
|
+
|
|
39
|
+
[project.urls]
|
|
40
|
+
Homepage = "https://github.com/trac3er00/OMG"
|
|
41
|
+
Repository = "https://github.com/trac3er00/OMG.git"
|
|
42
|
+
Issues = "https://github.com/trac3er00/OMG/issues"
|
|
43
|
+
|
|
44
|
+
[tool.setuptools]
|
|
45
|
+
packages = ["hooks", "runtime", "agents", "commands"]
|
|
46
|
+
|
|
47
|
+
[tool.pytest.ini_options]
|
|
48
|
+
testpaths = ["tests"]
|
|
49
|
+
python_files = ["test_*.py"]
|
|
50
|
+
python_classes = ["Test*"]
|
|
51
|
+
python_functions = ["test_*"]
|
|
52
|
+
addopts = [
|
|
53
|
+
"--strict-markers",
|
|
54
|
+
"--cov=.",
|
|
55
|
+
"--cov-report=term-missing",
|
|
56
|
+
"--cov-report=html",
|
|
57
|
+
]
|
|
58
|
+
markers = [
|
|
59
|
+
"slow: marks tests as slow",
|
|
60
|
+
"integration: marks tests as integration tests",
|
|
61
|
+
"unit: marks tests as unit tests",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
[tool.coverage.run]
|
|
65
|
+
source = ["."]
|
|
66
|
+
omit = [
|
|
67
|
+
"tests/*",
|
|
68
|
+
"*/__pycache__/*",
|
|
69
|
+
".venv/*",
|
|
70
|
+
"setup.py",
|
|
71
|
+
]
|
|
72
|
+
|
|
73
|
+
[tool.coverage.report]
|
|
74
|
+
exclude_lines = [
|
|
75
|
+
"pragma: no cover",
|
|
76
|
+
"def __repr__",
|
|
77
|
+
"raise AssertionError",
|
|
78
|
+
"raise NotImplementedError",
|
|
79
|
+
"if __name__ == .__main__.:",
|
|
80
|
+
"if TYPE_CHECKING:",
|
|
81
|
+
]
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
When any file write or edit operation shows an error, warning, or hook error:
|
|
4
4
|
|
|
5
5
|
1. **NEVER claim success** without reading the file to verify changes are present
|
|
6
|
-
2. **Hook errors from external plugins** (e.g.
|
|
6
|
+
2. **Hook errors from external plugins** (e.g. security_reminder_hook.py) are warnings — the write may have succeeded. READ the file to check.
|
|
7
7
|
3. **"Error editing file"** means the Edit tool failed. Use an alternative:
|
|
8
8
|
- Try `Write` tool (creates new file)
|
|
9
9
|
- Try Bash: `cat > path/to/file << 'EOF'\n[content]\nEOF`
|
|
@@ -13,7 +13,7 @@ When any file write or edit operation shows an error, warning, or hook error:
|
|
|
13
13
|
|
|
14
14
|
## Common Hook Error Pattern
|
|
15
15
|
```
|
|
16
|
-
Error: PreToolUse:Write hook error: [
|
|
16
|
+
Error: PreToolUse:Write hook error: [python3 .../security_reminder_hook.py]: ⚠️ Security Warning: ...
|
|
17
17
|
```
|
|
18
18
|
This means an external hook emitted a warning. The file write likely succeeded.
|
|
19
19
|
**Action:** Read the file to verify, then continue. Do NOT retry blindly.
|
package/rules/core/00-truth.md
CHANGED
|
@@ -17,4 +17,4 @@ NEVER claim a state you haven't verified. Period.
|
|
|
17
17
|
|
|
18
18
|
Forbidden without evidence: "done", "LGTM", "fixed", "works now", "tests passed"
|
|
19
19
|
|
|
20
|
-
> Enforced: stop-gate.
|
|
20
|
+
> Enforced: stop-gate.py checks evidence. tool-ledger.py logs tool calls.
|
|
@@ -16,4 +16,4 @@ For 3+ file changes: create .omg/state/_plan.md + _checklist.md BEFORE coding.
|
|
|
16
16
|
Mark [x] immediately as steps complete. Update plan when approach changes.
|
|
17
17
|
If stuck 2x: STOP. Try different approach or /OMG:escalate.
|
|
18
18
|
|
|
19
|
-
> Enforced: stop-gate.
|
|
19
|
+
> Enforced: stop-gate.py checks diff budget. circuit-breaker.py catches loops.
|
|
@@ -16,7 +16,7 @@ Options:
|
|
|
16
16
|
- **Force-Fixer:** Immediately try to fix without understanding root cause
|
|
17
17
|
|
|
18
18
|
## Auto-Escalation
|
|
19
|
-
After 3 failures: circuit-breaker.
|
|
19
|
+
After 3 failures: circuit-breaker.py suggests /OMG:escalate with specific context.
|
|
20
20
|
After 5 failures: HARD BLOCK. Must escalate or get user input.
|
|
21
21
|
|
|
22
|
-
> Enforced: circuit-breaker.
|
|
22
|
+
> Enforced: circuit-breaker.py tracks patterns + auto-escalates.
|
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
- Stuck on anything for 3+ attempts → /OMG:escalate to relevant model
|
|
14
14
|
|
|
15
15
|
## Auto-Detection
|
|
16
|
-
prompt-enhancer.
|
|
17
|
-
circuit-breaker.
|
|
16
|
+
prompt-enhancer.py detects keywords and suggests the right model.
|
|
17
|
+
circuit-breaker.py auto-suggests escalation after failures.
|
|
18
18
|
|
|
19
19
|
## Plugins & MCPs
|
|
20
20
|
- Installed plugins: USE them (they're installed for a reason)
|
|
@@ -25,4 +25,4 @@ circuit-breaker.ts auto-suggests escalation after failures.
|
|
|
25
25
|
Say: "This touches auth — let me get Codex to check the security."
|
|
26
26
|
NOT: "Invoking cross-model review protocol for backend analysis."
|
|
27
27
|
|
|
28
|
-
> Enforced: prompt-enhancer.
|
|
28
|
+
> Enforced: prompt-enhancer.py + session-start.py detect available tools.
|
package/rules/core/04-testing.md
CHANGED
|
@@ -24,7 +24,7 @@ Then write tests for THOSE scenarios.
|
|
|
24
24
|
|
|
25
25
|
## Quality Gate
|
|
26
26
|
Every change runs: format → lint → typecheck (if typed) → test
|
|
27
|
-
If quality-gate.json exists, quality-runner.
|
|
27
|
+
If quality-gate.json exists, quality-runner.py enforces this.
|
|
28
28
|
|
|
29
|
-
> Enforced: test-
|
|
30
|
-
> quality-runner.
|
|
29
|
+
> Enforced: test-validator.py catches fake/boilerplate tests.
|
|
30
|
+
> quality-runner.py runs QA commands.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"""Runtime package for OMG."""
|
|
2
|
+
|
|
3
|
+
from .compat import (
|
|
4
|
+
build_compat_gap_report,
|
|
5
|
+
build_omg_gap_report,
|
|
6
|
+
dispatch_compat_skill,
|
|
7
|
+
dispatch_omg_skill,
|
|
8
|
+
get_compat_skill_contract,
|
|
9
|
+
get_omg_skill_contract,
|
|
10
|
+
list_compat_skill_contracts,
|
|
11
|
+
list_compat_skills,
|
|
12
|
+
list_omg_skill_contracts,
|
|
13
|
+
list_omg_skills,
|
|
14
|
+
)
|
|
15
|
+
from .ecosystem import ecosystem_status, list_ecosystem_repos, resolve_ecosystem_selection, sync_ecosystem_repos
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"build_compat_gap_report",
|
|
19
|
+
"build_omg_gap_report",
|
|
20
|
+
"dispatch_compat_skill",
|
|
21
|
+
"dispatch_omg_skill",
|
|
22
|
+
"get_compat_skill_contract",
|
|
23
|
+
"get_omg_skill_contract",
|
|
24
|
+
"list_compat_skill_contracts",
|
|
25
|
+
"list_compat_skills",
|
|
26
|
+
"list_omg_skill_contracts",
|
|
27
|
+
"list_omg_skills",
|
|
28
|
+
"ecosystem_status",
|
|
29
|
+
"list_ecosystem_repos",
|
|
30
|
+
"resolve_ecosystem_selection",
|
|
31
|
+
"sync_ecosystem_repos",
|
|
32
|
+
]
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"""Runtime adapters for OMG v1."""
|
|
2
|
+
|
|
3
|
+
from .claude import ClaudeAdapter
|
|
4
|
+
from .gpt import GPTAdapter
|
|
5
|
+
from .local import LocalAdapter
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def get_adapters():
|
|
9
|
+
return {
|
|
10
|
+
"claude": ClaudeAdapter(),
|
|
11
|
+
"gpt": GPTAdapter(),
|
|
12
|
+
"local": LocalAdapter(),
|
|
13
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""Claude runtime adapter (v1 stub)."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from datetime import datetime, timezone
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ClaudeAdapter:
|
|
9
|
+
runtime = "claude"
|
|
10
|
+
|
|
11
|
+
def plan(self, idea: dict[str, Any]) -> dict[str, Any]:
|
|
12
|
+
goal = str(idea.get("goal", "")).strip() or "unspecified-goal"
|
|
13
|
+
return {
|
|
14
|
+
"runtime": self.runtime,
|
|
15
|
+
"phase": "plan",
|
|
16
|
+
"status": "planned",
|
|
17
|
+
"goal": goal,
|
|
18
|
+
"steps": [
|
|
19
|
+
"analyze-goal",
|
|
20
|
+
"generate-plan",
|
|
21
|
+
"emit-checklist",
|
|
22
|
+
],
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
def execute(self, plan: dict[str, Any]) -> dict[str, Any]:
|
|
26
|
+
return {
|
|
27
|
+
"runtime": self.runtime,
|
|
28
|
+
"phase": "execute",
|
|
29
|
+
"status": "executed",
|
|
30
|
+
"operations": [
|
|
31
|
+
"apply-plan",
|
|
32
|
+
"collect-diff",
|
|
33
|
+
],
|
|
34
|
+
"errors": [],
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
def verify(self, execution_result: dict[str, Any]) -> dict[str, Any]:
|
|
38
|
+
return {
|
|
39
|
+
"runtime": self.runtime,
|
|
40
|
+
"phase": "verify",
|
|
41
|
+
"status": "verified",
|
|
42
|
+
"ok": True,
|
|
43
|
+
"checks": [
|
|
44
|
+
{"name": "tests", "passed": True},
|
|
45
|
+
{"name": "security", "passed": True},
|
|
46
|
+
],
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
def collect_evidence(self, verify_result: dict[str, Any]) -> dict[str, Any]:
|
|
50
|
+
return {
|
|
51
|
+
"runtime": self.runtime,
|
|
52
|
+
"phase": "evidence",
|
|
53
|
+
"status": "collected",
|
|
54
|
+
"created_at": datetime.now(timezone.utc).isoformat(),
|
|
55
|
+
"tests": verify_result.get("checks", []),
|
|
56
|
+
"security_scans": [],
|
|
57
|
+
"diff_summary": {},
|
|
58
|
+
"reproducibility": {"seed": "deterministic"},
|
|
59
|
+
"unresolved_risks": [],
|
|
60
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""GPT runtime adapter (v1 stub)."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
from datetime import datetime, timezone
|
|
5
|
+
from typing import Any
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class GPTAdapter:
|
|
9
|
+
runtime = "gpt"
|
|
10
|
+
|
|
11
|
+
def plan(self, idea: dict[str, Any]) -> dict[str, Any]:
|
|
12
|
+
goal = str(idea.get("goal", "")).strip() or "unspecified-goal"
|
|
13
|
+
return {
|
|
14
|
+
"runtime": self.runtime,
|
|
15
|
+
"phase": "plan",
|
|
16
|
+
"status": "planned",
|
|
17
|
+
"goal": goal,
|
|
18
|
+
"steps": ["analyze-goal", "generate-plan", "emit-checklist"],
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
def execute(self, plan: dict[str, Any]) -> dict[str, Any]:
|
|
22
|
+
return {
|
|
23
|
+
"runtime": self.runtime,
|
|
24
|
+
"phase": "execute",
|
|
25
|
+
"status": "executed",
|
|
26
|
+
"operations": ["apply-plan", "collect-diff"],
|
|
27
|
+
"errors": [],
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
def verify(self, execution_result: dict[str, Any]) -> dict[str, Any]:
|
|
31
|
+
return {
|
|
32
|
+
"runtime": self.runtime,
|
|
33
|
+
"phase": "verify",
|
|
34
|
+
"status": "verified",
|
|
35
|
+
"ok": True,
|
|
36
|
+
"checks": [
|
|
37
|
+
{"name": "tests", "passed": True},
|
|
38
|
+
{"name": "security", "passed": True},
|
|
39
|
+
],
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
def collect_evidence(self, verify_result: dict[str, Any]) -> dict[str, Any]:
|
|
43
|
+
return {
|
|
44
|
+
"runtime": self.runtime,
|
|
45
|
+
"phase": "evidence",
|
|
46
|
+
"status": "collected",
|
|
47
|
+
"created_at": datetime.now(timezone.utc).isoformat(),
|
|
48
|
+
"tests": verify_result.get("checks", []),
|
|
49
|
+
"security_scans": [],
|
|
50
|
+
"diff_summary": {},
|
|
51
|
+
"reproducibility": {"seed": "deterministic"},
|
|
52
|
+
"unresolved_risks": [],
|
|
53
|
+
}
|