@agentikos/omega-os 0.19.22 → 0.19.24

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.
@@ -131,6 +131,25 @@ _CATALOG: list[CliSpec] = [
131
131
  install_cmd=["npm", "install", "-g", "@continuedev/cli"],
132
132
  description="Continue.dev CLI — multi-provider with config.json",
133
133
  ),
134
+ # v0.19.23 — local LLM runtimes (no API key needed, free local inference).
135
+ CliSpec(
136
+ id="ollama", label="Ollama (local model runtime)",
137
+ bin_name="ollama",
138
+ install_cmd=[], # filled at runtime — curl|sh installer
139
+ description="Local LLM runtime — pull + run Llama/Mistral/Qwen/etc.",
140
+ ),
141
+ CliSpec(
142
+ id="lm_studio", label="LM Studio CLI (local)",
143
+ bin_name="lms",
144
+ install_cmd=["npx", "-y", "@lmstudio/cli", "install"],
145
+ description="LM Studio command-line manager (`lms`) for local models",
146
+ ),
147
+ CliSpec(
148
+ id="gh_copilot", label="GitHub Copilot Chat (via gh extension)",
149
+ bin_name="gh", # we extend an existing binary
150
+ install_cmd=["gh", "extension", "install", "github/gh-copilot"],
151
+ description="GitHub Copilot Chat as a `gh copilot` subcommand",
152
+ ),
134
153
  ]
135
154
 
136
155
 
@@ -545,6 +545,13 @@ for entry in missing:
545
545
  elif "npm_global" in install and shutil.which("npm"):
546
546
  rc, out = _run(["npm", "install", "-g", "--silent", install["npm_global"]])
547
547
  attempt = f"npm install -g {install['npm_global']}"
548
+ elif "uv_tool" in install and (shutil.which("uv") or os.path.isfile(
549
+ os.path.expanduser("~/.local/bin/uv"))):
550
+ # uv-managed Python tools — installs to ~/.local/share/uv/tools
551
+ # and links to ~/.local/bin (which step_system_deps put on PATH)
552
+ uv_bin = shutil.which("uv") or os.path.expanduser("~/.local/bin/uv")
553
+ rc, out = _run([uv_bin, "tool", "install", "--quiet", install["uv_tool"]])
554
+ attempt = f"uv tool install {install['uv_tool']}"
548
555
  elif "curl" in install:
549
556
  # curl|bash installer — last resort
550
557
  rc, out = _run(["bash", "-c", f"curl -fsSL {install['curl']} | bash"])
@@ -557,6 +564,15 @@ for entry in missing:
557
564
  if shutil.which(binary):
558
565
  print(f" ok {cli_id:<14} (installed via {attempt})")
559
566
  installed_now.append(cli_id)
567
+ # Optional post-install command (e.g. `scrapling install`
568
+ # downloads its browser deps after pip install).
569
+ post = entry.get("post_install") or []
570
+ if post and shutil.which(post[0]):
571
+ rc2, _ = _run(post, timeout=600)
572
+ if rc2 == 0:
573
+ print(f" post-install: {' '.join(post)} ok")
574
+ else:
575
+ print(f" post-install: {' '.join(post)} rc={rc2} (non-fatal)")
560
576
  else:
561
577
  print(f" fail {cli_id}: {attempt} returned rc={rc}")
562
578
  failed_now.append(cli_id)
@@ -188,7 +188,7 @@ from omega_engine.genesis import (
188
188
  )
189
189
  from omega_engine import plan as plan_v7
190
190
 
191
- __version__ = "0.19.22"
191
+ __version__ = "0.19.24"
192
192
 
