feat(adr-124/packaging): rename to @ruvnet/rvagent 0.1.0 + manifest test (ADR-124 §2)
Advances SPARC Phase 1 (Specification) for ADR-124 SENSE-BRIDGE by establishing
the correct npm package identity that all subsequent implementation iters depend on.
Changes:
- tools/ruview-mcp/package.json
- name: @ruv/ruview-mcp → @ruvnet/rvagent (ADR-124 §2.1)
- version: 0.0.1 → 0.1.0 (initial publishable milestone)
- removed private:true so the package is publishable (ADR-124 §2.6)
- bin: added rvagent key alongside legacy ruview-mcp alias (ADR-124 §2.4)
- exports: added "." entry with import+types keys for ESM+CJS dual output (ADR-124 §2.5)
- files: added README.md and CHANGELOG.md slots (ADR-124 §5 npm publish plan)
- keywords: expanded with sense-bridge, rvagent, ruvnet
- repository / homepage / bugs: wired to github.com/ruvnet/RuView
- tools/ruview-mcp/src/index.ts
- SERVER_NAME: "ruview" → "rvagent"
- PACKAGE_VERSION: "0.0.1" → "0.1.0"
- stderr log prefix: [ruview-mcp] → [@ruvnet/rvagent]
- tools/ruview-mcp/tests/manifest.test.ts (NEW)
- 10 ADR-124 §2 acceptance-criterion assertions, all green
- Guards name, version >=0.1.0, engines.node >=20, bin.rvagent, exports structure,
publishConfig.access, @modelcontextprotocol/sdk dep, zod dep, ESM type, license
Test results: 26/26 PASS (manifest.test.ts ×10 + tools.test.ts ×5 + validate.test.ts ×11)
Build: tsc clean, zero errors.
Next iter target: (A) Zod schema barrel for the 15+5 tool catalog from ADR-124 §4.1/4.1a
Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
parent
8520e8ced6
commit
d11ca9c31e
|
|
@ -1,16 +1,25 @@
|
|||
{
|
||||
"name": "@ruv/ruview-mcp",
|
||||
"version": "0.0.1",
|
||||
"description": "RuView MCP server — expose WiFi-DensePose sensing capabilities as MCP tools for Claude Code, Cursor, and other MCP-compatible agents",
|
||||
"private": true,
|
||||
"name": "@ruvnet/rvagent",
|
||||
"version": "0.1.0",
|
||||
"description": "SENSE-BRIDGE: dual-transport MCP server (stdio + Streamable HTTP) exposing RuView WiFi-DensePose sensing primitives to AI agents",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"import": "./dist/index.js",
|
||||
"require": "./dist/index.cjs",
|
||||
"types": "./dist/index.d.ts"
|
||||
}
|
||||
},
|
||||
"bin": {
|
||||
"rvagent": "dist/index.js",
|
||||
"ruview-mcp": "dist/index.js"
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
"dist",
|
||||
"README.md",
|
||||
"CHANGELOG.md"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "tsc",
|
||||
|
|
@ -22,14 +31,26 @@
|
|||
},
|
||||
"keywords": [
|
||||
"mcp",
|
||||
"rvagent",
|
||||
"ruview",
|
||||
"wifi",
|
||||
"csi",
|
||||
"pose-estimation",
|
||||
"cognitum"
|
||||
"cognitum",
|
||||
"sense-bridge",
|
||||
"ruvnet"
|
||||
],
|
||||
"author": "ruv <ruv@ruv.net>",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ruvnet/RuView.git",
|
||||
"directory": "tools/ruview-mcp"
|
||||
},
|
||||
"homepage": "https://github.com/ruvnet/RuView/tree/main/tools/ruview-mcp",
|
||||
"bugs": {
|
||||
"url": "https://github.com/ruvnet/RuView/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"@modelcontextprotocol/sdk": "^1.0.0",
|
||||
"zod": "^3.23.8"
|
||||
|
|
|
|||
|
|
@ -43,8 +43,8 @@ import {
|
|||
jobStatus,
|
||||
} from "./tools/train-count.js";
|
||||
|
||||
const PACKAGE_VERSION = "0.0.1";
|
||||
const SERVER_NAME = "ruview";
|
||||
const PACKAGE_VERSION = "0.1.0";
|
||||
const SERVER_NAME = "rvagent";
|
||||
|
||||
// ── Tool registry ──────────────────────────────────────────────────────────
|
||||
|
||||
|
|
@ -297,7 +297,7 @@ async function main(): Promise<void> {
|
|||
|
||||
// Log to stderr so it doesn't interfere with the MCP stdio protocol.
|
||||
process.stderr.write(
|
||||
`[ruview-mcp] Server v${PACKAGE_VERSION} started. ` +
|
||||
`[@ruvnet/rvagent] Server v${PACKAGE_VERSION} started. ` +
|
||||
`Sensing server: ${config.sensingServerUrl}\n`
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,101 @@
|
|||
/**
|
||||
* ADR-124 §2 manifest validation test.
|
||||
*
|
||||
* Guards that package.json satisfies every structural decision from ADR-124 §2:
|
||||
* 1. Package name is @ruvnet/rvagent
|
||||
* 2. Version is >= 0.1.0
|
||||
* 3. engines.node is >= 20
|
||||
* 4. bin includes the "rvagent" key (npx @ruvnet/rvagent invocation)
|
||||
* 5. exports["." ] includes both "import" and "types" keys (ESM + types in tarball)
|
||||
* 6. publishConfig.access === "public" (scoped package must be explicit)
|
||||
* 7. @modelcontextprotocol/sdk is a runtime dependency (dual-transport server)
|
||||
* 8. zod is a runtime dependency (input schema validation)
|
||||
* 9. type === "module" (ESM-first, Node.js 20+ native)
|
||||
* 10. license === "Apache-2.0"
|
||||
*/
|
||||
|
||||
import { readFileSync } from "node:fs";
|
||||
import { resolve, dirname } from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
const pkgPath = resolve(__dirname, "../package.json");
|
||||
|
||||
// Parse once; keep raw for snapshot assertions.
|
||||
const raw = readFileSync(pkgPath, "utf-8");
|
||||
const pkg = JSON.parse(raw) as Record<string, unknown>;
|
||||
|
||||
// Helper to assert string field value.
|
||||
function assertField(field: string, expected: string): void {
|
||||
expect(pkg[field]).toBe(expected);
|
||||
}
|
||||
|
||||
// Helper to get a nested value.
|
||||
function nested<T>(obj: Record<string, unknown>, ...keys: string[]): T {
|
||||
let cur: unknown = obj;
|
||||
for (const k of keys) {
|
||||
if (typeof cur !== "object" || cur === null) {
|
||||
throw new Error(`Expected object at key "${k}"`);
|
||||
}
|
||||
cur = (cur as Record<string, unknown>)[k];
|
||||
}
|
||||
return cur as T;
|
||||
}
|
||||
|
||||
describe("@ruvnet/rvagent package.json (ADR-124 §2)", () => {
|
||||
it("§2.1 — name is @ruvnet/rvagent", () => {
|
||||
assertField("name", "@ruvnet/rvagent");
|
||||
});
|
||||
|
||||
it("§2.2 — version is semver >= 0.1.0", () => {
|
||||
const version = pkg["version"] as string;
|
||||
expect(typeof version).toBe("string");
|
||||
const [major, minor] = version.split(".").map(Number);
|
||||
const isAtLeast010 = (major ?? 0) > 0 || (minor ?? 0) >= 1;
|
||||
expect(isAtLeast010).toBe(true);
|
||||
});
|
||||
|
||||
it("§2.3 — engines.node requires Node.js >= 20", () => {
|
||||
const nodeRange = nested<string>(pkg, "engines", "node");
|
||||
expect(typeof nodeRange).toBe("string");
|
||||
// Accept >=20 or >=20.0.0 patterns.
|
||||
expect(nodeRange).toMatch(/>=\s*20/);
|
||||
});
|
||||
|
||||
it("§2.4 — bin.rvagent is defined (npx @ruvnet/rvagent invocation)", () => {
|
||||
const bin = nested<Record<string, string>>(pkg, "bin");
|
||||
expect(typeof bin["rvagent"]).toBe("string");
|
||||
expect(bin["rvagent"]).toMatch(/dist\/index\.js/);
|
||||
});
|
||||
|
||||
it("§2.5 — exports['.'] has import + types keys (ESM + TypeScript declarations)", () => {
|
||||
const exports = nested<Record<string, Record<string, string>>>(pkg, "exports");
|
||||
const dotExport = exports["."];
|
||||
expect(dotExport).toBeDefined();
|
||||
expect(typeof dotExport?.["import"]).toBe("string");
|
||||
expect(typeof dotExport?.["types"]).toBe("string");
|
||||
});
|
||||
|
||||
it("§2.6 — publishConfig.access is 'public' (scoped package requirement)", () => {
|
||||
const access = nested<string>(pkg, "publishConfig", "access");
|
||||
expect(access).toBe("public");
|
||||
});
|
||||
|
||||
it("§2.7 — @modelcontextprotocol/sdk is a runtime dependency", () => {
|
||||
const deps = nested<Record<string, string>>(pkg, "dependencies");
|
||||
expect(typeof deps["@modelcontextprotocol/sdk"]).toBe("string");
|
||||
});
|
||||
|
||||
it("§2.8 — zod is a runtime dependency", () => {
|
||||
const deps = nested<Record<string, string>>(pkg, "dependencies");
|
||||
expect(typeof deps["zod"]).toBe("string");
|
||||
});
|
||||
|
||||
it("§2.9 — type is 'module' (ESM-first, Node.js 20+ native)", () => {
|
||||
assertField("type", "module");
|
||||
});
|
||||
|
||||
it("§2.10 — license is Apache-2.0", () => {
|
||||
assertField("license", "Apache-2.0");
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue