🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

mendapi

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mendapi - npm Package Compare versions

Comparing version
0.5.3
to
0.5.4
+33
dbpath.js
// dbpath.js — single source of truth for where the change database lives.
//
// Resolution order (read and write use the same rules, so every command
// agrees on one location):
//
// 1. MENDAPI_DB env var — explicit override, used verbatim.
// 2. <package>/data/sentinel.db — but only when it already exists.
// This keeps the repo/dev workflow (where the DB is checked into the
// working tree next to the source) working unchanged, and stays
// backward compatible with consumers who synced under older versions
// (their DB sat inside node_modules/mendapi/data).
// 3. <cwd>/.mendapi/sentinel.db — the default for npm consumers.
//
// Rationale for (3): writing into the package install directory
// (node_modules/mendapi/data) means `npm update` / a reinstall silently
// deletes the user's synced database. A dot-directory in the project the
// user runs mendapi from survives dependency churn, and `.mendapi` is
// already skipped by the scanner/fixer walkers.
import { existsSync } from 'node:fs';
import { dirname, join, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
const PKG_ROOT = dirname(fileURLToPath(import.meta.url));
const PKG_DB = join(PKG_ROOT, 'data', 'sentinel.db');
export function resolveDbPath() {
if (process.env.MENDAPI_DB) return resolve(process.env.MENDAPI_DB);
if (existsSync(PKG_DB)) return PKG_DB;
return join(process.cwd(), '.mendapi', 'sentinel.db');
}
export const DB_PATH = resolveDbPath();
+66
-2

@@ -14,2 +14,3 @@ #!/usr/bin/env node

import { spawnSync } from 'node:child_process';
import { readFileSync } from 'node:fs';
import { join, dirname } from 'node:path';

@@ -20,2 +21,11 @@ import { fileURLToPath } from 'node:url';

// Single source of truth for the version: package.json (never hand-write it here).
function pkgVersion() {
try {
return JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf8')).version;
} catch {
return 'unknown';
}
}
const COMMANDS = {

@@ -30,3 +40,3 @@ sync: { script: 'watcher.js', summary: 'Fetch the latest API change feed from provider release channels (network)' },

pr: { script: 'pr.js', summary: 'Turn a fix into a reviewable git branch + PR-ready description (local by default)' },
mcp: { script: 'mcp.js', summary: 'Run a Model Context Protocol server on stdio (tools: scan, fix, changes, deps; local only)' },
mcp: { script: 'mcp.js', summary: 'Run a Model Context Protocol server on stdio (tools: scan, fix, deps, revalidate, changes; local only)' },
};

@@ -48,4 +58,28 @@

console.log('Run `mendapi <command> --help` (or with no args) for command options.');
console.log('Run `mendapi --version` to print the installed version.');
}
// Preflight: node:sqlite is only available unflagged on Node >= 22.13.0 (23.4.0 on the 23.x line).
// Older 22.x passes a naive "22+" check yet crashes with ERR_UNKNOWN_BUILTIN_MODULE — fail loud
// with a clear message instead of a stack trace. Required version is read from package.json engines.
// Called after the --help/--version branches: those need no sqlite and must always work.
function checkNodeVersion() {
let required = '22.13.0';
try {
const engines = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf8')).engines;
const m = /([0-9]+\.[0-9]+\.[0-9]+)/.exec(engines?.node || '');
if (m) required = m[1];
} catch { /* fall back to the documented floor */ }
const cur = process.versions.node.split('.').map(Number);
const req = required.split('.').map(Number);
for (let i = 0; i < 3; i++) {
if (cur[i] > req[i]) return;
if (cur[i] < req[i]) {
console.error(`mendapi requires Node.js >= ${required} (built-in node:sqlite).`);
console.error(`You are running Node.js ${process.versions.node}. Please upgrade: https://nodejs.org/`);
process.exit(1);
}
}
}
const [cmd, ...rest] = process.argv.slice(2);

@@ -58,2 +92,9 @@

if (cmd === '--version' || cmd === '-v' || cmd === 'version') {
console.log(pkgVersion());
process.exit(0);
}
checkNodeVersion();
const target = COMMANDS[cmd];

