fix(ruvector-npm): accurate MCP tool count + reconcile tool lists (0.2.33) (#624)

* fix(ruvector-npm): accurate MCP tool count + reconcile tool lists (0.2.33)

The package advertised 103 MCP tools but the server registers 97, and the
README listed 12 tools (brain_agi_*, midstream_*) that don't exist. Three
independent sources had also drifted: server TOOLS array (97), the cli
'mcp tools' display list (91, missing the 6 decompile_* tools), and the
README count (103).

- README: 103 → 97; drop the 12 phantom tool bullets; point to
  'npx ruvector mcp tools' as the authoritative list
- cli.js 'mcp tools': add the missing 'decompile' group (6 tools) →
  now lists 97, matching the server
- mcp-server.js: report version from package.json instead of the
  hardcoded (and stale) '0.2.30'
- bump 0.2.32 → 0.2.33

All three sources now reconcile to 97. Full test suite passes
(73 + 7 + 2 + 8 + 2 across the publish-gate files).

Co-Authored-By: claude-flow <ruv@ruv.net>

* fix(ci): commit optimizer module, ignore RUSTSEC-2026-0190, ship src/optimizer

Root-causes three pre-existing CI failures on the ruvector npm package:

1. Optimizer test (Cannot find module src/optimizer/index.js): the module
   was never committed because .gitignore's bare 'index.js' rule (for napi
   artifacts) silently ignored this hand-written module. Add a negation
   exception (as already done for @ruvector/sona) and commit index.js —
   8 profiles, detectTaskType, applyProfile. Test: 135/135 pass.

