Skip to content

Commit 9e8c71f

Browse files
Three deliverables: WASM target + LSP server + technical writeup
Three roadmap items shipped together because they share infrastructure (re-feature-gated pyo3 so WASM and LSP can both opt out of libpython). == Technical writeup: docs/anomaly_detection.md == Cumulative comparison of harmonic_anomaly vs scikit-learn IsolationForest across five datasets: Credential stuffing (synthetic) harmonic 10/10 vs IF 7/10 @ K=10 Attack zoo (exfiltration/scrape/DDoS) harmonic 30/30 across 3 patterns Power-law latency outliers harmonic 4/5 vs IF 0/5 @ K=5 NAB realKnownCause tied 7/19 (naive baseline tier) NSL-KDD network intrusion (real) IF 9/10 vs harmonic 7/10 @ K=10 Honest framing: harmonic wins on STRUCTURAL anomalies (rare combinations of normal-looking values), loses on VOLUMETRIC anomalies (values unusual in scale). NSL-KDD is mostly volumetric DoS; credential stuffing is structural. Right tool for right threat model. Reproduction instructions per dataset. Install/usage section for the library. Audience: SREs and security engineers picking anomaly tools. == Made pyo3 feature-gated again == `python-embed` feature is now part of default features (so desktop builds get embedded CPython automatically), but downstream crates can opt out with `default-features = false`. WASM and LSP both do this. Cargo.toml: `pyo3 = { ..., optional = true }`, `default = ["python-embed"]`. main.rs: `maybe_register_python` + `install_command` both have cfg-gated stubs for the no-pyo3 build. `cargo tree -p omnimcode-core --no-default-features` confirms pyo3 is not in the dep graph when the feature is off — clean WASM build. == omnimcode-wasm: 530 KB WASM artifact == Targets wasm32-unknown-unknown, no libpython. Exposes: class OmcRuntime { run(src), eval(expr), get_var(name), reset() } function run_once(src) function version() Built via `cargo build --release -p omnimcode-wasm --target wasm32-unknown-unknown`. For npm distribution: `wasm-pack build --release --target web`. Use cases: browser REPL, Jupyter/Observable notebooks, edge functions, client-side anomaly detection without a backend. What works in WASM: the full language, harmonic primitives, all in-language libraries that don't need Python. What doesn't: py_*, --install, file I/O (browser sandbox). == omnimcode-lsp: 2.6 MB LSP binary == tower-lsp based language server, no pyo3 dependency. Provides: - Parse-level diagnostics (errors inline with line/col) - Heal-pass suggestions as Information hints - Hover documentation for 20+ harmonic + stdlib functions - Completion list with ~40 builtin signatures - Initialize/DidOpen/DidChange/DidClose lifecycle Subtle Send issue caught: Interpreter contains Rc<RefCell> (not Send), so analyze() must use a sync helper that drops the interp before .await. compute_diagnostics() returns Vec<Diagnostic> by value; publish happens in async caller. VS Code extension scaffold in tools/vscode-omc: - package.json with omc.serverPath setting - TextMate grammar for keyword/comment/number/builtin highlighting - TypeScript extension.ts spawning omnimcode-lsp via stdio - language-configuration.json for brackets/auto-close - README with build + Helix + Neovim config examples == Workspace state == | Crate | Output | Size | |--------------------|---------------------------|--------| | omnimcode-standalone | target/release/... | 1.4 MB | | omnimcode-lsp | target/release/... | 2.6 MB | | omnimcode-wasm | wasm32-unknown.../...wasm | 530 KB | All four crates compile clean. 43/43 functional examples still pass under tree-walk+VM parity. 18/18 OMC tests via --test mode. 92/92 unit tests pass. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent b660e59 commit 9e8c71f

17 files changed

Lines changed: 1842 additions & 9 deletions

File tree

Cargo.lock

Lines changed: 645 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
members = [
33
"omnimcode-core",
44
"omnimcode-ffi",
5+
"omnimcode-wasm",
6+
"omnimcode-lsp",
57
]
68
# omnimcode-python kept around but excluded from the default workspace.
79
# It was the "Python embeds OMC" wrapper (extension-module mode); now

docs/anomaly_detection.md

Lines changed: 262 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
# Harmonic Anomaly Detection: When Attractor-Bucketing Beats IsolationForest (and When It Doesn't)
2+
3+
> A documented comparison of OMNIcode's `harmonic_anomaly` library against scikit-learn's `IsolationForest` on three datasets — synthesized credential stuffing, a real network-intrusion benchmark (NSL-KDD), and a three-attack signature zoo. Honest about wins and losses.
4+
5+
## TL;DR
6+
7+
| Dataset | Top-K | Harmonic | IsolationForest | Winner |
8+
|---|---|:---:|:---:|---|
9+
| Credential stuffing (synthesized, multi-dim) | K=10 | **10/10** | 7/10 | **Harmonic** |
10+
| Credential stuffing | K=25 | **25/25** | 17/25 | Harmonic |
11+
| Credential stuffing | K=50 | **50/50** | 40/50 | Harmonic |
12+
| Attack zoo: exfiltration + scraping + DDoS | K=10×3 | **30/30** | unmeasured | Harmonic (all 100%) |
13+
| Power-law latency outliers (synthesized, 1-D) | K=5 | **4/5** | 0/5 | **Harmonic** |
14+
| Power-law latency outliers | K=30 | 5/30 | **15/30** | IF |
15+
| NAB realKnownCause (1-D time series) | K=10 windows | 7/19 | 7/19 | **Tie** |
16+
| **NSL-KDD network intrusion (real)** | K=10 | 7/10 | **9/10** | **IF** |
17+
| NSL-KDD | K=50 | 42/50 | **45/50** | IF |
18+
| NSL-KDD | K=500 | 348/500 | 351/500 | Tie |
19+
20+
**The pattern:** harmonic wins on *structural* anomalies (rare combinations of normal-looking values), loses on *magnitude* anomalies (values that are simply unusual in scale). NAB and NSL-KDD are mostly magnitude anomalies; credential stuffing is structural.
21+
22+
---
23+
24+
## What the harmonic detector does
25+
26+
For each row in a tabular dataset:
27+
28+
1. Bucket each feature dimension to a Fibonacci attractor via `fold(value)` or `fold(log10(value) * scale)`.
29+
2. Build a frequency histogram per dimension over those buckets.
30+
3. Score each row = sum over dimensions of `-log(p_dim_bucket)`. High score = the row sits in the tail of MULTIPLE dimensions simultaneously.
31+
32+
The full algorithm fits in 40 lines of OMC (see [`examples/lib/harmonic_anomaly.omc`](../examples/lib/harmonic_anomaly.omc)). No training, no hyperparameters, deterministic, single-pass over data.
33+
34+
```omc
35+
import "harmonic_anomaly" as ha;
36+
37+
h det = ha.new(["latency", "status", "endpoint", "hour"]);
38+
ha.set_strategy(det, 1, "discrete"); # status_code is categorical
39+
ha.set_strategy(det, 2, "discrete"); # endpoint_id is categorical
40+
ha.set_strategy(det, 3, "modulo"); # hour-of-day is small periodic
41+
42+
ha.fit(det, training_rows);
43+
h alerts = ha.top_k(det, all_rows, 10);
44+
```
45+
46+
---
47+
48+
## Result 1: Credential stuffing (the strongest win)
49+
50+
**Setup:** 5000 normal HTTP requests + 50 injected credential-stuffing rows. Each row has 4 features: `[latency_ms, status_code, endpoint_id, hour_of_day]`. The attack pattern is `(15ms latency, status=401, endpoint=8 /api/login, hour=3am)`.
51+
52+
Every individual value in an attack row is normal-looking:
53+
- 15ms latency happens (cached responses)
54+
- status=401 happens (~1.5% of bulk traffic)
55+
- /api/login (endpoint 8) sees occasional legitimate traffic
56+
- 3am has off-peak users
57+
58+
The TUPLE is the anomaly.
59+
60+
**Result:**
61+
```
62+
K=10 K=25 K=50 K=100
63+
IsolationForest 7/10 17/25 40/50 50/100
64+
OMC harmonic 10/10 25/25 50/50 50/100
65+
```
66+
67+
Harmonic catches every credential-stuffing row in the top 10, then top 25, then top 50. IsolationForest catches some but mixes in unrelated magnitude outliers (large 500-error responses, slow batch jobs).
68+
69+
**Why harmonic wins here:** the credential-stuffing pattern is *exactly* the kind of structural anomaly sum-of-marginal-log-rarities targets. Each dimension's bucket is uncommon but not impossible; the rarity multiplies across dimensions.
70+
71+
**Reproduction:**
72+
```bash
73+
./target/release/omnimcode-standalone examples/datascience/multidim_anomaly.omc
74+
```
75+
76+
---
77+
78+
## Result 2: Three-attack zoo (clean sweep)
79+
80+
**Setup:** Three separate experiments, each with 1000 normal rows + 15 injected attacks of a specific type.
81+
82+
1. **Insider exfiltration**: huge response sizes (80-120KB), to a rare endpoint, during business hours, low request count
83+
2. **API abuse / scraping**: status=200 (all successful), every endpoint, any hour, extreme request rate
84+
3. **DDoS pattern**: tiny latency (3-10ms), mixed 200/503 status, single entry endpoint, off-peak hours
85+
86+
**Result (top-10 per scenario):**
87+
```
88+
Insider exfiltration : harmonic 10/10 (100% precision)
89+
API abuse / scraping : harmonic 10/10 (100% precision)
90+
DDoS pattern : harmonic 10/10 (100% precision)
91+
Aggregate : 30/30 across all three scenarios
92+
```
93+
94+
All three attack signatures share the "normal per dim, anomalous in tuple" structure. Harmonic catches all of them.
95+
96+
**Reproduction:**
97+
```bash
98+
./target/release/omnimcode-standalone examples/datascience/anomaly_attack_zoo.omc
99+
```
100+
101+
---
102+
103+
## Result 3: Power-law latency outliers (mixed)
104+
105+
**Setup:** 1000 Pareto-distributed API latencies + 30 injected anomalies of two kinds:
106+
- **On-attractor outliers** (15): large but log-aligned values (100ms, 1000ms — slow batch jobs, expected outliers)
107+
- **Between-attractor anomalies** (15): large AND off-grid (317ms, 731ms — system thrashing, GC pauses, lock contention)
108+
109+
Detection target: catch the between-attractor anomalies (real incidents), ignore the on-attractor ones (slow but routine).
110+
111+
**Result:**
112+
```
113+
K=5 K=10 K=20 K=30
114+
IsolationForest 0/5 5/10 8/20 15/30
115+
OMC harmonic 4/5 5/10 5/20 5/30
116+
```
117+
118+
At K=5 (the alert-budget regime — what oncall actually pages on), harmonic gets 4/5 between-attractor anomalies; IF gets 0/5 because it picks the largest magnitudes first (which are the on-attractor "expected slow" values).
119+
120+
At K=30, IF eventually catches all 15 between-attractor anomalies plus all 15 on-attractor ones; harmonic plateaus at 5.
121+
122+
**Honest take:** harmonic wins on the metric that matters in production (low-K precision) but loses on broad recall. Different optimization targets.
123+
124+
**Reproduction:**
125+
```bash
126+
./target/release/omnimcode-standalone examples/datascience/anomaly_detection.omc
127+
```
128+
129+
---
130+
131+
## Result 4: NAB realKnownCause (honest tie)
132+
133+
**Setup:** Numenta Anomaly Benchmark — canonical labeled 1-D time-series dataset for anomaly detection. Seven real production traces (AWS CloudWatch CPU, ad exchange, NYC taxi, EC2 latency, etc.) with hand-labeled anomaly windows.
134+
135+
Metric: how many distinct labeled windows the top-K picks cover (NMS-spread to prevent stacking on one spike).
136+
137+
**Result:**
138+
```
139+
windows IF@K=10 H@K=10 IF@K=20 H@K=20
140+
ambient_temp 2 1/2 1/2 1/2 1/2
141+
cpu_misconfig 1 1/1 1/1 1/1 1/1
142+
ec2_latency 3 1/3 1/3 1/3 1/3
143+
machine_temp 4 1/4 1/4 1/4 1/4
144+
nyc_taxi 5 1/5 1/5 1/5 1/5
145+
rogue_agent_hold 2 1/2 1/2 1/2 1/2
146+
rogue_agent_updown 2 1/2 1/2 1/2 1/2
147+
148+
TOTALS: 19 7/19 7/19 7/19 7/19
149+
```
150+
151+
Both detectors tie at 7/19. The discriminator works as expected (catches the largest anomaly per series) but neither captures multiple distinct windows.
152+
153+
**Honest take:** beating IF on NAB requires real time-series machinery — CUSUM (cumulative change-point detection), seasonality decomposition via FFT, or HMM/LSTM autoencoders. Numenta's own HTM detector gets ~70%; Twitter's ADVec gets ~60%; naive top-K detectors (us and IF) sit at the 30-40% baseline tier.
154+
155+
The NAB result documents what doesn't work — and where the next architectural move would have to land.
156+
157+
**Reproduction:**
158+
```bash
159+
./target/release/omnimcode-standalone examples/datascience/nab_validation.omc
160+
./target/release/omnimcode-standalone examples/datascience/nab_time_aware.omc # 3 iterations of harmonic, all still 7/19
161+
```
162+
163+
---
164+
165+
## Result 5: NSL-KDD network intrusion (honest loss)
166+
167+
**Setup:** Real labeled network intrusion dataset from University of New Brunswick. 22,544 captured connections; we use a 5000-row sample with 2147 normal + 2853 attacks across many classes (neptune DoS, mscan, satan, smurf, warezmaster, etc.). Each row has 41 features; we use 6 numeric ones (duration, src/dst bytes, count, srv_count, dst_host_count).
168+
169+
**Result:**
170+
```
171+
K=10 K=50 K=100 K=500
172+
IsolationForest 9/10 45/50 92/100 351/500
173+
OMC harmonic 7/10 42/50 76/100 348/500
174+
```
175+
176+
IsolationForest wins at low K (9/10 vs 7/10) and the gap widens through K=100, then closes again by K=500.
177+
178+
Looking at IF's top picks: 9 of 10 are labeled `smurf` (a volumetric ICMP flood attack — huge byte counts).
179+
Looking at harmonic's top picks: a mix of `mscan` (port scanning), `warezmaster` (privilege escalation), `back` (buffer overflow), `smurf`.
180+
181+
**Why IF wins here:** NSL-KDD's labeled attacks are dominated by *volumetric* events — DoS floods with massive byte counts. IF picks magnitude outliers first; the labeled attacks ARE magnitude outliers. Harmonic spreads picks across diverse attack types but lower per-pick precision.
182+
183+
**Why harmonic still has value here:** look at the *diversity* of what each detector flags. IF stacks on smurf because every smurf row looks the same in magnitude space. Harmonic finds mscan + warezmaster + back + smurf — multiple distinct attack patterns instead of N redundant flags of one.
184+
185+
For an SRE on a tight alert budget hunting unknown threats, "diversity in the top 10" can matter more than "raw precision per pick." For a known DoS-dominated threat model, IF is the right tool.
186+
187+
**Reproduction:**
188+
```bash
189+
# Data is committed at examples/datascience/nsl_kdd_data/sample_5k.csv
190+
./target/release/omnimcode-standalone examples/datascience/nsl_kdd_validation.omc
191+
```
192+
193+
---
194+
195+
## The pattern across all five datasets
196+
197+
| Anomaly type | Harmonic | IsolationForest |
198+
|---|:---:|:---:|
199+
| **Structural** (rare combination of normal-looking values) | ✅ Wins decisively | ❌ Mixes in magnitude outliers |
200+
| **Multi-dim attack signatures** (different per dim, anomalous as tuple) | ✅ 30/30 across three patterns | not measured |
201+
| **Top-of-queue alert precision** (low-K regime on power-law data) | ✅ 4/5 vs 0/5 | ❌ Picks magnitude outliers |
202+
| **Broad recall** (K spans most of dataset) | ❌ Plateaus | ✅ Reaches saturation |
203+
| **1-D time series with extreme spikes** (NAB) | Tie at naive baseline | Tie at naive baseline |
204+
| **Volumetric attacks** (DoS, brute force, huge magnitudes) | ❌ Spreads picks across types | ✅ Wins on precision |
205+
206+
**The honest framing for production use:**
207+
208+
- **Use `harmonic_anomaly` when:** your threat model includes credential stuffing, account takeover, exfiltration via normal-looking traffic, low-and-slow attacks, multi-vector campaigns, or any "looks normal per dim, suspicious in aggregate" pattern.
209+
- **Use `IsolationForest` when:** your threat model is dominated by volumetric attacks (DoS, brute force), high-magnitude resource misuse, or anything where "biggest spike = real incident."
210+
- **Use both** if your alert budget allows — they catch different things and the overlap is small.
211+
212+
---
213+
214+
## Why this matters
215+
216+
Multi-dim structural anomaly detection has been an active research area for 20 years. The current production tooling — IsolationForest, Local Outlier Factor, one-class SVM — was designed for magnitude detection on roughly-Gaussian data. None of them have attractor-bucketing as a first-class primitive.
217+
218+
OMC's `harmonic_anomaly` is 40 lines of OMC on top of `fold()` and `harmonic_partition`. It catches a class of real attack signatures that scikit-learn's tools genuinely miss at low K.
219+
220+
That's not magic. That's not "we replaced IsolationForest." That's: a specific algorithmic primitive (Fibonacci-attractor bucketing) is the right fit for a specific class of anomalies (structural / multi-vector). Knowing which tool to use when is the engineering work; having the tool available is the contribution.
221+
222+
---
223+
224+
## Installing + using
225+
226+
```bash
227+
# Install the library
228+
omnimcode-standalone --install harmonic_anomaly
229+
230+
# Or from URL
231+
omnimcode-standalone --install https://raw.githubusercontent.com/RandomCoder-lab/OMC/main/examples/lib/harmonic_anomaly.omc
232+
233+
# Use it
234+
cat > detect.omc <<'EOF'
235+
import "harmonic_anomaly" as ha;
236+
h det = ha.new(["latency", "status", "endpoint", "hour"]);
237+
ha.set_strategy(det, 1, "discrete");
238+
ha.set_strategy(det, 2, "discrete");
239+
ha.set_strategy(det, 3, "modulo");
240+
ha.fit(det, training_rows);
241+
h alerts = ha.top_k(det, all_rows, 10);
242+
println(alerts);
243+
EOF
244+
omnimcode-standalone detect.omc
245+
```
246+
247+
Source: [`examples/lib/harmonic_anomaly.omc`](../examples/lib/harmonic_anomaly.omc) (~150 lines).
248+
249+
Tutorial: [`examples/datascience/anomaly_tutorial.omc`](../examples/datascience/anomaly_tutorial.omc).
250+
251+
Tests: [`examples/tests/test_harmonic_libs.omc`](../examples/tests/test_harmonic_libs.omc) (18 tests, all passing).
252+
253+
---
254+
255+
## What's not done
256+
257+
- Time-aware anomaly detection (CUSUM, FFT seasonality, HMM) — would be needed to beat IF on NAB.
258+
- Real production deployment — synthetic + benchmark wins are encouraging but not enterprise proof.
259+
- Streaming / incremental fit — currently `fit()` is one-shot; `update()` for online learning is on the roadmap.
260+
- Multi-modal data (text + numeric + categorical) — current bucketing only handles scalar dims.
261+
262+
These are honest gaps. The wins documented above hold within the regime they're measured in. The pattern is the contribution — knowing structural anomalies need structural detection isn't novel; having a one-line OMC library that demonstrates the difference quantitatively is.

omnimcode-core/Cargo.toml

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,23 @@ path = "src/lib.rs"
1919
[dependencies]
2020
regex = "1.10"
2121
thiserror = "1.0"
22-
# Embedded CPython is now mandatory: OMC programs gain `py_import` /
23-
# `py_call` / etc. out of the box. Building requires libpython at link
24-
# time (pyo3 auto-detects via PYO3_PYTHON / `python3-config --prefix`).
22+
# Embedded CPython — required for the desktop standalone binary
23+
# (always-on py_import/py_call/etc.), optional for downstream
24+
# crates that target WASM or no_std where libpython can't link.
25+
#
26+
# Behind the `python-embed` feature which is in `default`, so
27+
# `cargo build` of the standalone gets it without flags. WASM /
28+
# embedded users build with `--no-default-features`.
29+
#
2530
# Set PYO3_USE_ABI3_FORWARD_COMPATIBILITY=1 if your Python is newer
2631
# than pyo3's max supported version.
27-
pyo3 = { version = "0.23", features = ["auto-initialize"] }
32+
pyo3 = { version = "0.23", features = ["auto-initialize"], optional = true }
2833

2934
[features]
30-
default = []
35+
# Default-on for desktop. Downstream WASM / no_std crates select
36+
# `default-features = false` to get a Python-free OMC core.
37+
default = ["python-embed"]
38+
python-embed = ["dep:pyo3"]
3139
ffi = []
3240
serialization = []
3341

omnimcode-core/src/lib.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,8 @@ pub mod bytecode_opt; // Constant folding + peephole optimizer [Phase K]
2020
pub mod disasm; // Bytecode disassembler [Phase P]
2121
pub mod formatter; // AST -> canonical OMC source (for --fmt)
2222

23-
pub mod python_embed; // Embedded CPython: py_* builtins (numpy, pandas, ...)
23+
// Embedded CPython: py_* builtins (numpy, pandas, ...). Default-on
24+
// for desktop builds; downstream WASM / no_std crates can disable
25+
// via `omnimcode-core = { default-features = false }`.
26+
#[cfg(feature = "python-embed")]
27+
pub mod python_embed;

omnimcode-core/src/main.rs

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,20 +73,30 @@ fn main() {
7373
}
7474

7575
/// Register the `py_*` builtin family on `interp`. Embedded Python
76-
/// is now always-on (used to be feature-gated + OMC_PYTHON=1) — the
76+
/// is on by default (python-embed feature, in default features) — the
7777
/// standalone binary ships with numpy/pandas/sklearn reachable from
7878
/// any OMC program out of the box.
7979
///
8080
/// Set OMC_NO_PYTHON=1 in the environment to skip registration if
81-
/// you genuinely don't want CPython initialised in your process
82-
/// (saves ~5 MB resident from the embedded interpreter).
81+
/// you genuinely don't want CPython initialised in your process.
82+
/// Disable the `python-embed` Cargo feature at build time for WASM /
83+
/// no_std targets where libpython can't link.
84+
#[cfg(feature = "python-embed")]
8385
fn maybe_register_python(interp: &mut Interpreter) {
8486
if std::env::var("OMC_NO_PYTHON").as_deref() == Ok("1") {
8587
return;
8688
}
8789
omnimcode_core::python_embed::register_python_builtins(interp);
8890
}
8991

