2026-04-21 03:35:45 +00:00
|
|
|
#!/usr/bin/env node
|
|
|
|
|
|
|
|
|
|
import { mkdir, readFile, stat, copyFile } from "node:fs/promises";
|
|
|
|
|
import path from "node:path";
|
|
|
|
|
import process from "node:process";
|
|
|
|
|
import { fileURLToPath } from "node:url";
|
|
|
|
|
|
|
|
|
|
const __filename = fileURLToPath(import.meta.url);
|
|
|
|
|
const __dirname = path.dirname(__filename);
|
|
|
|
|
const repoRoot = path.resolve(__dirname, "..");
|
|
|
|
|
const shippedArtifacts = ["main.js", "manifest.json", "styles.css"];
|
|
|
|
|
|
|
|
|
|
function printUsage() {
|
2026-05-13 18:44:11 +00:00
|
|
|
console.error("Usage: node scripts/install-built-plugin.mjs --vault \"/path/to/vault\" [--plugin-id aside]");
|
2026-04-21 03:35:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function parseArgs(argv) {
|
|
|
|
|
let vaultPath = "";
|
|
|
|
|
let pluginId = "";
|
|
|
|
|
|
|
|
|
|
for (let index = 0; index < argv.length; index += 1) {
|
|
|
|
|
const arg = argv[index];
|
|
|
|
|
if (arg === "--vault") {
|
|
|
|
|
vaultPath = argv[index + 1] ?? "";
|
|
|
|
|
index += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (arg === "--plugin-id") {
|
|
|
|
|
pluginId = argv[index + 1] ?? "";
|
|
|
|
|
index += 1;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (arg === "--help" || arg === "-h") {
|
|
|
|
|
printUsage();
|
|
|
|
|
process.exit(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw new Error(`Unknown argument: ${arg}`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!vaultPath) {
|
|
|
|
|
throw new Error("Missing required --vault argument.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
vaultPath: path.resolve(vaultPath),
|
|
|
|
|
pluginId: pluginId.trim(),
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function resolvePluginId(explicitPluginId) {
|
|
|
|
|
if (explicitPluginId) {
|
|
|
|
|
return explicitPluginId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const manifestPath = path.join(repoRoot, "manifest.json");
|
|
|
|
|
const manifest = JSON.parse(await readFile(manifestPath, "utf8"));
|
|
|
|
|
if (!manifest?.id || typeof manifest.id !== "string") {
|
|
|
|
|
throw new Error("manifest.json is missing a valid plugin id.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return manifest.id.trim();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function ensureDirectoryExists(directoryPath, description) {
|
|
|
|
|
try {
|
|
|
|
|
const target = await stat(directoryPath);
|
|
|
|
|
if (!target.isDirectory()) {
|
|
|
|
|
throw new Error(`${description} exists but is not a directory: ${directoryPath}`);
|
|
|
|
|
}
|
|
|
|
|
} catch (error) {
|
|
|
|
|
if (error && typeof error === "object" && "code" in error && error.code === "ENOENT") {
|
|
|
|
|
throw new Error(`${description} does not exist: ${directoryPath}`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw error;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function ensureArtifactsExist() {
|
|
|
|
|
for (const artifact of shippedArtifacts) {
|
|
|
|
|
const artifactPath = path.join(repoRoot, artifact);
|
|
|
|
|
try {
|
|
|
|
|
const target = await stat(artifactPath);
|
|
|
|
|
if (!target.isFile()) {
|
|
|
|
|
throw new Error();
|
|
|
|
|
}
|
|
|
|
|
} catch {
|
|
|
|
|
throw new Error(`Missing built artifact: ${artifactPath}. Run npm run build first.`);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function main() {
|
|
|
|
|
const options = parseArgs(process.argv.slice(2));
|
|
|
|
|
const pluginId = await resolvePluginId(options.pluginId);
|
|
|
|
|
|
|
|
|
|
await ensureDirectoryExists(options.vaultPath, "Vault path");
|
|
|
|
|
await ensureArtifactsExist();
|
|
|
|
|
|
|
|
|
|
const pluginsRoot = path.join(options.vaultPath, ".obsidian", "plugins");
|
|
|
|
|
const targetPluginDir = path.join(pluginsRoot, pluginId);
|
|
|
|
|
|
|
|
|
|
await mkdir(targetPluginDir, { recursive: true });
|
|
|
|
|
|
|
|
|
|
for (const artifact of shippedArtifacts) {
|
|
|
|
|
await copyFile(
|
|
|
|
|
path.join(repoRoot, artifact),
|
|
|
|
|
path.join(targetPluginDir, artifact),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.log(`Installed ${pluginId} build into ${targetPluginDir}`);
|
|
|
|
|
console.log("Copied: main.js, manifest.json, styles.css");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
await main().catch((error) => {
|
|
|
|
|
const message = error instanceof Error ? error.message : String(error);
|
|
|
|
|
console.error(message);
|
|
|
|
|
printUsage();
|
|
|
|
|
process.exit(1);
|
|
|
|
|
});
|