141 lines
3.7 KiB
JavaScript
Executable File
141 lines
3.7 KiB
JavaScript
Executable File
#!/usr/bin/env node
|
|
|
|
const debug = require('debug')('cli')
|
|
const https = require("https");
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const os = require("os");
|
|
const { URL } = require("url");
|
|
const yaml = require("yaml");
|
|
|
|
// === CLI PARSING ===
|
|
const rawArgs = process.argv.slice(2);
|
|
const asJSON = rawArgs.includes("--json");
|
|
const asMarkdown = rawArgs.includes("--markdown");
|
|
const query = rawArgs.find(arg => !arg.startsWith("--")) || null;
|
|
|
|
// === CONFIG SEARCH ===
|
|
function findTeaConfig() {
|
|
const xdg = process.env.XDG_CONFIG_HOME;
|
|
const home = os.homedir();
|
|
const platform = process.platform;
|
|
|
|
const paths = [];
|
|
|
|
if (xdg) paths.push(path.join(xdg, "tea", "config.yml"));
|
|
if (platform === "darwin") {
|
|
paths.push(path.join(home, "Library", "Application Support", "tea", "config.yml"));
|
|
} else {
|
|
paths.push(path.join(home, ".config", "tea", "config.yml"));
|
|
}
|
|
paths.push(path.join(home, ".tea", "tea.yml"));
|
|
|
|
for (const p of paths) {
|
|
if (fs.existsSync(p)) return p;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function loadGiteaLogin() {
|
|
const configPath = findTeaConfig();
|
|
if (!configPath) {
|
|
console.error("❌ Could not find tea config.yml or tea.yml");
|
|
process.exit(1);
|
|
}
|
|
|
|
const file = fs.readFileSync(configPath, "utf8");
|
|
const parsed = yaml.parse(file);
|
|
const logins = parsed.logins || [];
|
|
|
|
if (logins.length === 0) {
|
|
console.error("❌ No logins found in config");
|
|
process.exit(1);
|
|
}
|
|
|
|
const login = logins.find((l) => l.default) || logins[0];
|
|
|
|
debug(`🔧 Using config: ${configPath}`);
|
|
debug(`👤 Gitea user: ${login.user}`);
|
|
debug(`🌐 Gitea URL: ${login.url}`);
|
|
debug(`🔐 Auth token: ${login.token ? '[present]' : '[missing]'}`);
|
|
|
|
return {
|
|
baseUrl: login.url.replace(/\/$/, ""),
|
|
token: login.token,
|
|
user: login.user,
|
|
};
|
|
}
|
|
|
|
function fetchJSON(baseUrl, path, token) {
|
|
return new Promise((resolve, reject) => {
|
|
const url = new URL(path, baseUrl);
|
|
const options = {
|
|
headers: {
|
|
Authorization: `token ${token}`,
|
|
Accept: "application/json",
|
|
},
|
|
};
|
|
|
|
https.get(url, options, (res) => {
|
|
let body = "";
|
|
res.on("data", (chunk) => (body += chunk));
|
|
res.on("end", () => {
|
|
try {
|
|
const json = JSON.parse(body);
|
|
resolve(json);
|
|
} catch (err) {
|
|
reject(new Error("Failed to parse JSON: " + err.message));
|
|
}
|
|
});
|
|
}).on("error", reject);
|
|
});
|
|
}
|
|
|
|
function printPlain(packages) {
|
|
packages.forEach(pkg => {
|
|
console.log(`${pkg.name}@${pkg.version} — ${pkg.created_at}`);
|
|
});
|
|
}
|
|
|
|
function printMarkdown(packages) {
|
|
console.log(`| Package | Version | Created At |`);
|
|
console.log(`|---------|---------|------------|`);
|
|
packages.forEach(pkg => {
|
|
const name = `\`${pkg.name}\``;
|
|
const version = `\`${pkg.version}\``;
|
|
const created = new Date(pkg.created_at).toISOString().split("T")[0];
|
|
console.log(`| ${name} | ${version} | ${created} |`);
|
|
});
|
|
}
|
|
|
|
function printJSON(packages) {
|
|
console.log(JSON.stringify(packages, null, 2));
|
|
}
|
|
|
|
async function listPackages() {
|
|
const { baseUrl, token, user } = loadGiteaLogin();
|
|
|
|
const queryParams = new URLSearchParams({ type: "npm" });
|
|
if (query) queryParams.append("q", query);
|
|
|
|
const endpoint = `/api/v1/packages/${user}?${queryParams.toString()}`;
|
|
debug(`📦 Fetching from: ${baseUrl}${endpoint}`);
|
|
|
|
try {
|
|
const packages = await fetchJSON(baseUrl, endpoint, token);
|
|
if (!Array.isArray(packages)) throw new Error("Unexpected response");
|
|
|
|
if (asJSON) {
|
|
printJSON(packages);
|
|
} else if (asMarkdown) {
|
|
printMarkdown(packages);
|
|
} else {
|
|
printPlain(packages);
|
|
}
|
|
} catch (err) {
|
|
console.error("❌ Error:", err.message);
|
|
}
|
|
}
|
|
|
|
listPackages();
|