@massu/core 2.1.0 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/dist/cli.js +71 -11
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -10,6 +10,25 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
|
10
10
|
> redistributed under the **Apache License 2.0**. Full license + NOTICE:
|
|
11
11
|
> `packages/core/assets/embedder/MODEL-LICENSE`.
|
|
12
12
|
|
|
13
|
+
## [2.2.0] - 2026-07-22
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- **Windows Node bootstrap — CR-70 Layer 2 auto-recovery now covers Windows.** `2.1.0` shipped
|
|
18
|
+
the self-bootstrapping launcher that re-execs massu under a compatible installed Node when the
|
|
19
|
+
running Node is below the floor — but discovery was Unix-only (a slash-rooted allowlist, a POSIX
|
|
20
|
+
ownership gate). On Windows it degraded to a correct-but-manual winget/nodejs.org remedy. `2.2.0`
|
|
21
|
+
extends the SAME chokepoint, floor SoT, and re-exec to Windows: discovery now enumerates the
|
|
22
|
+
Windows install layouts (nvm-windows, fnm, volta, scoop, the MSI / winget / Chocolatey
|
|
23
|
+
`C:\Program Files\nodejs`, and `%LOCALAPPDATA%\Programs\nodejs`) from their env pointers only —
|
|
24
|
+
never `%PATH%` / `where.exe` — with a strict absolute-path allowlist-root containment trust gate
|
|
25
|
+
(the `getuid` analogue). A Windows customer with a compatible Node already installed now gets the
|
|
26
|
+
identical zero-onus auto-fix on `npm i -g @massu/core@2.2.0`; otherwise the already-shipped
|
|
27
|
+
correct Windows loud remedy. The POSIX path is byte-for-byte unchanged (regression-guarded). A
|
|
28
|
+
real `windows-latest` CI leg (`Windows Bootstrap Gate`) proves re-exec fidelity, installer
|
|
29
|
+
symmetry, and the doctor canary at runtime on Windows. No new Canonical Rule — Windows parity of
|
|
30
|
+
CR-70, folded into `canonical-rules-detail.md#cr-70`.
|
|
31
|
+
|
|
13
32
|
## [2.1.0] - 2026-07-22
|
|
14
33
|
|
|
15
34
|
### Added
|
package/dist/cli.js
CHANGED
|
@@ -6376,7 +6376,7 @@ import {
|
|
|
6376
6376
|
fsyncSync as fsyncSync3,
|
|
6377
6377
|
closeSync as closeSync3,
|
|
6378
6378
|
existsSync as existsSync14,
|
|
6379
|
-
realpathSync,
|
|
6379
|
+
realpathSync as realpathSync2,
|
|
6380
6380
|
unlinkSync as unlinkSync2,
|
|
6381
6381
|
accessSync as accessSync2,
|
|
6382
6382
|
statSync as statSync5,
|
|
@@ -6423,8 +6423,8 @@ function isContainedIn(rootDir, candidate, opts = {}) {
|
|
|
6423
6423
|
let realRoot;
|
|
6424
6424
|
let realProbe;
|
|
6425
6425
|
try {
|
|
6426
|
-
realRoot =
|
|
6427
|
-
realProbe =
|
|
6426
|
+
realRoot = realpathSync2(root);
|
|
6427
|
+
realProbe = realpathSync2(probe);
|
|
6428
6428
|
} catch {
|
|
6429
6429
|
return true;
|
|
6430
6430
|
}
|
|
@@ -38300,13 +38300,14 @@ import { fileURLToPath as fileURLToPath7 } from "url";
|
|
|
38300
38300
|
|
|
38301
38301
|
// src/lib/node-bootstrap.ts
|
|
38302
38302
|
init_node_floor();
|
|
38303
|
-
import { existsSync, readdirSync, statSync } from "fs";
|
|
38303
|
+
import { existsSync, readdirSync, statSync, realpathSync } from "fs";
|
|
38304
38304
|
import { spawnSync, execFileSync } from "child_process";
|
|
38305
38305
|
import { homedir } from "os";
|
|
38306
|
-
import { isAbsolute, resolve } from "path";
|
|
38306
|
+
import { isAbsolute, resolve, win32 as pathWin32 } from "path";
|
|
38307
38307
|
var REEXEC_SENTINEL_ENV = "MASSU_BOOTSTRAP_REEXEC";
|
|
38308
38308
|
var OPT_OUT_ENV = "MASSU_NO_NODE_BOOTSTRAP";
|
|
38309
|
-
function allowlistPatterns(env) {
|
|
38309
|
+
function allowlistPatterns(env, platform = process.platform) {
|
|
38310
|
+
if (platform === "win32") return windowsAllowlistPatterns(env);
|
|
38310
38311
|
const patterns = [];
|
|
38311
38312
|
const rawHome = env.HOME || homedir();
|
|
38312
38313
|
const home = rawHome && isAbsolute(rawHome) ? rawHome : null;
|
|
@@ -38326,6 +38327,44 @@ function allowlistPatterns(env) {
|
|
|
38326
38327
|
);
|
|
38327
38328
|
return patterns;
|
|
38328
38329
|
}
|
|
38330
|
+
function winManagerDirs(env) {
|
|
38331
|
+
const abs = (d2) => d2 && pathWin32.isAbsolute(d2) ? d2 : null;
|
|
38332
|
+
const appdata = abs(env.APPDATA);
|
|
38333
|
+
const localappdata = abs(env.LOCALAPPDATA);
|
|
38334
|
+
return {
|
|
38335
|
+
userprofile: abs(env.USERPROFILE),
|
|
38336
|
+
nvmHome: abs(env.NVM_HOME),
|
|
38337
|
+
nvmSymlink: abs(env.NVM_SYMLINK),
|
|
38338
|
+
fnmDir: abs(env.FNM_DIR) ?? (appdata ? `${appdata}\\fnm` : null),
|
|
38339
|
+
voltaHome: abs(env.VOLTA_HOME) ?? (localappdata ? `${localappdata}\\Volta` : null),
|
|
38340
|
+
localappdata
|
|
38341
|
+
};
|
|
38342
|
+
}
|
|
38343
|
+
function windowsAllowlistRoots(env) {
|
|
38344
|
+
const d2 = winManagerDirs(env);
|
|
38345
|
+
const roots = [];
|
|
38346
|
+
for (const r2 of [d2.userprofile, d2.nvmHome, d2.nvmSymlink, d2.fnmDir, d2.voltaHome, d2.localappdata]) {
|
|
38347
|
+
if (r2) roots.push(r2);
|
|
38348
|
+
}
|
|
38349
|
+
roots.push("C:\\Program Files\\nodejs", "C:\\Program Files (x86)\\nodejs");
|
|
38350
|
+
return roots;
|
|
38351
|
+
}
|
|
38352
|
+
function windowsAllowlistPatterns(env) {
|
|
38353
|
+
const d2 = winManagerDirs(env);
|
|
38354
|
+
const patterns = [];
|
|
38355
|
+
const add = (dir, suffix) => {
|
|
38356
|
+
if (dir) patterns.push(`${dir}\\${suffix}`);
|
|
38357
|
+
};
|
|
38358
|
+
add(d2.nvmHome, "v*\\node.exe");
|
|
38359
|
+
add(d2.nvmSymlink, "node.exe");
|
|
38360
|
+
add(d2.fnmDir, "node-versions\\v*\\installation\\node.exe");
|
|
38361
|
+
add(d2.voltaHome, "tools\\image\\node\\*\\node.exe");
|
|
38362
|
+
add(d2.userprofile, "scoop\\apps\\nodejs\\current\\node.exe");
|
|
38363
|
+
add(d2.userprofile, "scoop\\apps\\nodejs-lts\\current\\node.exe");
|
|
38364
|
+
add(d2.localappdata, "Programs\\nodejs\\node.exe");
|
|
38365
|
+
patterns.push("C:\\Program Files\\nodejs\\node.exe", "C:\\Program Files (x86)\\nodejs\\node.exe");
|
|
38366
|
+
return patterns;
|
|
38367
|
+
}
|
|
38329
38368
|
function isOwnershipTrusted(candidate) {
|
|
38330
38369
|
const getuid = process.getuid;
|
|
38331
38370
|
if (typeof getuid !== "function") return true;
|
|
@@ -38336,8 +38375,22 @@ function isOwnershipTrusted(candidate) {
|
|
|
38336
38375
|
return false;
|
|
38337
38376
|
}
|
|
38338
38377
|
}
|
|
38378
|
+
function isWindowsTrusted(candidate, env) {
|
|
38379
|
+
let resolved;
|
|
38380
|
+
try {
|
|
38381
|
+
resolved = pathWin32.resolve(realpathSync(candidate));
|
|
38382
|
+
} catch {
|
|
38383
|
+
resolved = pathWin32.resolve(candidate);
|
|
38384
|
+
}
|
|
38385
|
+
const target = resolved.toLowerCase();
|
|
38386
|
+
for (const root of windowsAllowlistRoots(env)) {
|
|
38387
|
+
const base = pathWin32.resolve(root).toLowerCase();
|
|
38388
|
+
if (target === base || target.startsWith(base + pathWin32.sep)) return true;
|
|
38389
|
+
}
|
|
38390
|
+
return false;
|
|
38391
|
+
}
|
|
38339
38392
|
function expandSingleStarGlob(pattern) {
|
|
38340
|
-
const parts = pattern.split(
|
|
38393
|
+
const parts = pattern.split(/[\\/]/);
|
|
38341
38394
|
const starIdx = parts.findIndex((p19) => p19.includes("*"));
|
|
38342
38395
|
if (starIdx === -1) {
|
|
38343
38396
|
return existsSync(pattern) ? [pattern] : [];
|
|
@@ -38371,16 +38424,23 @@ function probeNodeVersion(candidate) {
|
|
|
38371
38424
|
return null;
|
|
38372
38425
|
}
|
|
38373
38426
|
}
|
|
38374
|
-
function
|
|
38427
|
+
function isAcceptedCandidatePath(candidate, platform = process.platform) {
|
|
38428
|
+
if (platform === "win32") {
|
|
38429
|
+
return pathWin32.isAbsolute(candidate) && (/^[A-Za-z]:[\\/]/.test(candidate) || candidate.startsWith("\\\\"));
|
|
38430
|
+
}
|
|
38431
|
+
return candidate.startsWith("/");
|
|
38432
|
+
}
|
|
38433
|
+
function discoverCompatibleNode(env = process.env, platform = process.platform) {
|
|
38375
38434
|
const seen = /* @__PURE__ */ new Set();
|
|
38376
38435
|
let best = null;
|
|
38377
|
-
for (const pattern of allowlistPatterns(env)) {
|
|
38436
|
+
for (const pattern of allowlistPatterns(env, platform)) {
|
|
38378
38437
|
for (const candidate of expandSingleStarGlob(pattern)) {
|
|
38379
|
-
if (!candidate
|
|
38438
|
+
if (!isAcceptedCandidatePath(candidate, platform)) continue;
|
|
38380
38439
|
if (seen.has(candidate)) continue;
|
|
38381
38440
|
seen.add(candidate);
|
|
38382
38441
|
if (!existsSync(candidate)) continue;
|
|
38383
|
-
|
|
38442
|
+
const trusted = platform === "win32" ? isWindowsTrusted(candidate, env) : isOwnershipTrusted(candidate);
|
|
38443
|
+
if (!trusted) continue;
|
|
38384
38444
|
const v3 = probeNodeVersion(candidate);
|
|
38385
38445
|
if (!v3) continue;
|
|
38386
38446
|
if (!checkNodeVersion(`v${v3}`).ok) continue;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@massu/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.2.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AI Engineering Governance MCP Server - Session memory, knowledge system, feature registry, code intelligence, rule enforcement, tiered tooling (12 free / 73 total), 56 workflow commands, 11 agents, 20+ patterns",
|
|
6
6
|
"main": "./dist/cli.js",
|