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

@abdoknbgit/tau-installer

Package Overview
Dependencies
Maintainers
1
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@abdoknbgit/tau-installer - npm Package Compare versions

Comparing version
0.1.1
to
0.1.2
+552
-71
lib/installer.mjs
import { spawn } from "node:child_process";
import { randomUUID } from "node:crypto";
import {
existsSync,
fstatSync,
linkSync,
lstatSync,
mkdirSync,
openSync,
readFileSync,
readdirSync,
readlinkSync,
renameSync,
rmdirSync,
closeSync,
unlinkSync,
utimesSync,
writeFileSync,
} from "node:fs";

@@ -29,2 +40,6 @@ import { homedir } from "node:os";

const TERMINATION_GRACE_MS = 5_000;
const UPDATE_LOCK_STALE_MS = 15 * 60 * 1000;
const UPDATE_LOCK_HEARTBEAT_MS = 60 * 1000;
const LOCK_OWNER_PATTERN = /^owner-[0-9a-f-]{36}\.lease$/i;
export const INSTALLER_LOCK_CONTENDED_EXIT_CODE = 75;

@@ -169,2 +184,393 @@ const EXACT_SEMVER_PATTERN =

function errnoCode(error) {
return error && typeof error === "object" && typeof error.code === "string"
? error.code
: undefined;
}
function isMissing(error) {
return errnoCode(error) === "ENOENT";
}
function isContended(error) {
return ["EEXIST", "ENOTEMPTY", "EACCES", "EPERM"].includes(errnoCode(error));
}
function sameFile(left, right) {
if (left.dev !== 0 || left.ino !== 0 || right.dev !== 0 || right.ino !== 0) {
return left.dev === right.dev && left.ino === right.ino;
}
return (
left.birthtimeMs === right.birthtimeMs &&
left.mtimeMs === right.mtimeMs &&
left.size === right.size &&
left.mode === right.mode
);
}
function defaultProcessIsAlive(pid, processKillImpl = process.kill) {
if (!Number.isSafeInteger(pid) || pid <= 0) return false;
try {
processKillImpl(pid, 0);
return true;
} catch (error) {
if (errnoCode(error) === "ESRCH") return false;
// EPERM proves the process exists. Unknown probe errors fail closed too.
return true;
}
}
function readOwnerPid(path) {
try {
const parsed = JSON.parse(readFileSync(path, "utf8"));
return Number.isSafeInteger(parsed?.pid) && parsed.pid > 0 ? parsed.pid : null;
} catch (error) {
if (isMissing(error) || error instanceof SyntaxError) return null;
throw error;
}
}
function readLegacyOwnerPid(path) {
try {
const value = readFileSync(path, "utf8").trim();
if (!/^\d+$/.test(value)) return null;
const pid = Number(value);
return Number.isSafeInteger(pid) && pid > 0 ? pid : null;
} catch (error) {
if (isMissing(error)) return null;
throw error;
}
}
function removeEmptyDirectory(path) {
try {
rmdirSync(path);
return true;
} catch (error) {
if (isMissing(error)) return true;
if (isContended(error)) return false;
throw error;
}
}
function tryCreateLease(lockPath, { now, pid, randomUUIDImpl }) {
const token = randomUUIDImpl();
const leasePath = join(lockPath, `owner-${token}.lease`);
const createDirectory = () => {
try {
mkdirSync(lockPath);
return true;
} catch (error) {
if (errnoCode(error) === "EEXIST") return false;
throw error;
}
};
let created;
try {
created = createDirectory();
} catch (error) {
if (!isMissing(error)) throw error;
mkdirSync(dirname(lockPath), { recursive: true });
created = createDirectory();
}
if (!created) return null;
try {
writeFileSync(
leasePath,
JSON.stringify({ token, pid, acquiredAt: now() }),
{ encoding: "utf8", flag: "wx" },
);
return { lockPath, token, pid, leasePath, borrowed: false };
} catch (error) {
try {
rmdirSync(lockPath);
} catch {
// A replacement owner makes the directory non-empty and preserves it.
}
if (isMissing(error) || isContended(error)) return null;
throw error;
}
}
function recoverLeaseDirectory(
lockPath,
observedDirectory,
{ now, staleMs, isProcessAliveImpl },
) {
let entries;
try {
entries = readdirSync(lockPath, { withFileTypes: true });
} catch (error) {
if (isMissing(error)) return true;
throw error;
}
if (entries.length === 0) {
let recheck;
try {
recheck = lstatSync(lockPath);
} catch (error) {
if (isMissing(error)) return true;
throw error;
}
if (
!recheck.isDirectory() ||
!sameFile(observedDirectory, recheck) ||
now() - recheck.mtimeMs < staleMs
) {
return false;
}
return removeEmptyDirectory(lockPath);
}
const staleOwners = [];
for (const entry of entries) {
if (!entry.isFile() || !LOCK_OWNER_PATTERN.test(entry.name)) return false;
const path = join(lockPath, entry.name);
let stats;
try {
stats = lstatSync(path);
} catch (error) {
if (isMissing(error)) continue;
throw error;
}
if (!stats.isFile() || now() - stats.mtimeMs < staleMs) return false;
const ownerPid = readOwnerPid(path);
if (ownerPid && isProcessAliveImpl(ownerPid)) return false;
staleOwners.push({ path, stats });
}
for (const stale of staleOwners) {
let recheck;
try {
recheck = lstatSync(stale.path);
} catch (error) {
if (isMissing(error)) continue;
throw error;
}
if (
!recheck.isFile() ||
!sameFile(stale.stats, recheck) ||
now() - recheck.mtimeMs < staleMs
) {
return false;
}
const ownerPid = readOwnerPid(stale.path);
if (ownerPid && isProcessAliveImpl(ownerPid)) return false;
try {
unlinkSync(stale.path);
} catch (error) {
if (!isMissing(error)) throw error;
}
}
return removeEmptyDirectory(lockPath);
}
function restoreQuarantinedLegacyLock(quarantine, lockPath) {
try {
linkSync(quarantine, lockPath);
unlinkSync(quarantine);
} catch {
// Preserve an identity that could not be restored or verified.
}
}
function recoverLegacyLock(
lockPath,
observed,
{ now, staleMs, isProcessAliveImpl, randomUUIDImpl },
) {
if (now() - observed.mtimeMs < staleMs) return false;
const ownerPid = readLegacyOwnerPid(lockPath);
if (ownerPid && isProcessAliveImpl(ownerPid)) return false;
const quarantine = `${lockPath}.legacy-stale-${randomUUIDImpl()}`;
let handle;
try {
handle = openSync(lockPath, "r");
const opened = fstatSync(handle);
const recheck = lstatSync(lockPath);
if (
!recheck.isFile() ||
!sameFile(observed, opened) ||
!sameFile(opened, recheck) ||
now() - recheck.mtimeMs < staleMs
) {
return false;
}
const recheckedPid = readLegacyOwnerPid(lockPath);
if (recheckedPid && isProcessAliveImpl(recheckedPid)) return false;
renameSync(lockPath, quarantine);
const moved = lstatSync(quarantine);
if (!moved.isFile() || !sameFile(opened, moved)) {
restoreQuarantinedLegacyLock(quarantine, lockPath);
return false;
}
} catch (error) {
if (isMissing(error)) return true;
throw error;
} finally {
if (handle !== undefined) closeSync(handle);
}
unlinkSync(quarantine);
return true;
}
function acquireDirectoryLease(lockPath, options) {
const fresh = tryCreateLease(lockPath, options);
if (fresh) return fresh;
let observed;
try {
observed = lstatSync(lockPath);
} catch (error) {
if (isMissing(error)) return tryCreateLease(lockPath, options);
throw error;
}
if (!observed.isDirectory()) return null;
return recoverLeaseDirectory(lockPath, observed, options)
? tryCreateLease(lockPath, options)
: null;
}
function acquireMainLease(lockPath, options) {
const fresh = tryCreateLease(lockPath, options);
if (fresh) return fresh;
let observed;
try {
observed = lstatSync(lockPath);
} catch (error) {
if (isMissing(error)) return tryCreateLease(lockPath, options);
throw error;
}
const recovered = observed.isDirectory()
? recoverLeaseDirectory(lockPath, observed, options)
: observed.isFile()
? recoverLegacyLock(lockPath, observed, options)
: false;
return recovered ? tryCreateLease(lockPath, options) : null;
}
function readBorrowedLease(env, platform, isProcessAliveImpl) {
const path = env.TAU_UPDATE_LOCK_PATH;
const token = env.TAU_UPDATE_LOCK_TOKEN;
const pidText = env.TAU_UPDATE_LOCK_PID;
const supplied = [path, token, pidText].filter((value) => value !== undefined).length;
if (supplied === 0) return { status: "none" };
if (supplied !== 3 || !LOCK_OWNER_PATTERN.test(`owner-${token}.lease`)) {
return { status: "invalid" };
}
const pid = /^\d+$/.test(pidText) ? Number(pidText) : NaN;
const pathIsAbsolute = platform === "win32" ? win32.isAbsolute(path) : posix.isAbsolute(path);
if (
!Number.isSafeInteger(pid) ||
pid <= 0 ||
!pathIsAbsolute
) {
return { status: "invalid" };
}
const leasePath = join(path, `owner-${token}.lease`);
try {
const lockStats = lstatSync(path);
const leaseStats = lstatSync(leasePath);
const contents = JSON.parse(readFileSync(leasePath, "utf8"));
if (
!lockStats.isDirectory() ||
!leaseStats.isFile() ||
contents?.token !== token ||
contents?.pid !== pid ||
!isProcessAliveImpl(pid)
) {
return { status: "invalid" };
}
} catch {
return { status: "invalid" };
}
return {
status: "borrowed",
lease: { lockPath: path, token, pid, leasePath, borrowed: true },
};
}
export function getInstallerUpdateLockPath(
env = process.env,
workingDirectory = homedir(),
) {
const configured = env.CLAUDE_CONFIG_DIR?.trim();
const configHome = configured ? resolve(configured) : join(resolve(workingDirectory), ".claude");
return join(configHome, ".update.lock");
}
/** Acquire the shared global-update lease, or validate an outer updater handoff. */
export function acquireInstallerUpdateLease({
env = process.env,
lockPath = getInstallerUpdateLockPath(env),
platform = process.platform,
staleMs = UPDATE_LOCK_STALE_MS,
now = Date.now,
pid = process.pid,
randomUUIDImpl = randomUUID,
isProcessAliveImpl = defaultProcessIsAlive,
} = {}) {
const borrowed = readBorrowedLease(env, platform, isProcessAliveImpl);
if (borrowed.status !== "none") return borrowed;
const options = { now, pid, randomUUIDImpl, staleMs, isProcessAliveImpl };
const gate = acquireDirectoryLease(`${lockPath}.acquire`, options);
if (!gate) return { status: "contended" };
try {
const lease = acquireMainLease(lockPath, options);
return lease ? { status: "acquired", lease } : { status: "contended" };
} finally {
releaseInstallerUpdateLease(gate);
}
}
export function getInstallerLeaseEnvironment(lease) {
return {
TAU_UPDATE_LOCK_PATH: lease.lockPath,
TAU_UPDATE_LOCK_TOKEN: lease.token,
TAU_UPDATE_LOCK_PID: String(lease.pid),
};
}
export function releaseInstallerUpdateLease(lease) {
if (!lease || lease.borrowed) return;
try {
unlinkSync(lease.leasePath);
} catch (error) {
if (!isMissing(error)) throw error;
}
removeEmptyDirectory(lease.lockPath);
}
function startInstallerLeaseHeartbeat(
lease,
{
heartbeatMs = UPDATE_LOCK_HEARTBEAT_MS,
setIntervalImpl = setInterval,
clearIntervalImpl = clearInterval,
onError = () => {},
} = {},
) {
if (lease.borrowed) return () => {};
const timer = setIntervalImpl(() => {
try {
const now = new Date();
utimesSync(lease.leasePath, now, now);
} catch (error) {
if (!isMissing(error)) onError(error);
}
}, heartbeatMs);
timer.unref?.();
return () => clearIntervalImpl(timer);
}
function getEmbeddedLauncherTargets(launcherPath, content) {

@@ -236,8 +642,13 @@ const quotedTargets = [

export function resolveWindowsTaskkillPath(env = process.env) {
const configuredRoot = env.SystemRoot?.trim() || env.WINDIR?.trim();
const windowsRoot =
configuredRoot && win32.isAbsolute(configuredRoot)
? configuredRoot
: "C:\\Windows";
return win32.join(windowsRoot, "System32", "taskkill.exe");
for (const value of [env.SystemRoot, env.WINDIR]) {
const windowsRoot = value?.trim();
if (
windowsRoot &&
win32.isAbsolute(windowsRoot) &&
!/[\0\r\n]/.test(windowsRoot)
) {
return win32.join(windowsRoot, "System32", "taskkill.exe");
}
}
return null;
}

@@ -346,2 +757,7 @@

const command = resolveWindowsTaskkillPath(env);
// A missing/invalid SystemRoot is safer than guessing an OS drive or
// resolving a potentially shadowed taskkill.exe from PATH. Fall back to
// terminating npm directly; the next run's integrity repair handles any
// descendants that outlive it.
if (!command) return false;
const args = ["/PID", String(child.pid), "/T", ...(force ? ["/F"] : [])];

@@ -361,6 +777,28 @@ let killer;

let killerSettled = false;
let fallbackStarted = false;
const fallbackToDirectKill = (message) => {
// child_process can report both `error` and `close`. A failed taskkill
// must forward the fallback signal exactly once for this attempt.
if (fallbackStarted) return;
fallbackStarted = true;
stderr.write(`Unable to terminate npm's process tree: ${message}\n`);
killDirectly(fallbackSignal);
};
killer.once?.("error", (error) => {
stderr.write(`Unable to terminate npm's process tree: ${error.message}\n`);
killDirectly(fallbackSignal);
if (killerSettled) return;
killerSettled = true;
fallbackToDirectKill(error.message);
});
killer.once?.("close", (code, signal) => {
if (killerSettled) return;
killerSettled = true;
if (code === 0) return;
fallbackToDirectKill(
Number.isInteger(code)
? `taskkill exited with code ${code}`
: `taskkill exited via ${signal ?? "an unknown failure"}`,
);
});
return true;

@@ -720,3 +1158,7 @@ };

clearTimeoutImpl = clearTimeout,
setIntervalImpl = setInterval,
clearIntervalImpl = clearInterval,
workingDirectory = homedir(),
lockPath,
isProcessAliveImpl = (pid) => defaultProcessIsAlive(pid, processKillImpl),
stdout = process.stdout,

@@ -752,76 +1194,115 @@ stderr = process.stderr,

const globalPrefix = await detectGlobalPrefix(invocation, {
env: childEnv,
platform,
spawnImpl,
workingDirectory,
});
if (!globalPrefix) {
stderr.write("Unable to determine npm's global prefix safely.\n");
const expectedLockPath = lockPath ?? getInstallerUpdateLockPath(env, workingDirectory);
let lockResult;
try {
lockResult = acquireInstallerUpdateLease({
env,
lockPath: expectedLockPath,
platform,
isProcessAliveImpl,
});
} catch (error) {
stderr.write(`Unable to acquire Tau's update lock: ${error.message}\n`);
return 1;
}
if (lockResult.status === "invalid") {
stderr.write("Tau received an invalid update-lock handoff and refused to continue.\n");
return 1;
}
if (lockResult.status === "contended") {
stderr.write("Another Tau installation or update is already in progress.\n");
return INSTALLER_LOCK_CONTENDED_EXIT_CODE;
}
const binDirectory =
platform === "win32" ? globalPrefix : join(globalPrefix, "bin");
cleanDanglingLaunchers(binDirectory, { platform });
const lease = lockResult.lease;
Object.assign(childEnv, getInstallerLeaseEnvironment(lease));
const stopLockHeartbeat = startInstallerLeaseHeartbeat(lease, {
setIntervalImpl,
clearIntervalImpl,
onError: (error) => stderr.write(`Unable to refresh Tau's update lock: ${error.message}\n`),
});
const commandOptions = {
env: childEnv,
platform,
processKillImpl,
spawnImpl,
treeKillSpawnImpl,
signalSource,
terminationGraceMs,
setTimeoutImpl,
clearTimeoutImpl,
workingDirectory,
stderr,
};
const installCode = await runForegroundNpmCommand(
invocation,
buildInstallArguments(tauVersion, npmVersionResult.version),
commandOptions,
);
if (installCode !== 0) return installCode;
try {
const globalPrefix = await detectGlobalPrefix(invocation, {
env: childEnv,
platform,
spawnImpl,
workingDirectory,
});
if (!globalPrefix) {
stderr.write("Unable to determine npm's global prefix safely.\n");
return 1;
}
const packageRoot = getGlobalTauPackageRoot(globalPrefix, platform);
let lifecycleStatus = getLifecycleMarkerStatus(packageRoot);
if (tauVersion && lifecycleStatus.version && lifecycleStatus.version !== tauVersion) {
stderr.write(
`npm reported success, but installed Tau ${lifecycleStatus.version} instead of ${tauVersion}.\n`,
const binDirectory =
platform === "win32" ? globalPrefix : join(globalPrefix, "bin");
cleanDanglingLaunchers(binDirectory, { platform });
const commandOptions = {
env: childEnv,
platform,
processKillImpl,
spawnImpl,
treeKillSpawnImpl,
signalSource,
terminationGraceMs,
setTimeoutImpl,
clearTimeoutImpl,
workingDirectory,
stderr,
};
const installCode = await runForegroundNpmCommand(
invocation,
buildInstallArguments(tauVersion, npmVersionResult.version),
commandOptions,
);
return 1;
}
if (lifecycleStatus.ok) return 0;
if (lifecycleStatus.reason === "manifest-missing" || lifecycleStatus.reason === "manifest-invalid") {
stderr.write("npm reported success, but the global Tau package is missing or invalid.\n");
return 1;
}
if (installCode !== 0) return installCode;
const dependencyPackages = ALLOWED_SCRIPTS.filter(
(packageName) => packageName !== TAU_PACKAGE,
);
const dependencyRebuildCode = await runForegroundNpmCommand(
invocation,
buildRebuildArguments(dependencyPackages, npmVersionResult.version),
commandOptions,
);
if (dependencyRebuildCode !== 0) return dependencyRebuildCode;
const packageRoot = getGlobalTauPackageRoot(globalPrefix, platform);
let lifecycleStatus = getLifecycleMarkerStatus(packageRoot);
if (tauVersion && lifecycleStatus.version && lifecycleStatus.version !== tauVersion) {
stderr.write(
`npm reported success, but installed Tau ${lifecycleStatus.version} instead of ${tauVersion}.\n`,
);
return 1;
}
if (lifecycleStatus.ok) return 0;
if (lifecycleStatus.reason === "manifest-missing" || lifecycleStatus.reason === "manifest-invalid") {
stderr.write("npm reported success, but the global Tau package is missing or invalid.\n");
return 1;
}
const tauRebuildCode = await runForegroundNpmCommand(
invocation,
buildRebuildArguments([TAU_PACKAGE], npmVersionResult.version),
commandOptions,
);
if (tauRebuildCode !== 0) return tauRebuildCode;
const dependencyPackages = ALLOWED_SCRIPTS.filter(
(packageName) => packageName !== TAU_PACKAGE,
);
const dependencyRebuildCode = await runForegroundNpmCommand(
invocation,
buildRebuildArguments(dependencyPackages, npmVersionResult.version),
commandOptions,
);
if (dependencyRebuildCode !== 0) return dependencyRebuildCode;
lifecycleStatus = getLifecycleMarkerStatus(packageRoot);
if (!lifecycleStatus.ok) {
stderr.write(
"Tau's lifecycle scripts did not produce a valid completion marker.\n",
const tauRebuildCode = await runForegroundNpmCommand(
invocation,
buildRebuildArguments([TAU_PACKAGE], npmVersionResult.version),
commandOptions,
);
return 1;
if (tauRebuildCode !== 0) return tauRebuildCode;
lifecycleStatus = getLifecycleMarkerStatus(packageRoot);
if (!lifecycleStatus.ok) {
stderr.write(
"Tau's lifecycle scripts did not produce a valid completion marker.\n",
);
return 1;
}
return 0;
} finally {
stopLockHeartbeat();
try {
releaseInstallerUpdateLease(lease);
} catch (error) {
stderr.write(`Unable to release Tau's update lock: ${error.message}\n`);
}
}
return 0;
}

@@ -828,0 +1309,0 @@

+1
-1
{
"name": "@abdoknbgit/tau-installer",
"version": "0.1.1",
"version": "0.1.2",
"description": "Install Tau globally with its reviewed npm lifecycle scripts allowed for this install only.",

@@ -5,0 +5,0 @@ "type": "module",