Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@avcodes/skilled

Package Overview
Dependencies
Maintainers
1
Versions
5
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@avcodes/skilled - npm Package Compare versions

Comparing version
0.3.0
to
0.3.1
+84
-14
install.js

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

function rmrf(dir) {
if (fs.rmSync) {
fs.rmSync(dir, { recursive: true, force: true });
} else if (fs.existsSync(dir)) {
fs.rmdirSync(dir, { recursive: true });
}
}
const REPO = "av/skilled";

@@ -45,2 +53,20 @@ const BINARY = "skilled";

if (platform === "darwin" && arch === "amd64") {
throw new Error(
"Intel Mac (darwin-amd64) prebuilt binaries are not available.\n" +
"Options:\n" +
" - Use an Apple Silicon Mac (arm64)\n" +
" - Install from source: git clone https://github.com/av/skilled && cd skilled && bun run build"
);
}
if (platform === "windows" && arch === "arm64") {
throw new Error(
"Windows ARM64 prebuilt binaries are not available.\n" +
"Options:\n" +
" - Use Windows x64 (the x64 binary runs on ARM64 via emulation)\n" +
" - Install from source: git clone https://github.com/av/skilled && cd skilled && bun run build"
);
}
const artifact = `${BINARY}-${platform}-${arch}`;

@@ -51,8 +77,12 @@ const ext = platform === "windows" ? "zip" : "tar.gz";

function followRedirects(url) {
function followRedirects(url, maxRedirects = 10) {
return new Promise((resolve, reject) => {
if (maxRedirects <= 0) {
reject(new Error("Too many redirects (exceeded limit of 10)"));
return;
}
https
.get(url, { headers: { "User-Agent": "skilled-npm" } }, (res) => {
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
followRedirects(res.headers.location).then(resolve, reject);
followRedirects(res.headers.location, maxRedirects - 1).then(resolve, reject);
} else if (res.statusCode === 200) {

@@ -71,14 +101,31 @@ resolve(res);

if (platform === "windows") {
const zipPath = path.join(destDir, "download.zip");
const fileStream = fs.createWriteStream(zipPath);
await pipelineAsync(res, fileStream);
execSync(`tar -xf "${zipPath}" -C "${destDir}"`);
fs.unlinkSync(zipPath);
} else {
const tarPath = path.join(destDir, "download.tar.gz");
const fileStream = fs.createWriteStream(tarPath);
await pipelineAsync(res, fileStream);
execSync(`tar xzf "${tarPath}" -C "${destDir}"`);
fs.unlinkSync(tarPath);
// Extract into a temp directory first to avoid leaving corrupted binaries
// on partial failure (network drop, disk full, corrupt archive).
const tmpDir = destDir + ".tmp";
rmrf(tmpDir);
fs.mkdirSync(tmpDir, { recursive: true });
try {
if (platform === "windows") {
const zipPath = path.join(tmpDir, "download.zip");
const fileStream = fs.createWriteStream(zipPath);
await pipelineAsync(res, fileStream);
execSync(`tar -xf "${zipPath}" -C "${tmpDir}"`);
fs.unlinkSync(zipPath);
} else {
const tarPath = path.join(tmpDir, "download.tar.gz");
const fileStream = fs.createWriteStream(tarPath);
await pipelineAsync(res, fileStream);
execSync(`tar xzf "${tarPath}" -C "${tmpDir}"`);
fs.unlinkSync(tarPath);
}
// Move extracted files to final destination only after successful extraction
const files = fs.readdirSync(tmpDir);
for (const file of files) {
fs.renameSync(path.join(tmpDir, file), path.join(destDir, file));
}
} finally {
// Clean up temp directory regardless of success/failure
rmrf(tmpDir);
}

@@ -119,3 +166,26 @@ }

}
} else {
// On Windows, npm's bin shim runs `node bin/skilled` which hits the stub script.
// The actual binary is `bin/skilled.exe`. Replace the stub with a launcher that
// spawns the .exe, passing through args, stdio, and exit code.
const launcherScript = `#!/usr/bin/env node
"use strict";
var cp = require("child_process");
var path = require("path");
var exe = path.join(__dirname, "${BINARY}.exe");
var r = cp.spawnSync(exe, process.argv.slice(2), { stdio: "inherit" });
if (r.error) {
if (r.error.code === "ENOENT") {
console.error("${BINARY}: binary not found at " + exe);
console.error("Run 'npm rebuild @avcodes/${BINARY}' or reinstall.");
} else {
console.error("${BINARY}: " + r.error.message);
}
process.exit(1);
}
process.exit(r.status !== null ? r.status : 1);
`;
const launcherPath = path.join(binDir, BINARY);
fs.writeFileSync(launcherPath, launcherScript, { mode: 0o755 });
}

@@ -122,0 +192,0 @@ console.log(`Successfully installed ${BINARY} to ${binaryPath}`);

+1
-1
{
"name": "@avcodes/skilled",
"version": "0.3.0",
"version": "0.3.1",
"description": "TUI dashboard for skill usage stats across AI coding tools",

@@ -5,0 +5,0 @@ "license": "MIT",