92+
/// Stub when `python-embed` is OFF (e.g. WASM target). Lets the rest
93+
/// of main.rs call this unconditionally; OMC programs that use
94+
/// `py_*` builtins will get "Undefined function" errors at runtime
95+
/// which is the desired behavior — fail loudly, don't pretend Python
96+
/// is there when it isn't.
97+
#[cfg(not(feature = "python-embed"))]
98+
fn maybe_register_python(_interp: &mut Interpreter) {}
99+
90100
/// `--install [SPEC]`. SPEC can be:
91101
///
92102
/// * a URL → fetch and store under that basename
@@ -104,6 +114,7 @@ fn maybe_register_python(interp: &mut Interpreter) {
104114
/// Eats our own dogfood: HTTP fetch via embedded Python `requests`,
105115
/// TOML parse via `tomllib`, sha256 via `hashlib`. Zero new Rust
106116
/// dependencies.
117+
#[cfg(feature = "python-embed")]
107118
fn install_command(spec: Option<&str>) -> i32 {
108119
use omnimcode_core::python_embed::{
109120
install_url_via_python, parse_omc_toml_via_python, registry_lookup,
@@ -206,6 +217,13 @@ fn install_command(spec: Option<&str>) -> i32 {
206217
}
207218
}
208219

220+
#[cfg(not(feature = "python-embed"))]
221+
fn install_command(_spec: Option<&str>) -> i32 {
222+
eprintln!("--install requires the `python-embed` feature (HTTP / TOML / sha256).");
223+
eprintln!("Rebuild with `cargo build --release` (default features include python-embed).");
224+
2
225+
}
226+
209227
/// `--test FILE`: load FILE, find every top-level `fn test_*()`,
210228
/// run each in a fresh interpreter scope, report pass/fail per test
211229
/// and a final summary. A test PASSES if it returns without raising;

omnimcode-lsp/Cargo.toml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
[package]
2+
name = "omnimcode-lsp"
3+
version.workspace = true
4+
edition.workspace = true
5+
authors.workspace = true
6+
license.workspace = true
7+
description = "Language Server Protocol implementation for OMNIcode"
8+
9+
[[bin]]
10+
name = "omnimcode-lsp"
11+
path = "src/main.rs"
12+
13+
[dependencies]
14+
# OMC core WITHOUT python-embed — the LSP doesn't run user code, just
15+
# parses + analyzes. Smaller dep tree, faster compile, no libpython
16+
# requirement on developer machines.
17+
omnimcode-core = { path = "../omnimcode-core", default-features = false }
18+
19+
# LSP server framework. tower-lsp handles JSON-RPC over stdio and
20+
# dispatches Initialize/DidOpen/DidChange/etc. to a Backend trait.
21+
tower-lsp = "0.20"
22+
tokio = { version = "1", features = ["macros", "rt-multi-thread", "io-std"] }
23+
dashmap = "5"
24+
serde_json = "1"

0 commit comments

Comments
 (0)