@@ -66,3 +107,26 @@ if (!target) {

const res = spawnSync(process.execPath, [join(ROOT, target.script), ...rest], { stdio: 'inherit' });
// Suppress the node:sqlite ExperimentalWarning on every subcommand: it prints two lines of
// noise to stderr on each run (bad first impression, pollutes MCP stdio logs). The flag
// exists since Node 21.3.0 and our engines floor is 22.13.0, so it is always available here.
// CLI convention: explicitly requested help is a success, never a usage error,
// and its text belongs on stdout (so `mendapi fix --help | grep apply` works).
// Most subcommands print usage on their usage-error path (stderr, exit 2;
// review: 1). Normalize the bare `mendapi <cmd> --help` invocation at this
// single dispatch point: capture the output, emit it on stdout, exit 0.
// Scoped tight: only when --help/-h is the sole argument — real runs and
// mixed-flag calls keep inherited stdio and their true exit codes
// (e.g. `fix --migration bad --help` still fails loud on stderr).
const helpOnly = rest.length === 1 && (rest[0] === '--help' || rest[0] === '-h');
const usageCode = cmd === 'review' ? 1 : 2;
const res = spawnSync(
process.execPath,
['--disable-warning=ExperimentalWarning', join(ROOT, target.script), ...rest],
helpOnly ? { encoding: 'utf8' } : { stdio: 'inherit' }
);
if (helpOnly) {
process.stdout.write((res.stdout || '') + (res.stderr || ''));
// Subcommands that already handle --help natively exit 0; the rest land on
// their usage-error code. Both count as a successful help request.
process.exit(res.status === 0 || res.status === usageCode ? 0 : (res.status ?? 1));
}
process.exit(res.status ?? 1);
+3
-1

@@ -145,3 +145,5 @@ #!/usr/bin/env node

const outDir = args['out-dir'] || join(ROOT, '..', 'loop', 'evidence', 'llm-fix-drafts');
// Default under cwd/.mendapi — see fixer.js for the rationale (no writes
// next to the installed package, dot-dir invisible to scans).
const outDir = args['out-dir'] || join(process.cwd(), '.mendapi', 'llm-fix-drafts');
mkdirSync(outDir, { recursive: true });

@@ -148,0 +150,0 @@ const { unifiedDiff } = await import('./fixer.js');

+8
-4

@@ -10,2 +10,3 @@ #!/usr/bin/env node

// fix — preview (dry-run) or apply a deterministic migration pack
// revalidate — audit migration packs for staleness against the local DB
// changes — query the local change database (provider / type filters)

@@ -28,3 +29,3 @@ //

import { execFileSync } from 'node:child_process';
import { existsSync } from 'node:fs';
import { existsSync, readFileSync } from 'node:fs';
import { join, dirname, resolve } from 'node:path';

@@ -35,5 +36,8 @@ import { fileURLToPath } from 'node:url';

const ROOT = dirname(fileURLToPath(import.meta.url));
const DB_PATH = join(ROOT, 'data', 'sentinel.db');
import { DB_PATH } from './dbpath.js';
const SERVER_INFO = { name: 'mendapi', version: '0.2.0' };
// Server identity: version is read from package.json (single source) so the
// MCP serverInfo can never drift from the published npm version again.
const PKG_VERSION = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf8')).version;
const SERVER_INFO = { name: 'mendapi', version: PKG_VERSION };
// Dual-era version support (MCP spec revision 2026-07-28, "Versioning and

@@ -363,3 +367,3 @@ // Compatibility"): modern versions are served statelessly via per-request

console.log('Starts a Model Context Protocol server on stdio (JSON-RPC 2.0, newline-delimited).');
console.log('Tools: scan, deps, fix, changes. All local; no network code.');
console.log('Tools: scan, deps, fix, revalidate, changes. All local; no network code.');
process.exit(0);

@@ -366,0 +370,0 @@ }

{
"name": "mendapi",
"version": "0.5.3",
"version": "0.5.4",
"license": "AGPL-3.0-only",

@@ -29,2 +29,3 @@ "type": "module",

"astlite.js",
"dbpath.js",
"pr.js",

@@ -44,3 +45,3 @@ "review.js",

"engines": {
"node": ">=22.5.0"
"node": ">=22.13.0"
},

@@ -47,0 +48,0 @@ "author": "mendapi <contact@mendapi.com>",

+3
-1

@@ -71,3 +71,5 @@ #!/usr/bin/env node

const outDir = args['out-dir'] || join(ROOT, '..', 'loop', 'evidence', `pr-${migration}`);
// Default under cwd/.mendapi — see fixer.js for the rationale (no writes
// next to the installed package, dot-dir invisible to scans).
const outDir = args['out-dir'] || join(process.cwd(), '.mendapi', `pr-${migration}`);
mkdirSync(outDir, { recursive: true });

@@ -74,0 +76,0 @@

@@ -21,3 +21,3 @@ # mendapi

Requires Node.js 22+. Everything runs locally: the scanner, fixer, and review CLIs contain no network code at all.
Requires Node.js 22.13 or newer. Everything runs locally: the scanner, fixer, and review CLIs contain no network code at all.

@@ -47,3 +47,3 @@ ## Security model (read this first)

Requires Node.js 22+ (uses built-in `node:sqlite`). Zero npm dependencies.
Requires Node.js 22.13 or newer (uses built-in `node:sqlite`). Zero npm dependencies.

@@ -139,3 +139,3 @@ ```bash

Tools exposed: `scan`, `deps`, `fix`, `changes` — the same `schema_version`-stamped JSON as the CLI `--json` flags. See the [For AI agents](https://mendapi.com/docs/agents.html) docs page for the full tool catalog and an autonomous-maintenance recipe.
Tools exposed: `scan`, `deps`, `fix`, `revalidate`, `changes` — the same `schema_version`-stamped JSON as the CLI `--json` flags. See the [For AI agents](https://mendapi.com/docs/agents.html) docs page for the full tool catalog and an autonomous-maintenance recipe.

@@ -166,3 +166,3 @@ ## Why precision matters

Published on npm as [`mendapi`](https://www.npmjs.com/package/mendapi) (v0.5.3). Early release — the change database and migration pack registry grow daily; interfaces may still shift before 1.0.
Published on npm as [`mendapi`](https://www.npmjs.com/package/mendapi) (v0.5.4). Early release — the change database and migration pack registry grow daily; interfaces may still shift before 1.0.

@@ -169,0 +169,0 @@ ## License

@@ -17,3 +17,3 @@ #!/usr/bin/env node

const ROOT = dirname(fileURLToPath(import.meta.url));
const DB_PATH = join(ROOT, 'data', 'sentinel.db');
import { DB_PATH } from './dbpath.js';

@@ -20,0 +20,0 @@ const VALID_TYPES = new Set(['breaking', 'deprecation', 'additive', 'docs-only', 'fix', 'unknown']);

@@ -39,3 +39,4 @@ #!/usr/bin/env node

const ROOT = dirname(fileURLToPath(import.meta.url));
export const DEFAULT_DB_PATH = join(ROOT, 'data', 'sentinel.db');
import { DB_PATH as DEFAULT_DB_PATH } from './dbpath.js';
export { DEFAULT_DB_PATH };

@@ -42,0 +43,0 @@ // spec-diff source repos carry the version pair in the name

@@ -40,3 +40,3 @@ #!/usr/bin/env node

const ROOT = dirname(fileURLToPath(import.meta.url));
const DB_PATH = join(ROOT, 'data', 'sentinel.db');
import { DB_PATH } from './dbpath.js';

@@ -43,0 +43,0 @@ const VERDICTS = new Map([

@@ -22,3 +22,3 @@ #!/usr/bin/env node

const ROOT = dirname(fileURLToPath(import.meta.url));
const DB_PATH = join(ROOT, 'data', 'sentinel.db');
import { DB_PATH } from './dbpath.js';

@@ -714,3 +714,17 @@ // ---------- provider signatures ----------

const hidden = report.impacts.length - shown.length;
const list = shown.length ? shown : report.impacts.slice(0, 5);
// Terminal render cap: a repo with one generic SDK import and zero symbol
// matches can accumulate thousands of medium hits (every breaking change of
// that provider). Dumping them all makes the first-run report unreadable —
// the terminal view is a summary, the full data always lives in --json/--out.
// High-confidence hits are never capped (they are the actionable core).
const MAX_TERMINAL_IMPACTS = 25;
let list = shown.length ? shown : report.impacts.slice(0, 5);
let capped = 0;
if (list.length > MAX_TERMINAL_IMPACTS) {
const high = list.filter((im) => im.confidence === 'high');
const rest = list.filter((im) => im.confidence !== 'high');
const budget = Math.max(MAX_TERMINAL_IMPACTS - high.length, 0);
capped = rest.length - budget;
list = [...high, ...rest.slice(0, budget)];
}
for (const im of list) {

@@ -727,2 +741,6 @@ const ch = im.change;

}
if (capped > 0) {
out.push(dim(`${capped} more medium-confidence impact${capped === 1 ? '' : 's'} not shown — use --json or --out for the full report.`));
out.push('');
}
if (shown.length && hidden > 0) {

@@ -729,0 +747,0 @@ out.push(dim(`${hidden} low-confidence impact${hidden === 1 ? '' : 's'} hidden — use --json or --out for the full report.`));

@@ -13,3 +13,3 @@ #!/usr/bin/env node

const ROOT = dirname(fileURLToPath(import.meta.url));
const DB_PATH = join(ROOT, 'data', 'sentinel.db');
import { DB_PATH } from './dbpath.js';

@@ -118,3 +118,3 @@ // provider -> list of GitHub repos whose releases we watch

function openDb() {
mkdirSync(join(ROOT, 'data'), { recursive: true });
mkdirSync(dirname(DB_PATH), { recursive: true });
const db = new DatabaseSync(DB_PATH);

@@ -271,5 +271,21 @@ db.exec(`

function printUsage() {
console.log('Usage: mendapi sync');
console.log('');
console.log('Fetches the latest API change feed from provider release channels');
console.log('(GitHub Releases feeds of official SDK repos) into the local change');
console.log('database. This is the only mendapi command that makes network calls,');
console.log('and it only runs when you invoke it without --help.');
}
// Run only when invoked directly (keeps `classify` importable for tests without side effects).
// --help must never trigger the network sync: a user asking for help gets usage text only.
if (process.argv[1] === fileURLToPath(import.meta.url)) {
main();
const args = process.argv.slice(2);
if (args.includes('--help') || args.includes('-h')) {
printUsage();
process.exit(0);
} else {
main();
}
}

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display