2. cargo deny (advisories FAILED): RUSTSEC-2026-0190 (unsoundness in
   anyhow's Error::downcast_mut, anyhow 1.0.102, single version in tree).
   Added to deny.toml ignore list with justification + re-review date,
   consistent with the existing unsoundness exceptions — we never downcast
   anyhow::Error to a mismatched mutable type.

3. src/optimizer/ now ships (added to package.json files), so the published
   package's 'optimize' command works instead of graceful-degrading.

Pre-existing failures NOT addressed here (separate infra work; main is also
red): Functional smoke / Recall quality / Learning check fail because the
npm CI installs with --no-optional, so @ruvector/rvf + the native HNSW addon
are absent and the engine runs degraded. dependency-review is already
continue-on-error (awaiting a repo Dependency-Graph settings flip).

Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
rUv 2026-06-29 12:06:21 -04:00 committed by GitHub
parent ee620d600f
commit 227bb3f876
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 207 additions and 8 deletions

4
.gitignore vendored
View file

@ -41,6 +41,10 @@ index.d.ts
# (v3 emits no v2-style loader), which published an empty 0.1.6 (#516)
!npm/packages/sona/index.js
!npm/packages/sona/index.d.ts
# ruvector optimizer is a hand-written module (not a napi artifact); the bare
# `index.js` rule above wrongly ignored it, so it was never committed and CI's
# optimizer test could not resolve it.
!npm/packages/ruvector/src/optimizer/index.js
# Environment variables and secrets
.env

View file

@ -130,6 +130,14 @@ ignore = [
# mmap loading and other crates; no fixed release on the 0.9 line yet.
# We don't pass attacker-controlled offsets to memmap2. Re-review 2026-08-01.
"RUSTSEC-2026-0186",
# anyhow 1.0.102 — unsoundness in `Error::downcast_mut()` (RUSTSEC-2026-0190,
# "unsound", not an exploitable vuln). Triggering it requires downcasting an
# `anyhow::Error` to a mismatched mutable type — a pattern we never use; our
# usage is construct/propagate/`Display`/read-only `downcast_ref`. Single
# version (1.0.102) in the tree. Bump to the patched anyhow once it ships and
# remove this entry. Re-review 2026-08-01.
"RUSTSEC-2026-0190",
]
# ─────────────────────────────────────────────────────────────────────

View file

@ -69,7 +69,7 @@ npx ruvector hooks init --pretrain --build-agents quality
### MCP Server Integration
RuVector includes an MCP server for Claude Code with 103 tools:
RuVector includes an MCP server for Claude Code with 97 tools:
```bash
# Add to Claude Code
@ -86,10 +86,11 @@ claude mcp add ruvector -- npx ruvector mcp start
- `hooks_rag_context` — Semantic context retrieval
- `hooks_attention_info`, `hooks_gnn_info` — Neural capabilities
- `brain_search`, `brain_share`, `brain_status` — Shared brain knowledge
- `brain_agi_status`, `brain_sona_stats`, `brain_temporal`, `brain_explore` — AGI diagnostics
- `brain_midstream`, `brain_flags` — Midstream platform + feature flags
- `midstream_status`, `midstream_attractor`, `midstream_scheduler` — Streaming analysis
- `midstream_benchmark`, `midstream_search`, `midstream_health` — Latency benchmarks + health
- `decompile_package`, `decompile_file`, `decompile_url` — Package/file decompilation + witness
- `edge_status`, `edge_join`, `edge_balance` — Edge cluster coordination
- `identity_generate`, `identity_show` — Agent identity
See `npx ruvector mcp tools` for the full, authoritative tool list.
**MCP tool-access policy (default-deny, ADR-256):** restrict the exposed/callable
tool surface with environment variables — useful for least-privilege deployments.

View file

@ -8200,7 +8200,7 @@ mcpCmd.command('info')
mcpCmd.command('tools')
.description('List all MCP tools with descriptions (JSON output)')
.option('--group <group>', 'Filter by group (hooks, workers, rvf, rvlite, brain, edge, identity)')
.option('--group <group>', 'Filter by group (hooks, workers, rvf, rvlite, brain, edge, identity, decompile)')
.option('--json', 'JSON output')
.action((opts) => {
const tools = {
@ -8323,6 +8323,14 @@ mcpCmd.command('tools')
{ name: 'identity_generate', desc: 'Generate new pi key' },
{ name: 'identity_show', desc: 'Show current identity' },
],
'decompile': [
{ name: 'decompile_package', desc: 'Decompile an npm package + witness' },
{ name: 'decompile_file', desc: 'Decompile a single file' },
{ name: 'decompile_url', desc: 'Decompile from a URL' },
{ name: 'decompile_diff', desc: 'Diff two decompiled artifacts' },
{ name: 'decompile_search', desc: 'Search decompiled artifacts' },
{ name: 'decompile_witness', desc: 'Verify decompile witness' },
],
};
// Filter by group if specified

View file

@ -514,7 +514,7 @@ class Intelligence {
const server = new Server(
{
name: 'ruvector',
version: '0.2.30',
version: require('../package.json').version,
},
{
capabilities: {

View file

@ -1,6 +1,6 @@
{
"name": "ruvector",
"version": "0.2.32",
"version": "0.2.33",
"description": "Self-learning vector database for Node.js \u2014 hybrid search, Graph RAG, FlashAttention-3, HNSW, 50+ attention mechanisms",
"main": "dist/index.js",
"types": "dist/index.d.ts",
@ -93,6 +93,7 @@
"bin/",
"dist/",
"src/decompiler/",
"src/optimizer/",
"wasm/",
"README.md",
"LICENSE"

View file

@ -0,0 +1,177 @@
/**
* RVAgent Optimizer Claude Code configuration profiles (ADR-139).
*
* Maps a task type (coding, research, quickfix, ) to an optimal set of
* `CLAUDE_CODE_*` environment variables and a permission mode. Profiles are
* derived from the decompiled Claude Code intelligence (see ADR-139) and are
* consumed by `npx ruvector optimize` and the settings generator.
*
* Public API:
* - PERMISSION_MODES valid permission-mode strings
* - listProfiles() array of profile names
* - getProfile(name) { description, permissionMode, env } | null
* - applyProfile(name) sets process.env, returns { applied, permissionMode } | null
* - detectTaskType(prompt) infer a profile name from a free-text prompt
*/
'use strict';
/** Permission modes understood by Claude Code's harness. */
const PERMISSION_MODES = [
'default',
'acceptEdits',
'bypassPermissions',
'plan',
'dontAsk',
'auto',
];
/**
* Task profiles. Every env key MUST start with `CLAUDE_CODE_` and every
* `permissionMode` MUST be a member of {@link PERMISSION_MODES}.
*/
const PROFILES = {
coding: {
description: 'Implementation work — edits with checkpointing and thinking enabled',
permissionMode: 'acceptEdits',
env: {
CLAUDE_CODE_EFFORT_LEVEL: 'high',
CLAUDE_CODE_THINKING: '1',
CLAUDE_CODE_AUTO_COMPACT: '1',
CLAUDE_CODE_FILE_CHECKPOINTING: '1',
},
},
research: {
description: 'Investigation and analysis — read-heavy, no edits, deep reasoning',
permissionMode: 'default',
env: {
CLAUDE_CODE_EFFORT_LEVEL: 'high',
CLAUDE_CODE_THINKING: '1',
CLAUDE_CODE_AUTO_COMPACT: '1',
},
},
quickfix: {
description: 'Small, fast fixes — brief output, low effort, quick turnaround',
permissionMode: 'acceptEdits',
env: {
CLAUDE_CODE_BRIEF: '1',
CLAUDE_CODE_EFFORT_LEVEL: 'low',
CLAUDE_CODE_THINKING: '0',
},
},
planning: {
description: 'Architecture and design — plan mode, no edits until approved',
permissionMode: 'plan',
env: {
CLAUDE_CODE_EFFORT_LEVEL: 'high',
CLAUDE_CODE_THINKING: '1',
},
},
background: {
description: 'Long-running background/daemon work — autonomous, minimal prompts',
permissionMode: 'bypassPermissions',
env: {
CLAUDE_CODE_EFFORT_LEVEL: 'medium',
CLAUDE_CODE_AUTO_COMPACT: '1',
CLAUDE_CODE_PROMPT_SUGGESTION: '0',
},
},
swarm: {
description: 'Multi-agent swarm coordination — autonomous, hooks-driven',
permissionMode: 'bypassPermissions',
env: {
CLAUDE_CODE_EFFORT_LEVEL: 'medium',
CLAUDE_CODE_AUTO_COMPACT: '1',
CLAUDE_CODE_THINKING: '1',
},
},
review: {
description: 'Code review — read-only, no edits, thorough reasoning',
permissionMode: 'default',
env: {
CLAUDE_CODE_EFFORT_LEVEL: 'high',
CLAUDE_CODE_THINKING: '1',
CLAUDE_CODE_BRIEF: '0',
},
},
ci: {
description: 'CI / automation pipelines — fast, non-interactive, no suggestions',
permissionMode: 'dontAsk',
env: {
CLAUDE_CODE_FAST_MODE: '1',
CLAUDE_CODE_EFFORT_LEVEL: 'low',
CLAUDE_CODE_PROMPT_SUGGESTION: '0',
},
},
};
/**
* Keyword profile rules, evaluated in order. The first rule whose regex
* matches the prompt wins, so more specific task types are listed first.
*/
const DETECTION_RULES = [
{ type: 'quickfix', re: /\b(typo|quick\s?-?fix|one-?liner|small fix|rename)\b/i },
{ type: 'ci', re: /\b(ci|cd|pipeline|github actions|workflow|deploy)\b/i },
{ type: 'swarm', re: /\b(swarm|multi-?agent|coordinate|orchestrat\w*|hive)\b/i },
{ type: 'background', re: /\b(background|daemon|monitor\w*|watch\b|long-?running)\b/i },
{ type: 'review', re: /\b(review|pull request|\bpr\b|audit|critique)\b/i },
{ type: 'planning', re: /\b(plan\w*|architect\w*|design|roadmap|strategy)\b/i },
{ type: 'research', re: /\b(research|investigat\w*|explore|compare|survey)\b/i },
{ type: 'coding', re: /\b(implement|code|build|add|write|refactor|create|fix|function|feature)\b/i },
];
/** List all available profile names. */
function listProfiles() {
return Object.keys(PROFILES);
}
/** Return a profile by name, or `null` if it does not exist. */
function getProfile(name) {
if (!name || !Object.prototype.hasOwnProperty.call(PROFILES, name)) {
return null;
}
return PROFILES[name];
}
/**
* Apply a profile's env vars to `process.env`. Returns `{ applied, permissionMode }`
* where `applied` is the map of env vars that were set, or `null` if the profile
* is unknown.
*/
function applyProfile(name) {
const profile = getProfile(name);
if (!profile) {
return null;
}
const applied = {};
for (const [key, val] of Object.entries(profile.env)) {
process.env[key] = val;
applied[key] = val;
}
return { applied, permissionMode: profile.permissionMode };
}
/**
* Infer the most likely task type from a free-text prompt. Defaults to
* `'coding'` for empty/unrecognised input.
*/
function detectTaskType(prompt) {
if (!prompt || typeof prompt !== 'string') {
return 'coding';
}
for (const rule of DETECTION_RULES) {
if (rule.re.test(prompt)) {
return rule.type;
}
}
return 'coding';
}
module.exports = {
PERMISSION_MODES,
PROFILES,
listProfiles,
getProfile,
applyProfile,
detectTaskType,
};