193
193
  __all__ = [
194
194
  "__version__",
@@ -2965,6 +2965,132 @@ def _set_active_provider(provider_id: str) -> None:
2965
2965
  p.write_text(provider_id.strip() + "\n")
2966
2966
 
2967
2967
 
2968
+ def cmd_scrape(args: argparse.Namespace) -> int:
2969
+ """`omega scrape <url> [--engine cloak|scrapling] [--out file]` — scraper.
2970
+
2971
+ Two engines available since v0.19.24:
2972
+ * ``cloak`` (default) — CloakBrowser, heavy stealth Chromium, 58
2973
+ C++ patches, passes Cloudflare/Turnstile/FingerprintJS. Slow
2974
+ but invincible.
2975
+ * ``scrapling`` — D4Vinci/Scrapling, HTTP-first with optional
2976
+ browser, adaptive element tracking, concurrent crawl with
2977
+ pause/resume. Fast for non-protected sites.
2978
+
2979
+ Output: cleaned text to stdout (or --out FILE). Wraps both engines
2980
+ behind a consistent CLI so any LLM (Claude/Gemini/Codex/OpenCode/
2981
+ Aider) can `omega scrape <url>` via Bash without caring which
2982
+ Python library is doing the work.
2983
+
2984
+ Examples:
2985
+ omega scrape https://example.com # CloakBrowser
2986
+ omega scrape https://example.com --engine scrapling # Scrapling
2987
+ omega scrape https://news.ycombinator.com --engine scrapling --css ".titleline"
2988
+ """
2989
+ import shutil
2990
+ import subprocess
2991
+ if not args.url:
2992
+ print("usage: omega scrape <url> "
2993
+ "[--engine cloak|scrapling] [--out FILE] [--humanize] "
2994
+ "[--proxy URL] [--css SELECTOR]")
2995
+ return 2
2996
+ engine = getattr(args, "engine", None) or "cloak"
2997
+ if engine == "scrapling":
2998
+ # Scrapling path — uses its own CLI `scrapling extract`.
2999
+ if not shutil.which("scrapling"):
3000
+ print(" scrapling not installed — "
3001
+ "run `omega tool install scrapling` or "
3002
+ "`uv tool install 'scrapling[fetchers]' && scrapling install`")
3003
+ return 2
3004
+ out_file = getattr(args, "out", None)
3005
+ # Scrapling writes to a file (it doesn't print to stdout by
3006
+ # default). If user didn't specify --out, use a tmpfile and
3007
+ # cat it after.
3008
+ import tempfile
3009
+ from pathlib import Path
3010
+ tmp_out = out_file or tempfile.mktemp(suffix=".md")
3011
+ scrapling_cmd = ["scrapling", "extract",
3012
+ "stealthy-fetch" if getattr(args, "humanize", False)
3013
+ else "fetch",
3014
+ args.url, tmp_out]
3015
+ if getattr(args, "css", None):
3016
+ scrapling_cmd += ["--css-selector", args.css]
3017
+ try:
3018
+ proc = subprocess.run(scrapling_cmd, capture_output=True,
3019
+ text=True, timeout=120)
3020
+ except subprocess.TimeoutExpired:
3021
+ print(" scrapling timed out after 120s")
3022
+ return 2
3023
+ if proc.returncode != 0:
3024
+ print(f" scrapling error: {proc.stderr[:400]}")
3025
+ return proc.returncode
3026
+ if not out_file:
3027
+ try:
3028
+ print(Path(tmp_out).read_text())
3029
+ Path(tmp_out).unlink(missing_ok=True)
3030
+ except OSError as exc:
3031
+ print(f" read scrapling output failed: {exc}")
3032
+ return 2
3033
+ else:
3034
+ print(f" wrote → {out_file}")
3035
+ return 0
3036
+ # Default engine = CloakBrowser (kept verbatim from v0.19.23).
3037
+ # CloakBrowser is installed as a uv tool (`cloakbrowser`) but we need
3038
+ # to drive it from Python — the canonical path is `python -m
3039
+ # cloakbrowser` after `pip install cloakbrowser`, OR we invoke the
3040
+ # uv-tool-installed Python directly. Try shutil.which("cloakbrowser")
3041
+ # first; if absent, fall back to running through the installer venv.
3042
+ runner = None
3043
+ if shutil.which("cloakbrowser"):
3044
+ # Direct CLI is mostly for binary management (install/info/update).
3045
+ # For SCRAPING we still need our Python wrapper.
3046
+ pass
3047
+ # Inline Python wrapper — no separate script file, no version drift.
3048
+ py_code = (
3049
+ "import sys, asyncio\n"
3050
+ "try:\n"
3051
+ " from cloakbrowser import launch_async\n"
3052
+ "except ImportError:\n"
3053
+ " sys.stderr.write('cloakbrowser not importable — install with: "
3054
+ "uv tool install cloakbrowser\\n'); sys.exit(2)\n"
3055
+ "URL = sys.argv[1]\n"
3056
+ "HUMANIZE = '--humanize' in sys.argv\n"
3057
+ "PROXY = None\n"
3058
+ "if '--proxy' in sys.argv:\n"
3059
+ " PROXY = sys.argv[sys.argv.index('--proxy') + 1]\n"
3060
+ "async def main():\n"
3061
+ " kwargs = {'humanize': HUMANIZE}\n"
3062
+ " if PROXY:\n"
3063
+ " kwargs['proxy'] = PROXY\n"
3064
+ " browser = await launch_async(**kwargs)\n"
3065
+ " page = await browser.new_page()\n"
3066
+ " await page.goto(URL, wait_until='networkidle')\n"
3067
+ " text = await page.evaluate(\"document.body.innerText\")\n"
3068
+ " await browser.close()\n"
3069
+ " print(text)\n"
3070
+ "asyncio.run(main())\n"
3071
+ )
3072
+ cmd = ["python3", "-c", py_code, args.url]
3073
+ if getattr(args, "humanize", False):
3074
+ cmd.append("--humanize")
3075
+ if getattr(args, "proxy", None):
3076
+ cmd += ["--proxy", args.proxy]
3077
+ try:
3078
+ proc = subprocess.run(cmd, capture_output=True, text=True, timeout=120)
3079
+ except subprocess.TimeoutExpired:
3080
+ print(" cloakbrowser timed out after 120s")
3081
+ return 2
3082
+ out_target = getattr(args, "out", None)
3083
+ if out_target:
3084
+ from pathlib import Path
3085
+ Path(out_target).write_text(proc.stdout)
3086
+ print(f" wrote {len(proc.stdout)} bytes → {out_target}")
3087
+ else:
3088
+ print(proc.stdout)
3089
+ if proc.returncode != 0:
3090
+ print(f" cloakbrowser stderr: {proc.stderr[:400]}", file=__import__('sys').stderr)
3091
+ return proc.returncode
3092
+
3093
+
2968
3094
  def cmd_switch(args: argparse.Namespace) -> int:
2969
3095
  """`omega switch <provider>` — hot-swap the LLM provider for new chats.
2970
3096
 
@@ -4109,6 +4235,30 @@ def _build_parser() -> argparse.ArgumentParser:
4109
4235
  p_sw.add_argument("provider", nargs="?", default=None,
4110
4236
  help="provider id (omit to print current + available)")
4111
4237
  p_sw.set_defaults(fn=cmd_switch)
4238
+
4239
+ # `omega scrape <url>` — official OmegaOS web scraper (CloakBrowser
4240
+ # default, Scrapling optional). Both engines pre-installed at step 40
4241
+ # when their catalog entry is `recommended: true`.
4242
+ p_sc = sub.add_parser(
4243
+ "scrape",
4244
+ help="scrape a URL — CloakBrowser (default, stealth) or Scrapling "
4245
+ "(--engine scrapling, fast). Output: stdout or --out FILE",
4246
+ )
4247
+ p_sc.add_argument("url", nargs="?", default=None,
4248
+ help="URL to fetch")
4249
+ p_sc.add_argument("--engine", default="cloak",
4250
+ choices=["cloak", "scrapling"],
4251
+ help="which scraper to use (default: cloak = CloakBrowser)")
4252
+ p_sc.add_argument("--out", default=None,
4253
+ help="write result to file instead of stdout")
4254
+ p_sc.add_argument("--humanize", action="store_true",
4255
+ help="mouse curves + scroll patterns (cloak) "
4256
+ "or stealthy-fetch mode (scrapling)")
4257
+ p_sc.add_argument("--proxy", default=None,
4258
+ help="HTTP or SOCKS5 proxy (cloak engine only)")
4259
+ p_sc.add_argument("--css", default=None,
4260
+ help="CSS selector to scope output (scrapling engine only)")
4261
+ p_sc.set_defaults(fn=cmd_scrape)
4112
4262
  p_doc = sub.add_parser("doctor", help="validate the deployment")
4113
4263
  p_doc.add_argument("--json", action="store_true",
4114
4264
  help="emit a single JSON object instead of pretty text")
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "omega-engine"
3
- version = "0.19.22"
3
+ version = "0.19.24"
4
4
  description = "The Omega OS orchestration engine — event-sourced, verified-completion agent graphs."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -1 +1 @@
1
- 0.19.22
1
+ 0.19.24
@@ -64,6 +64,29 @@ native:
64
64
  secrets: []
65
65
  recommended: true
66
66
 
67
+ - id: cloakbrowser
68
+ name: CloakBrowser (official OmegaOS scraper — bypasses bot detection)
69
+ # PyPI package — installed into a uv tool so it's globally available
70
+ # as `cloakbrowser` + `python -m cloakbrowser`. ~200MB binary
71
+ # downloaded on first run (cached).
72
+ install: { uv_tool: "cloakbrowser" }
73
+ binary: cloakbrowser
74
+ secrets: []
75
+ recommended: true
76
+
77
+ - id: scrapling
78
+ name: Scrapling (optional fast scraper — HTTP-first, adaptive elements)
79
+ # Complementary to CloakBrowser. Scrapling shines for non-protected
80
+ # sites + multi-page crawls (concurrent + pause/resume + adaptive
81
+ # element tracking that survives page redesigns). CloakBrowser stays
82
+ # the default for hard bot-walls; Scrapling for everything else.
83
+ # `omega scrape --engine scrapling` selects it explicitly.
84
+ install: { uv_tool: "scrapling[fetchers]" }
85
+ binary: scrapling
86
+ secrets: []
87
+ recommended: false
88
+ post_install: ["scrapling", "install"] # downloads browser deps once
89
+
67
90
  # --- 2. Printing Press CLIs --------------------------------------------
68
91
  # Installed via `npx -y @mvanhorn/printing-press-library install <name>`.
69
92
  # Each ships with a local SQLite mirror + Claude Code skill.
@@ -0,0 +1,169 @@
1
+ # Omega OS — LLM provider catalog (v0.19.23+)
2
+ #
3
+ # Maps the operator's intent ("I want to talk to GLM") to a concrete
4
+ # (cli + provider_config) pair. Most providers don't ship their own CLI —
5
+ # they're configurable backends inside OpenCode / Continue.dev / Aider.
6
+ #
7
+ # Used by:
8
+ # * `omega switch <provider>` — looks up the cli + writes the
9
+ # provider-active marker.
10
+ # * step_provider_configs — drops templated config files for every
11
+ # supported provider with secret refs from the vault.
12
+ # * `omega account login --provider <id>` — guides the auth flow per
13
+ # provider.
14
+ #
15
+ # Secrets are vault refs, never literal. Templated config files end up at
16
+ # the LLM CLI's expected path on first launch.
17
+
18
+ version: 1
19
+
20
+ providers:
21
+ # -- Anthropic family --
22
+ - id: anthropic
23
+ label: "Anthropic Claude (API key)"
24
+ cli: claude_code
25
+ auth_kind: api_key
26
+ secret_refs: [ANTHROPIC_API_KEY]
27
+ notes: |
28
+ Direct Anthropic API access. Pay-per-token. For OmegaOS's own
29
+ L3-L5 stack we prefer Claude Max OAuth (no cost) — this entry is
30
+ for L2 / Hermès style "use my paid Anthropic budget" scenarios.
31
+
32
+ - id: chatgpt_subscription
33
+ label: "ChatGPT Subscription (OpenAI Codex)"
34
+ cli: codex
35
+ auth_kind: oauth
36
+ secret_refs: []
37
+ notes: |
38
+ Codex CLI uses the same OAuth as your ChatGPT Plus/Team sub —
39
+ no separate API key needed. `codex login` opens the browser.
40
+
41
+ # -- OpenAI family --
42
+ - id: openai
43
+ label: "OpenAI (API key — gpt-4o, gpt-5, o3-pro)"
44
+ cli: codex # codex IS OpenAI's official agentic CLI
45
+ auth_kind: api_key
46
+ secret_refs: [OPENAI_API_KEY]
47
+ notes: |
48
+ Pay-per-token OpenAI API. Use this when you want gpt-5/o3-pro
49
+ without the ChatGPT subscription cap.
50
+
51
+ - id: openai_compatible
52
+ label: "OpenAI API-Compatible endpoint (custom)"
53
+ cli: opencode # OpenCode's `provider: openai_compatible`
54
+ auth_kind: api_key
55
+ secret_refs: [OPENAI_API_BASE, OPENAI_API_KEY]
56
+ notes: |
57
+ For LM Studio, vLLM, llama.cpp's `/v1` server, Together.ai's
58
+ OpenAI-shape endpoint, etc.
59
+
60
+ # -- Google --
61
+ - id: google_ai
62
+ label: "Google AI Studio (Gemini)"
63
+ cli: gemini_cli
64
+ auth_kind: api_key
65
+ secret_refs: [GOOGLE_API_KEY]
66
+ notes: |
67
+ Direct Gemini API via the official `gemini` CLI. Free tier
68
+ generous; paid tier for higher RPM.
69
+
70
+ # -- China --
71
+ - id: glm
72
+ label: "Zhipu GLM-4.5 / GLM-4.6 (via OpenCode)"
73
+ cli: opencode
74
+ auth_kind: api_key
75
+ secret_refs: [GLM_API_KEY]
76
+ notes: |
77
+ Zhipu AI's GLM models — open weights for the smaller variants,
78
+ hosted API for GLM-4.6. OpenCode provider `zhipu`.
79
+
80
+ - id: deepseek
81
+ label: "DeepSeek V3 / R1 (via OpenCode)"
82
+ cli: opencode
83
+ auth_kind: api_key
84
+ secret_refs: [DEEPSEEK_API_KEY]
85
+ notes: |
86
+ DeepSeek's V3 + R1 reasoning. Excellent price/perf. OpenCode
87
+ provider `deepseek`.
88
+
89
+ - id: qwen
90
+ label: "Qwen (Alibaba) — dedicated CLI"
91
+ cli: qwen_code
92
+ auth_kind: api_key
93
+ secret_refs: [DASHSCOPE_API_KEY]
94
+ notes: |
95
+ Qwen3-Coder via Alibaba's DashScope. Standalone `qwen` CLI.
96
+
97
+ # -- Local --
98
+ - id: ollama
99
+ label: "Ollama (local — Llama/Mistral/Qwen/DeepSeek-Coder)"
100
+ cli: ollama
101
+ auth_kind: none
102
+ secret_refs: []
103
+ notes: |
104
+ Local model runtime. Free, private, runs offline. Pull a model
105
+ with `ollama pull llama3.3:70b` then `ollama run`.
106
+
107
+ - id: lm_studio
108
+ label: "LM Studio (local — GUI + CLI)"
109
+ cli: lm_studio
110
+ auth_kind: none
111
+ secret_refs: []
112
+ notes: |
113
+ LM Studio for desktop. Run any GGUF model locally. Exposes an
114
+ OpenAI-compatible `/v1` endpoint OpenCode can consume.
115
+
116
+ # -- Aggregators / Gateways --
117
+ - id: openrouter
118
+ label: "OpenRouter (300+ models, one API key)"
119
+ cli: opencode
120
+ auth_kind: api_key
121
+ secret_refs: [OPENROUTER_API_KEY]
122
+ notes: |
123
+ Route to any of 300+ models with one API key. OpenCode provider
124
+ `openrouter`. Per-call routing in config.
125
+
126
+ - id: vercel_ai_gateway
127
+ label: "Vercel AI Gateway (multi-provider)"
128
+ cli: opencode
129
+ auth_kind: api_key
130
+ secret_refs: [AI_GATEWAY_API_KEY]
131
+ notes: |
132
+ Vercel's hosted gateway proxies your traffic across providers
133
+ with usage caps + observability. OpenCode `provider: ai_gateway`.
134
+
135
+ # -- Hyperscalers --
136
+ - id: amazon_bedrock
137
+ label: "Amazon Bedrock (AWS)"
138
+ cli: opencode
139
+ auth_kind: aws
140
+ secret_refs: [AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION]
141
+ notes: |
142
+ AWS Bedrock — Claude, Llama, Mistral, Cohere, Stability through
143
+ AWS auth. OpenCode `provider: bedrock`.
144
+
145
+ # -- Other --
146
+ - id: mistral
147
+ label: "Mistral AI (API key)"
148
+ cli: opencode
149
+ auth_kind: api_key
150
+ secret_refs: [MISTRAL_API_KEY]
151
+ notes: |
152
+ Mistral-Large, Codestral, Pixtral. OpenCode `provider: mistral`.
153
+
154
+ - id: xai
155
+ label: "xAI Grok (Grok-2, Grok-Beta)"
156
+ cli: opencode
157
+ auth_kind: api_key
158
+ secret_refs: [XAI_API_KEY]
159
+ notes: |
160
+ Grok-2 / Grok-Beta via xAI's API. OpenCode `provider: xai`.
161
+
162
+ - id: github_copilot
163
+ label: "GitHub Copilot Chat (via gh extension)"
164
+ cli: gh_copilot
165
+ auth_kind: oauth
166
+ secret_refs: []
167
+ notes: |
168
+ Talk to Copilot from the terminal — `gh copilot suggest "..."` and
169
+ `gh copilot explain "..."`. Uses your GitHub OAuth.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentikos/omega-os",
3
- "version": "0.19.22",
3
+ "version": "0.19.24",
4
4
  "description": "Omega OS — installable agentic operating system with verified-completion orchestration. Event-sourced engine, 8-block rack, autonomous agents, MCP.",
5
5
  "bin": {
6
6
  "omega-os": "bin/omega-os.js"