mirror of
https://github.com/ruvnet/RuVector.git
synced 2026-07-09 17:28:42 +00:00
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:
parent
ee620d600f
commit
227bb3f876
7 changed files with 207 additions and 8 deletions
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
]
|
||||
|
||||
# ─────────────────────────────────────────────────────────────────────
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -514,7 +514,7 @@ class Intelligence {
|
|||
const server = new Server(
|
||||
{
|
||||
name: 'ruvector',
|
||||
version: '0.2.30',
|
||||
version: require('../package.json').version,
|
||||
},
|
||||
{
|
||||
capabilities: {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
177
npm/packages/ruvector/src/optimizer/index.js
Normal file
177
npm/packages/ruvector/src/optimizer/index.js
Normal 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,
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue