Skip to content

fix(ruvector-cli): release-hygiene fixes for v0.2.24 (#399, #401)#403

Merged
ruvnet merged 1 commit intomainfrom
fix/ruvector-npm-release-hygiene
Apr 27, 2026
Merged

fix(ruvector-cli): release-hygiene fixes for v0.2.24 (#399, #401)#403
ruvnet merged 1 commit intomainfrom
fix/ruvector-npm-release-hygiene

Conversation

@ruvnet
Copy link
Copy Markdown
Owner

@ruvnet ruvnet commented Apr 27, 2026

Addresses release-hygiene gaps in the published ruvector npm CLI (0.2.23) reported today by @ronmikailov in #399, #400, #401, #402.

Scope

Fixes structural / packaging issues. Out of scope: binding-side API drift (#400, #402 §A/B) — tracked for follow-up.

Changes

1. prepublishOnly build-output verification — fixes #399, #402 §C

0.2.23 shipped without a dist/ directory at all, breaking 13 require('../dist/...') sites in bin/cli.js (ruvector doctor false negative, embed text crash, rvf subcommands crash). The existing prepublishOnly hook ran tsc but didn't catch a silent build failure.

Adds scripts/verify-dist.js: scans bin/cli.js for every require('../dist/...') and asserts the file exists locally. Wired into prepublishOnly after npm run build:

-  \"prepublishOnly\": \"npm run build\"
+  \"prepublishOnly\": \"npm run build && npm run verify-dist\"

Now publish fails loudly if the artifact is incomplete — independent of whether the publisher remembered to run the build manually.

2. Router help-text package name — fixes #401 §2

CLI claimed router requires ruvector-router-core, which is the Rust crate name and isn't on npm. Replaced 3 user-facing strings to point at @ruvector/router (the actual npm package, already used by src/core/router-wrapper.ts:16).

3. optimize graceful failure — fixes #401 §1

The optimizer module was never implemented — src/optimizer/index.js doesn't exist; only three orphan helpers live in that directory and none export the functions the CLI calls. Hard-coded process.exit(1) after a generic stack trace made it look like the user's install was broken.

Replaced with a friendly "not yet shipped" message linking the tracking issue.

Version bump

0.2.23 → 0.2.24.

Out of scope (deferred — needs binding investigation)

Issue Reason
#400ruvector demo modes broken API drift between CLI and @ruvector/core@0.1.31 (db.insert is not a function); needs binding-surface audit.
#402 §A — VectorDB CRUD broken Same drift class — insertBatch missing from native binding.
#402 §B — GNN/attention typed-array failures Get TypedArray info failed from napi-rs; CLI passing number[] where Float32Array expected.

The structural fixes here unblock #399 and #402 §C entirely (all dist/... paths now ship); the remaining items are tracked separately.

Verification

$ npm run build && npm run verify-dist
verify-dist: 13 dist path(s) present.

$ node bin/cli.js optimize --list
  ruvector optimize: not yet shipped in this release.
  ...track at .../issues/401

$ node bin/cli.js router --info
  Status: Coming Soon
  npm package:  npm install @ruvector/router
  Rust crate:   cargo add ruvector-router-core

$ node bin/cli.js --help | grep router
  router [options]   AI semantic router operations (requires @ruvector/router)

$ npm pack --dry-run | grep -E \"dist/(index|onnx-embedder|rvf-wrapper)\"
 14.3kB dist/core/onnx-embedder.js
  2.6kB dist/core/rvf-wrapper.js
  7.8kB dist/index.js

Closes #399 (release-hygiene structural fix). Partially addresses #401, #402 §C.

Addresses release-hygiene gaps in the published `ruvector` npm CLI
(0.2.23) reported in #399, #400, #401, #402.

## Changes

### `prepublishOnly` build-output verification (#399, #402 §C)

`0.2.23` was published without a `dist/` directory at all. tsc was
supposed to run via the existing `prepublishOnly` hook, but the hook
either didn't fire or failed silently — the published tarball shipped
no `dist/` and `bin/cli.js`'s 13 distinct `require('../dist/...')`
sites all crashed (`ruvector doctor`, `embed`, `rvf` subsystems).

Add `scripts/verify-dist.js` that scans `bin/cli.js` for every
`require('../dist/...')` path and asserts the file exists in the
local tree. Wire it into `prepublishOnly` after `npm run build` so
publish itself fails loudly if the artifact is incomplete:

  "prepublishOnly": "npm run build && npm run verify-dist"

This is a structural gate — independent of whether the publisher
remembered to run the build manually.

### Router help-text package name (#401 §2)

The CLI claimed `router` "requires ruvector-router-core", which is the
Rust crate name and isn't on npm. Users following the hint hit
`npm error 404 'ruvector-router-core@*' is not in this registry`.

The actual npm package is `@ruvector/router` (already used by the
internal wrapper at `src/core/router-wrapper.ts:16`). Replace the
three user-facing strings:

- `program.command('router').description(...)`
- the `--info` help block's "Rust crate available:" line
- the install-hint section in `info` (kept the Rust hint for the
  Rust workflow, added a parallel npm hint)

### `optimize` graceful failure (#401 §1)

`bin/cli.js` requires `'../src/optimizer/index.js'`, but the
optimizer module was never implemented — there's no `index.js` in
`src/optimizer/` (only three orphan helpers: `context.js`,
`settings-generator.js`, `tool-schemas.js`), and the listProfiles /
getProfile / detectTaskType functions the CLI calls don't exist
anywhere. Hard-coded `process.exit(1)` after a generic stack-trace
made it look like the package was broken on the user's machine.

Replace with a friendly "not yet shipped" message that points at the
tracking issue.

### Out of scope (deferred)

These need binding-side investigation and are larger:
- #400: `ruvector demo` API drift (`db.insert is not a function`)
- #402 §A: `VectorDB` CRUD lifecycle (`insertBatch is not a function`)
- #402 §B: GNN/attention typed-array marshalling

The structural fixes here unblock #399 and #402 §C entirely; the
remaining items are tracked separately.

## Verification

```
$ npm run build
$ npm run verify-dist
verify-dist: 13 dist path(s) present.

$ node bin/cli.js optimize --list
  ruvector optimize: not yet shipped in this release.
  ...track at .../issues/401

$ node bin/cli.js router --info
  Status: Coming Soon
  npm package:  npm install @ruvector/router
  Rust crate:   cargo add ruvector-router-core

$ node bin/cli.js --help | grep router
  router [options]   AI semantic router operations (requires
                     @ruvector/router)

$ npm pack --dry-run | grep -E "dist/(index|core/onnx-embedder|core/rvf-wrapper)"
14.3kB dist/core/onnx-embedder.js
 2.6kB dist/core/rvf-wrapper.js
 7.8kB dist/index.js
```

Version bumped 0.2.23 → 0.2.24.
@ruvnet ruvnet merged commit ceee9fd into main Apr 27, 2026
20 of 21 checks passed
ruvnet added a commit that referenced this pull request Apr 27, 2026
…402) (#404)

Follow-up to #403. Addresses the runtime-side issues from #400 (`ruvector
demo` modes) and #402 §A/§B (VectorDB CRUD + GNN/attention typed-array
errors) that needed binding-surface investigation.

## Changes

### `VectorDBWrapper`: normalize distance metric (§A root cause)

`@ruvector/core`'s `JsDistanceMetric` enum is PascalCase
(`Euclidean | Cosine | DotProduct | Manhattan`), but every CLI call site
passes lowercase shorthand (`'cosine'`, `'euclidean'`, `'dot'`). The
native binding rejects lowercase with:

  value `"cosine"` does not match any variant of enum `JsDistanceMetric`
  on JsDbOptions.distanceMetric

Add a `normalizeMetric()` helper in `src/index.ts` that maps both casing
*and* common aliases (`l2`, `dot`, `dotproduct`, `innerproduct`, `l1`)
to the enum variant. Also accept `metric` as a constructor alias for
`distanceMetric` so the CLI's existing `{metric: ...}` shape works
without changing every call site.

### `demo --basic`: realign with current `VectorDb` API (§A surface)

Old code:

  db.insert('vec1', [1.0, 0.0, 0.0, 0.0], { label: 'x-axis' });
  const r = db.search([0.8, 0.6, 0, 0], 3);

Current `VectorDBWrapper` (and the underlying `@ruvector/core` binding)
takes a single object:

  await db.insert({ id: 'vec1', vector: new Float32Array([...]),
                    metadata: { label: 'x-axis' } });
  const r = await db.search({ vector: new Float32Array([...]), k: 3 });

Updated all four insert calls + the search call accordingly. Verified
locally — vec4 (closest to [0.8, 0.6]) is correctly returned first.

### `demo --gnn`: Float32Array + binding-bug surfaceability

Two issues:

1. CLI passed plain `number[]`; binding requires `Float32Array`. Fixed.

2. `@ruvector/gnn-linux-x64-gnu@0.1.25` has a published-binding
   regression where every method (`differentiableSearch`,
   `RuvectorLayer.forward`, `TensorCompress.compress`) throws
   `Given napi value is not an array` regardless of input shape —
   verified with both `Array<Float32Array>` and `number[][]`. This is
   a binary-side bug, not fixable from the CLI.

Added `reportGnnBindingError()` helper that detects the error pattern
and surfaces a pointer at #402 so users don't waste time debugging
their own install. Wired it into all three GNN command error handlers
(`gnn layer --test`, `gnn compress`, `gnn search`) and the demo.

Also fixed `result.attention_weights` → `result.weights` (the wrapper
shape; `attention_weights` was the older binding shape) with a fallback
that handles both.

### `demo --graph`: real round-trip via `GraphDatabase`

Was a stub printing "Full graph demo coming soon". `@ruvector/graph-node`
exposes a `GraphDatabase` class with `createNode({ id, embedding,
properties })`, `createEdge({ from, to, description, embedding,
confidence })`, and `stats()` — all async. Implemented a tiny
Alice -[:KNOWS]-> Bob round-trip using the actual API surface.

### `demo --benchmark`: real inline benchmark (with workaround)

Was redirecting to `npx ruvector benchmark`. Implemented an inline
1000-vector / 100-query mini-benchmark. Pinned to `dim=4` because
`ruvector-core-linux-x64-gnu@0.1.29` has a regression where the
`dimensions` constructor arg is ignored — every `VectorDb` instance
reports `expected 4` regardless of what's passed (verified by
constructing fresh instances with various dims). Tracked at #402.
Once that binding is rebuilt, `dim` can scale up.

### `attention compute`: align with current `compute()` surface (§B)

The CLI's old switch invoked `attn.forward([query], keys, values)`,
but every current `@ruvector/attention` class exposes `compute(query,
keys, values)` instead — `forward` doesn't exist. Also the query
must be a flat `Float32Array`, not `[query]` matrix.

Reproduces the user's `Failed to convert napi value Undefined into
rust type u32` and `Get TypedArray info failed` errors directly.

Replaced all five branches (`dot | multi-head | flash | hyperbolic |
linear`) with the correct `compute()` invocation + Float32Array
conversion. Verified locally:

  $ node bin/cli.js attention compute -q "[1,0,0,0]" -k keys.json -t dot
  ✔ Attention computed (dot)
  Output: [0.6225, 0.3775, 0, 0...]

### `gnn layer --test` / `gnn compress` / `gnn search`: typed-array conversion

All three commands previously passed plain `number[]` where the binding
needs `Float32Array`. Converted at the call sites + added the
`reportGnnBindingError` hook so users see the upstream pointer when
they hit the binding-side regression.

## Verification

```
$ node bin/cli.js demo --basic
  Searching for nearest to [0.8, 0.6, 0, 0]:
    1. vec4 (score: 0.0101)  ✓ correct nearest
    2. vec1 (score: 0.2000)
    3. vec2 (score: 0.4000)
  Demo complete!

$ node bin/cli.js demo --gnn
  GNN demo failed: Given napi value is not an array
  Note: this is a known regression in the @ruvector/gnn native binding…
    #402

$ node bin/cli.js demo --graph
  ✓ GraphDatabase instance created
  ✓ Created nodes: Alice (alice), Bob (bob)
  ✓ Created edge Alice -[:KNOWS]-> Bob (uuid)
  Graph demo complete!

$ node bin/cli.js demo --benchmark
  ✓ Inserted 1000 vectors in 126ms (0.13ms/vec)
  ✓ 100× top-10 search in 51ms (0.51ms/query)

$ node bin/cli.js attention compute -q "[1,0,0,0]" -k keys.json -t dot
  ✔ Attention computed (dot)

$ npm run verify-dist
  verify-dist: 13 dist path(s) present.
```

Version bumped 0.2.24 → 0.2.25.

## Out of scope (binding-side rebuilds needed)

- `@ruvector/gnn` published bindings throw on every call (binding bug).
- `@ruvector/core` published bindings ignore `dimensions` constructor
  arg (binding bug).

Both need a rebuild from current source — the Rust source in this repo
shows correct independent state, but the published `.node` files have
the regression. Rebuild and republish are tracked separately.

Co-authored-by: ruvnet <ruvnet@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant