@trac3er/oh-my-god 2.0.8 → 2.0.9
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 +2 -2
- package/.claude-plugin/plugin.json +1 -1
- package/.gemini/settings.json +11 -0
- package/.kimi/mcp.json +11 -0
- package/CHANGELOG.md +10 -0
- package/OMG-setup.sh +1 -1
- package/OMG_COMPAT_CONTRACT.md +10 -4
- package/README.md +1 -0
- package/build/lib/commands/OMG:forge.md +92 -0
- package/build/lib/commands/OMG:mode.md +13 -13
- package/build/lib/commands/OMG:session-branch.md +17 -1
- package/build/lib/commands/OMG:session-fork.md +5 -1
- package/build/lib/commands/OMG:session-merge.md +5 -1
- package/build/lib/control_plane/server.py +4 -0
- package/build/lib/control_plane/service.py +55 -0
- package/build/lib/hooks/setup_wizard.py +21 -1
- package/build/lib/hooks/shadow_manager.py +25 -2
- package/build/lib/hooks/state_migration.py +3 -0
- package/build/lib/plugins/dephealth/cve_scanner.py +91 -0
- package/build/lib/plugins/dephealth/vuln_analyzer.py +7 -0
- package/build/lib/registry/omg-capability.schema.json +83 -1
- package/build/lib/runtime/adoption.py +12 -4
- package/build/lib/runtime/artifact_parsers.py +161 -0
- package/build/lib/runtime/background_verification.py +48 -0
- package/build/lib/runtime/claim_judge.py +184 -7
- package/build/lib/runtime/contract_compiler.py +118 -9
- package/build/lib/runtime/evidence_query.py +203 -0
- package/build/lib/runtime/omg_mcp_server.py +19 -0
- package/build/lib/runtime/playwright_adapter.py +39 -0
- package/build/lib/runtime/proof_chain.py +136 -8
- package/build/lib/runtime/proof_gate.py +102 -0
- package/build/lib/runtime/providers/gemini_provider.py +7 -0
- package/build/lib/runtime/providers/kimi_provider.py +7 -0
- package/build/lib/runtime/repro_pack.py +292 -0
- package/build/lib/runtime/runtime_profile.py +87 -15
- package/build/lib/runtime/security_check.py +86 -3
- package/build/lib/runtime/test_intent_lock.py +47 -0
- package/build/lib/runtime/tracebank.py +33 -3
- package/build/lib/runtime/verification_loop.py +73 -0
- package/commands/OMG:forge.md +92 -0
- package/commands/OMG:mode.md +13 -13
- package/commands/OMG:session-branch.md +17 -1
- package/commands/OMG:session-fork.md +5 -1
- package/commands/OMG:session-merge.md +5 -1
- package/control_plane/server.py +4 -0
- package/control_plane/service.py +55 -0
- package/dist/enterprise/bundle/.gemini/settings.json +11 -0
- package/dist/enterprise/bundle/.kimi/mcp.json +11 -0
- package/dist/enterprise/bundle/OMG_COMPAT_CONTRACT.md +9 -3
- package/dist/enterprise/bundle/registry/omg-capability.schema.json +83 -1
- package/dist/enterprise/bundle/settings.json +1 -0
- package/dist/enterprise/manifest.json +17 -3
- package/dist/public/bundle/.agents/skills/omg/incident-replay/SKILL.md +1 -1
- package/dist/public/bundle/.agents/skills/omg/incident-replay/openai.yaml +1 -1
- package/dist/public/bundle/.agents/skills/omg/lsp-pack/SKILL.md +1 -1
- package/dist/public/bundle/.agents/skills/omg/lsp-pack/openai.yaml +1 -1
- package/dist/public/bundle/.agents/skills/omg/mcp-fabric/SKILL.md +1 -1
- package/dist/public/bundle/.agents/skills/omg/mcp-fabric/openai.yaml +1 -1
- package/dist/public/bundle/.agents/skills/omg/plan-council/SKILL.md +1 -1
- package/dist/public/bundle/.agents/skills/omg/plan-council/openai.yaml +1 -1
- package/dist/public/bundle/.agents/skills/omg/preflight/SKILL.md +1 -1
- package/dist/public/bundle/.agents/skills/omg/preflight/openai.yaml +1 -1
- package/dist/public/bundle/.agents/skills/omg/proof-gate/SKILL.md +1 -1
- package/dist/public/bundle/.agents/skills/omg/proof-gate/openai.yaml +1 -1
- package/dist/public/bundle/.agents/skills/omg/remote-supervisor/SKILL.md +1 -1
- package/dist/public/bundle/.agents/skills/omg/remote-supervisor/openai.yaml +1 -1
- package/dist/public/bundle/.agents/skills/omg/robotics/SKILL.md +1 -1
- package/dist/public/bundle/.agents/skills/omg/robotics/openai.yaml +1 -1
- package/dist/public/bundle/.agents/skills/omg/secure-worktree-pipeline/SKILL.md +1 -1
- package/dist/public/bundle/.agents/skills/omg/secure-worktree-pipeline/openai.yaml +1 -1
- package/dist/public/bundle/.agents/skills/omg/security-check/SKILL.md +1 -1
- package/dist/public/bundle/.agents/skills/omg/security-check/openai.yaml +1 -1
- package/dist/public/bundle/.agents/skills/omg/test-intent-lock/SKILL.md +1 -1
- package/dist/public/bundle/.agents/skills/omg/test-intent-lock/openai.yaml +1 -1
- package/dist/public/bundle/.agents/skills/omg/tracebank/SKILL.md +1 -1
- package/dist/public/bundle/.agents/skills/omg/tracebank/openai.yaml +1 -1
- package/dist/public/bundle/.agents/skills/omg/vision/SKILL.md +1 -1
- package/dist/public/bundle/.agents/skills/omg/vision/openai.yaml +1 -1
- package/dist/public/bundle/.gemini/settings.json +11 -0
- package/dist/public/bundle/.kimi/mcp.json +11 -0
- package/dist/public/bundle/OMG_COMPAT_CONTRACT.md +9 -3
- package/dist/public/bundle/registry/omg-capability.schema.json +83 -1
- package/dist/public/bundle/settings.json +2 -1
- package/dist/public/manifest.json +43 -29
- package/docs/proof.md +1 -0
- package/hooks/setup_wizard.py +21 -1
- package/hooks/shadow_manager.py +25 -2
- package/hooks/state_migration.py +3 -0
- package/hud/omg-hud.mjs +66 -3
- package/package.json +1 -1
- package/plugins/advanced/plugin.json +1 -1
- package/plugins/core/plugin.json +1 -1
- package/plugins/dephealth/cve_scanner.py +91 -0
- package/plugins/dephealth/vuln_analyzer.py +7 -0
- package/pyproject.toml +1 -1
- package/registry/omg-capability.schema.json +83 -1
- package/runtime/adoption.py +13 -5
- package/runtime/artifact_parsers.py +161 -0
- package/runtime/background_verification.py +48 -0
- package/runtime/claim_judge.py +184 -7
- package/runtime/contract_compiler.py +118 -9
- package/runtime/evidence_query.py +203 -0
- package/runtime/omg_mcp_server.py +19 -0
- package/runtime/playwright_adapter.py +39 -0
- package/runtime/proof_chain.py +136 -8
- package/runtime/proof_gate.py +102 -0
- package/runtime/providers/gemini_provider.py +7 -0
- package/runtime/providers/kimi_provider.py +7 -0
- package/runtime/repro_pack.py +292 -0
- package/runtime/runtime_profile.py +87 -15
- package/runtime/security_check.py +86 -3
- package/runtime/test_intent_lock.py +47 -0
- package/runtime/tracebank.py +33 -3
- package/runtime/verification_loop.py +73 -0
- package/scripts/omg.py +30 -3
- package/settings.json +4 -3
- package/tools/python_sandbox.py +9 -6
- package/tools/session_snapshot.py +146 -40
package/hooks/shadow_manager.py
CHANGED
|
@@ -6,6 +6,7 @@ Maintains overlay-style shadow writes and evidence artifacts.
|
|
|
6
6
|
from __future__ import annotations
|
|
7
7
|
|
|
8
8
|
import hashlib
|
|
9
|
+
import importlib
|
|
9
10
|
import json
|
|
10
11
|
import os
|
|
11
12
|
import platform
|
|
@@ -18,8 +19,15 @@ from typing import Any
|
|
|
18
19
|
HOOKS_DIR = os.path.dirname(__file__)
|
|
19
20
|
if HOOKS_DIR not in sys.path:
|
|
20
21
|
sys.path.insert(0, HOOKS_DIR)
|
|
21
|
-
|
|
22
|
-
from
|
|
22
|
+
try:
|
|
23
|
+
from hooks._common import _resolve_project_dir
|
|
24
|
+
from hooks.security_validators import ensure_path_within_dir, validate_opaque_identifier
|
|
25
|
+
except ImportError:
|
|
26
|
+
_common = importlib.import_module("_common")
|
|
27
|
+
security_validators = importlib.import_module("security_validators")
|
|
28
|
+
_resolve_project_dir = _common._resolve_project_dir
|
|
29
|
+
ensure_path_within_dir = security_validators.ensure_path_within_dir
|
|
30
|
+
validate_opaque_identifier = security_validators.validate_opaque_identifier
|
|
23
31
|
|
|
24
32
|
|
|
25
33
|
def _project_dir() -> str:
|
|
@@ -189,6 +197,11 @@ def create_evidence_pack(
|
|
|
189
197
|
lineage: dict[str, Any] | None = None,
|
|
190
198
|
executor: dict[str, Any] | None = None,
|
|
191
199
|
environment: dict[str, Any] | None = None,
|
|
200
|
+
artifacts: list[dict[str, Any]] | None = None,
|
|
201
|
+
claims: list[dict[str, Any]] | None = None,
|
|
202
|
+
test_delta: dict[str, Any] | None = None,
|
|
203
|
+
browser_evidence_path: str | None = None,
|
|
204
|
+
repro_pack_path: str | None = None,
|
|
192
205
|
) -> str:
|
|
193
206
|
ensure_shadow_dirs(project_dir)
|
|
194
207
|
run_id = _validated_run_id(run_id)
|
|
@@ -209,6 +222,7 @@ def create_evidence_pack(
|
|
|
209
222
|
|
|
210
223
|
evidence = {
|
|
211
224
|
"schema": "EvidencePack",
|
|
225
|
+
"schema_version": 2,
|
|
212
226
|
"run_id": run_id,
|
|
213
227
|
"created_at": _utc_now(),
|
|
214
228
|
"tests": tests or [],
|
|
@@ -224,7 +238,16 @@ def create_evidence_pack(
|
|
|
224
238
|
"lineage": lineage or {},
|
|
225
239
|
"executor": executor,
|
|
226
240
|
"environment": environment,
|
|
241
|
+
"artifacts": artifacts or [],
|
|
227
242
|
}
|
|
243
|
+
if claims is not None:
|
|
244
|
+
evidence["claims"] = claims
|
|
245
|
+
if test_delta is not None:
|
|
246
|
+
evidence["test_delta"] = test_delta
|
|
247
|
+
if browser_evidence_path is not None:
|
|
248
|
+
evidence["browser_evidence_path"] = browser_evidence_path
|
|
249
|
+
if repro_pack_path is not None:
|
|
250
|
+
evidence["repro_pack_path"] = repro_pack_path
|
|
228
251
|
evidence_path = ensure_path_within_dir(
|
|
229
252
|
_evidence_root(project_dir),
|
|
230
253
|
os.path.join(_evidence_root(project_dir), f"{run_id}.json"),
|
package/hooks/state_migration.py
CHANGED
|
@@ -115,6 +115,9 @@ MIGRATION_MAP: list[tuple[str, str, str]] = [
|
|
|
115
115
|
("dir", "repl_sessions", "state/repl_sessions"),
|
|
116
116
|
("dir", "sessions", "state/sessions"),
|
|
117
117
|
("dir", "snapshots", "state/snapshots"),
|
|
118
|
+
("file", "current_branch.json", "state/current_branch.json"),
|
|
119
|
+
("file", "background-verification.json", "state/background-verification.json"),
|
|
120
|
+
("dir", "branches", "state/branches"),
|
|
118
121
|
("dir", "knowledge", "knowledge"),
|
|
119
122
|
]
|
|
120
123
|
|
package/hud/omg-hud.mjs
CHANGED
|
@@ -55,7 +55,7 @@ function readOmgVersion() {
|
|
|
55
55
|
const OMG_VERSION = readOmgVersion();
|
|
56
56
|
|
|
57
57
|
const DEFAULT_HUD_CONFIG = {
|
|
58
|
-
preset: "
|
|
58
|
+
preset: "standard",
|
|
59
59
|
elements: {
|
|
60
60
|
cwd: true,
|
|
61
61
|
cwdFormat: "relative",
|
|
@@ -129,7 +129,7 @@ const PRESET_CONFIGS = {
|
|
|
129
129
|
safeMode: true,
|
|
130
130
|
inventory: true,
|
|
131
131
|
},
|
|
132
|
-
|
|
132
|
+
standard: {
|
|
133
133
|
cwd: true,
|
|
134
134
|
cwdFormat: "relative",
|
|
135
135
|
gitRepo: false,
|
|
@@ -251,6 +251,17 @@ const PRESET_CONFIGS = {
|
|
|
251
251
|
},
|
|
252
252
|
};
|
|
253
253
|
|
|
254
|
+
const HUD_PRESET_ALIASES = {
|
|
255
|
+
focused: "standard",
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
function resolveHudPreset(preset) {
|
|
259
|
+
const requested = typeof preset === "string" ? preset : DEFAULT_HUD_CONFIG.preset;
|
|
260
|
+
const canonical = HUD_PRESET_ALIASES[requested] || requested;
|
|
261
|
+
if (PRESET_CONFIGS[canonical]) return canonical;
|
|
262
|
+
return DEFAULT_HUD_CONFIG.preset;
|
|
263
|
+
}
|
|
264
|
+
|
|
254
265
|
function countByExt(dirPath, ext) {
|
|
255
266
|
if (!existsSync(dirPath)) return 0;
|
|
256
267
|
try {
|
|
@@ -373,7 +384,7 @@ function readRawHudConfig() {
|
|
|
373
384
|
|
|
374
385
|
function readHudConfig() {
|
|
375
386
|
const source = readRawHudConfig();
|
|
376
|
-
const preset = source.preset
|
|
387
|
+
const preset = resolveHudPreset(source.preset);
|
|
377
388
|
const presetElements = PRESET_CONFIGS[preset] || {};
|
|
378
389
|
const elements = {
|
|
379
390
|
...DEFAULT_HUD_CONFIG.elements,
|
|
@@ -530,6 +541,7 @@ function readOmgState(cwd) {
|
|
|
530
541
|
const stateDir = join(cwd, ".omg", "state");
|
|
531
542
|
const result = {
|
|
532
543
|
modes: [],
|
|
544
|
+
currentMode: null,
|
|
533
545
|
hookCount: 0,
|
|
534
546
|
profile: null,
|
|
535
547
|
ralph: null,
|
|
@@ -564,6 +576,14 @@ function readOmgState(cwd) {
|
|
|
564
576
|
}
|
|
565
577
|
}
|
|
566
578
|
|
|
579
|
+
const modeState = readJsonSafe(join(stateDir, "mode.json"));
|
|
580
|
+
if (modeState && typeof modeState === "object") {
|
|
581
|
+
const candidate = modeState.mode || modeState.current_mode || modeState.name;
|
|
582
|
+
if (typeof candidate === "string" && candidate.trim()) {
|
|
583
|
+
result.currentMode = candidate.trim().toLowerCase();
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
|
|
567
587
|
const ralphState = readJsonSafe(join(stateDir, "ralph-state.json"));
|
|
568
588
|
if (ralphState?.active) {
|
|
569
589
|
result.ralph = {
|
|
@@ -627,6 +647,19 @@ function readOmgState(cwd) {
|
|
|
627
647
|
return result;
|
|
628
648
|
}
|
|
629
649
|
|
|
650
|
+
function readBackgroundVerificationState(stateDir) {
|
|
651
|
+
const filePath = join(stateDir, "background-verification.json");
|
|
652
|
+
const data = readJsonSafe(filePath);
|
|
653
|
+
if (!data || data.schema !== "BackgroundVerificationState") return null;
|
|
654
|
+
return {
|
|
655
|
+
status: data.status || "unknown",
|
|
656
|
+
blockers: Array.isArray(data.blockers) ? data.blockers : [],
|
|
657
|
+
evidence_links: Array.isArray(data.evidence_links) ? data.evidence_links : [],
|
|
658
|
+
progress: data.progress || {},
|
|
659
|
+
updated_at: data.updated_at || null,
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
|
|
630
663
|
function parseTranscript(transcriptPath) {
|
|
631
664
|
const result = {
|
|
632
665
|
tools: 0,
|
|
@@ -814,6 +847,29 @@ function renderBackgroundTasks(tasks) {
|
|
|
814
847
|
return `bg:${colorFn(`${running}/${MAX}`)}`;
|
|
815
848
|
}
|
|
816
849
|
|
|
850
|
+
function renderVerificationStatus(state) {
|
|
851
|
+
if (!state) return dim("verification: unknown");
|
|
852
|
+
const { status, blockers, evidence_links } = state;
|
|
853
|
+
const blockerCount = blockers.length;
|
|
854
|
+
const latestEvidence = evidence_links.length > 0
|
|
855
|
+
? evidence_links[evidence_links.length - 1]
|
|
856
|
+
: null;
|
|
857
|
+
const evidenceSuffix = latestEvidence
|
|
858
|
+
? ` ${dim(`evidence:${basename(latestEvidence)}`)}`
|
|
859
|
+
: "";
|
|
860
|
+
if (status === "ok") {
|
|
861
|
+
return green("\u2713 verification ok") + evidenceSuffix;
|
|
862
|
+
}
|
|
863
|
+
if (status === "running") {
|
|
864
|
+
return yellow("\u27F3 verification running") + evidenceSuffix;
|
|
865
|
+
}
|
|
866
|
+
if (status === "error" || status === "blocked") {
|
|
867
|
+
const blockerSuffix = blockerCount > 0 ? ` (${blockerCount} blockers)` : "";
|
|
868
|
+
return red(`\u2717 verification blocked${blockerSuffix}`) + evidenceSuffix;
|
|
869
|
+
}
|
|
870
|
+
return dim("verification: unknown");
|
|
871
|
+
}
|
|
872
|
+
|
|
817
873
|
function renderTodos(todos) {
|
|
818
874
|
if (!todos || todos.length === 0) return null;
|
|
819
875
|
const completed = todos.filter((t) => t.status === "completed").length;
|
|
@@ -1136,6 +1192,9 @@ async function main() {
|
|
|
1136
1192
|
|
|
1137
1193
|
// Active skills (modes) + last skill
|
|
1138
1194
|
if (cfg.elements.activeSkills !== false) {
|
|
1195
|
+
if (omgState.currentMode) {
|
|
1196
|
+
els.push(`mode:${cyan(omgState.currentMode)}`);
|
|
1197
|
+
}
|
|
1139
1198
|
const modeBadges = renderModeBadges(omgState.modes, {
|
|
1140
1199
|
hideRalph: !!omgState.ralph,
|
|
1141
1200
|
hideAutopilot: !!omgState.autopilot,
|
|
@@ -1181,6 +1240,10 @@ async function main() {
|
|
|
1181
1240
|
if (bgEl) els.push(bgEl);
|
|
1182
1241
|
}
|
|
1183
1242
|
|
|
1243
|
+
const verificationStateDir = join(cwd, ".omg", "state");
|
|
1244
|
+
const verificationState = readBackgroundVerificationState(verificationStateDir);
|
|
1245
|
+
els.push(renderVerificationStatus(verificationState));
|
|
1246
|
+
|
|
1184
1247
|
// Model name
|
|
1185
1248
|
if (cfg.elements.model !== false && model && model !== "?") {
|
|
1186
1249
|
els.push(dim(model));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trac3er/oh-my-god",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.9",
|
|
4
4
|
"description": "OMG (Oh My God) — Multi-agent orchestration, evidence-backed verification, and durable session state for Claude Code, Codex, and supported agent hosts",
|
|
5
5
|
"main": "OMG-setup.sh",
|
|
6
6
|
"scripts": {
|
package/plugins/core/plugin.json
CHANGED
|
@@ -10,7 +10,11 @@ import urllib.request
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
OSV_BATCH_URL = "https://api.osv.dev/v1/querybatch"
|
|
13
|
+
KEV_URL = "https://www.cisa.gov/sites/default/files/feeds/known_exploited_vulnerabilities.json"
|
|
14
|
+
EPSS_URL_TEMPLATE = "https://api.first.org/data/v1/epss?cve={cve_id}"
|
|
13
15
|
CACHE_REL_PATH = Path(".omg") / "state" / "cve-cache.json"
|
|
16
|
+
KEV_CACHE_REL_PATH = Path(".omg") / "state" / "kev-cache.json"
|
|
17
|
+
EPSS_CACHE_REL_PATH = Path(".omg") / "state" / "epss-cache.json"
|
|
14
18
|
CACHE_TTL_HOURS = 24
|
|
15
19
|
|
|
16
20
|
|
|
@@ -72,6 +76,93 @@ def scan_for_cves(dependency_list: list[dict[str, str]], project_dir: str = ".")
|
|
|
72
76
|
return scan_result
|
|
73
77
|
|
|
74
78
|
|
|
79
|
+
def enrich_with_kev(finding: dict[str, Any], cache_dir: str) -> dict[str, Any]:
|
|
80
|
+
result = dict(finding)
|
|
81
|
+
if not _dep_health_enabled():
|
|
82
|
+
result["kev_listed"] = False
|
|
83
|
+
return result
|
|
84
|
+
|
|
85
|
+
cve_id = str(finding.get("id", "")).strip()
|
|
86
|
+
if not cve_id:
|
|
87
|
+
result["kev_listed"] = False
|
|
88
|
+
return result
|
|
89
|
+
|
|
90
|
+
cache_path = Path(cache_dir) / KEV_CACHE_REL_PATH
|
|
91
|
+
cached = _load_cache(cache_path)
|
|
92
|
+
|
|
93
|
+
if cached and _is_cache_fresh(cached.get("fetched_at")):
|
|
94
|
+
result["kev_listed"] = cve_id in cached.get("cve_ids", [])
|
|
95
|
+
return result
|
|
96
|
+
|
|
97
|
+
try:
|
|
98
|
+
kev_data = _fetch_kev_catalog()
|
|
99
|
+
kev_ids = [v.get("cveID", "") for v in kev_data.get("vulnerabilities", [])]
|
|
100
|
+
_save_cache(cache_path, {
|
|
101
|
+
"fetched_at": datetime.now(timezone.utc).isoformat(),
|
|
102
|
+
"cve_ids": kev_ids,
|
|
103
|
+
})
|
|
104
|
+
result["kev_listed"] = cve_id in kev_ids
|
|
105
|
+
except (urllib.error.URLError, OSError, json.JSONDecodeError):
|
|
106
|
+
if cached:
|
|
107
|
+
result["kev_listed"] = cve_id in cached.get("cve_ids", [])
|
|
108
|
+
else:
|
|
109
|
+
result["kev_listed"] = False
|
|
110
|
+
return result
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def enrich_with_epss(finding: dict[str, Any], cache_dir: str) -> dict[str, Any]:
|
|
114
|
+
result = dict(finding)
|
|
115
|
+
if not _dep_health_enabled():
|
|
116
|
+
result["epss_score"] = None
|
|
117
|
+
return result
|
|
118
|
+
|
|
119
|
+
cve_id = str(finding.get("id", "")).strip()
|
|
120
|
+
if not cve_id:
|
|
121
|
+
result["epss_score"] = None
|
|
122
|
+
return result
|
|
123
|
+
|
|
124
|
+
cache_path = Path(cache_dir) / EPSS_CACHE_REL_PATH
|
|
125
|
+
cached = _load_cache(cache_path) or {}
|
|
126
|
+
entries = cached.get("entries", {})
|
|
127
|
+
|
|
128
|
+
entry = entries.get(cve_id)
|
|
129
|
+
if entry and _is_cache_fresh(entry.get("fetched_at")):
|
|
130
|
+
result["epss_score"] = entry.get("epss")
|
|
131
|
+
return result
|
|
132
|
+
|
|
133
|
+
try:
|
|
134
|
+
epss_data = _fetch_epss_score(cve_id)
|
|
135
|
+
data_list = epss_data.get("data", [])
|
|
136
|
+
score = float(data_list[0].get("epss", 0)) if data_list else None
|
|
137
|
+
entries[cve_id] = {
|
|
138
|
+
"epss": score,
|
|
139
|
+
"fetched_at": datetime.now(timezone.utc).isoformat(),
|
|
140
|
+
}
|
|
141
|
+
_save_cache(cache_path, {"entries": entries})
|
|
142
|
+
result["epss_score"] = score
|
|
143
|
+
except (urllib.error.URLError, OSError, json.JSONDecodeError, ValueError, TypeError):
|
|
144
|
+
if entry:
|
|
145
|
+
result["epss_score"] = entry.get("epss")
|
|
146
|
+
else:
|
|
147
|
+
result["epss_score"] = None
|
|
148
|
+
return result
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def _fetch_kev_catalog() -> dict[str, Any]:
|
|
152
|
+
request = urllib.request.Request(KEV_URL, headers={"Accept": "application/json"})
|
|
153
|
+
with urllib.request.urlopen(request, timeout=15) as response:
|
|
154
|
+
body = response.read().decode("utf-8")
|
|
155
|
+
return json.loads(body)
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
def _fetch_epss_score(cve_id: str) -> dict[str, Any]:
|
|
159
|
+
url = EPSS_URL_TEMPLATE.format(cve_id=cve_id)
|
|
160
|
+
request = urllib.request.Request(url, headers={"Accept": "application/json"})
|
|
161
|
+
with urllib.request.urlopen(request, timeout=15) as response:
|
|
162
|
+
body = response.read().decode("utf-8")
|
|
163
|
+
return json.loads(body)
|
|
164
|
+
|
|
165
|
+
|
|
75
166
|
def _query_osv_batch(dependency_list: list[dict[str, str]]) -> dict[str, Any]:
|
|
76
167
|
payload = {
|
|
77
168
|
"queries": [
|
|
@@ -3,6 +3,8 @@ import re
|
|
|
3
3
|
from pathlib import Path
|
|
4
4
|
from typing import Any
|
|
5
5
|
|
|
6
|
+
from plugins.dephealth.cve_scanner import enrich_with_kev, enrich_with_epss
|
|
7
|
+
|
|
6
8
|
|
|
7
9
|
_CRITICAL_PATTERN = re.compile(r"\bcritical\b", re.IGNORECASE)
|
|
8
10
|
_HIGH_PATTERN = re.compile(r"\bhigh\b", re.IGNORECASE)
|
|
@@ -33,6 +35,9 @@ def analyze_reachability(cve_result: dict[str, Any], project_dir: str) -> dict[s
|
|
|
33
35
|
risk_level = _classify_risk(reachability, summary)
|
|
34
36
|
recommendation = _build_recommendation(package, fixed_version, reachability)
|
|
35
37
|
|
|
38
|
+
kev_enriched = enrich_with_kev({"id": cve_id}, project_dir)
|
|
39
|
+
epss_enriched = enrich_with_epss({"id": cve_id}, project_dir)
|
|
40
|
+
|
|
36
41
|
return {
|
|
37
42
|
"package": package,
|
|
38
43
|
"cve_id": cve_id,
|
|
@@ -40,6 +45,8 @@ def analyze_reachability(cve_result: dict[str, Any], project_dir: str) -> dict[s
|
|
|
40
45
|
"import_locations": sorted(imported_files),
|
|
41
46
|
"risk_level": risk_level,
|
|
42
47
|
"recommendation": recommendation,
|
|
48
|
+
"kev_listed": kev_enriched.get("kev_listed", False),
|
|
49
|
+
"epss_score": epss_enriched.get("epss_score"),
|
|
43
50
|
}
|
|
44
51
|
|
|
45
52
|
|
package/pyproject.toml
CHANGED
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "oh-my-god"
|
|
7
|
-
version = "2.0.
|
|
7
|
+
version = "2.0.9"
|
|
8
8
|
description = "OMG (Oh My God) — Multi-agent orchestration, evidence-backed verification, and durable session state for Claude Code, Codex, and supported agent hosts"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -43,7 +43,9 @@
|
|
|
43
43
|
"type": "string",
|
|
44
44
|
"enum": [
|
|
45
45
|
"claude",
|
|
46
|
-
"codex"
|
|
46
|
+
"codex",
|
|
47
|
+
"gemini",
|
|
48
|
+
"kimi"
|
|
47
49
|
]
|
|
48
50
|
},
|
|
49
51
|
"minItems": 1
|
|
@@ -281,6 +283,86 @@
|
|
|
281
283
|
}
|
|
282
284
|
},
|
|
283
285
|
"additionalProperties": true
|
|
286
|
+
},
|
|
287
|
+
"gemini": {
|
|
288
|
+
"type": "object",
|
|
289
|
+
"required": [
|
|
290
|
+
"compilation_targets",
|
|
291
|
+
"mcp",
|
|
292
|
+
"skills",
|
|
293
|
+
"automations"
|
|
294
|
+
],
|
|
295
|
+
"properties": {
|
|
296
|
+
"compilation_targets": {
|
|
297
|
+
"type": "array",
|
|
298
|
+
"minItems": 1,
|
|
299
|
+
"items": {
|
|
300
|
+
"type": "string"
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
"mcp": {
|
|
304
|
+
"type": "array",
|
|
305
|
+
"minItems": 1,
|
|
306
|
+
"items": {
|
|
307
|
+
"type": "string"
|
|
308
|
+
}
|
|
309
|
+
},
|
|
310
|
+
"skills": {
|
|
311
|
+
"type": "array",
|
|
312
|
+
"minItems": 1,
|
|
313
|
+
"items": {
|
|
314
|
+
"type": "string"
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
"automations": {
|
|
318
|
+
"type": "array",
|
|
319
|
+
"minItems": 1,
|
|
320
|
+
"items": {
|
|
321
|
+
"type": "string"
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
},
|
|
325
|
+
"additionalProperties": true
|
|
326
|
+
},
|
|
327
|
+
"kimi": {
|
|
328
|
+
"type": "object",
|
|
329
|
+
"required": [
|
|
330
|
+
"compilation_targets",
|
|
331
|
+
"mcp",
|
|
332
|
+
"skills",
|
|
333
|
+
"automations"
|
|
334
|
+
],
|
|
335
|
+
"properties": {
|
|
336
|
+
"compilation_targets": {
|
|
337
|
+
"type": "array",
|
|
338
|
+
"minItems": 1,
|
|
339
|
+
"items": {
|
|
340
|
+
"type": "string"
|
|
341
|
+
}
|
|
342
|
+
},
|
|
343
|
+
"mcp": {
|
|
344
|
+
"type": "array",
|
|
345
|
+
"minItems": 1,
|
|
346
|
+
"items": {
|
|
347
|
+
"type": "string"
|
|
348
|
+
}
|
|
349
|
+
},
|
|
350
|
+
"skills": {
|
|
351
|
+
"type": "array",
|
|
352
|
+
"minItems": 1,
|
|
353
|
+
"items": {
|
|
354
|
+
"type": "string"
|
|
355
|
+
}
|
|
356
|
+
},
|
|
357
|
+
"automations": {
|
|
358
|
+
"type": "array",
|
|
359
|
+
"minItems": 1,
|
|
360
|
+
"items": {
|
|
361
|
+
"type": "string"
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
},
|
|
365
|
+
"additionalProperties": true
|
|
284
366
|
}
|
|
285
367
|
},
|
|
286
368
|
"additionalProperties": true
|
package/runtime/adoption.py
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
4
|
import json
|
|
5
|
+
import importlib
|
|
5
6
|
from pathlib import Path
|
|
6
|
-
from typing import Any
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
CANONICAL_BRAND = "OMG"
|
|
@@ -11,10 +11,12 @@ CANONICAL_REPO_URL = "https://github.com/trac3er00/OMG"
|
|
|
11
11
|
CANONICAL_PACKAGE_NAME = "@trac3er/oh-my-god"
|
|
12
12
|
CANONICAL_PLUGIN_ID = "omg"
|
|
13
13
|
CANONICAL_MARKETPLACE_ID = "omg"
|
|
14
|
-
CANONICAL_VERSION = "2.0.
|
|
14
|
+
CANONICAL_VERSION = "2.0.9"
|
|
15
15
|
|
|
16
16
|
VALID_ADOPTION_MODES = ("omg-only", "coexist")
|
|
17
17
|
VALID_PRESETS = ("safe", "balanced", "interop", "labs")
|
|
18
|
+
CANONICAL_MODE_NAMES = ("chill", "focused", "exploratory")
|
|
19
|
+
"""Cross-surface user-facing mode names reserved for the shared mode system."""
|
|
18
20
|
|
|
19
21
|
MANAGED_PRESET_FLAGS = (
|
|
20
22
|
"SETUP",
|
|
@@ -91,6 +93,12 @@ def get_preset_features(preset: str | None) -> dict[str, bool]:
|
|
|
91
93
|
return dict(PRESET_FEATURES[resolved])
|
|
92
94
|
|
|
93
95
|
|
|
96
|
+
def get_mode_profile(mode: str) -> dict[str, object]:
|
|
97
|
+
runtime_profile = importlib.import_module("runtime.runtime_profile")
|
|
98
|
+
loader = getattr(runtime_profile, "load_canonical_mode_profile")
|
|
99
|
+
return loader(mode)
|
|
100
|
+
|
|
101
|
+
|
|
94
102
|
def _resolve_claude_dir(base_dir: Path) -> Path:
|
|
95
103
|
nested = base_dir / ".claude"
|
|
96
104
|
if nested.exists():
|
|
@@ -180,7 +188,7 @@ def build_adoption_report(
|
|
|
180
188
|
requested_mode: str | None = None,
|
|
181
189
|
preset: str | None = None,
|
|
182
190
|
adopt: str = "auto",
|
|
183
|
-
) -> dict[str,
|
|
191
|
+
) -> dict[str, object]:
|
|
184
192
|
detected_ecosystems = detect_ecosystems(project_dir) if adopt == "auto" else []
|
|
185
193
|
recommended_mode = recommend_mode(detected_ecosystems)
|
|
186
194
|
selected_mode = requested_mode if requested_mode in VALID_ADOPTION_MODES else recommended_mode
|
|
@@ -204,9 +212,9 @@ def build_adoption_report(
|
|
|
204
212
|
}
|
|
205
213
|
|
|
206
214
|
|
|
207
|
-
def write_adoption_report(project_dir: str | Path, report: dict[str,
|
|
215
|
+
def write_adoption_report(project_dir: str | Path, report: dict[str, object]) -> str:
|
|
208
216
|
state_dir = Path(project_dir) / ".omg" / "state"
|
|
209
217
|
state_dir.mkdir(parents=True, exist_ok=True)
|
|
210
218
|
report_path = state_dir / "adoption-report.json"
|
|
211
|
-
report_path.write_text(json.dumps(report, indent=2, ensure_ascii=True) + "\n", encoding="utf-8")
|
|
219
|
+
_ = report_path.write_text(json.dumps(report, indent=2, ensure_ascii=True) + "\n", encoding="utf-8")
|
|
212
220
|
return str(report_path)
|