@zenitheditor/zenith-mcp 0.0.3

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/bin/zenith.js ADDED
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawnSync } = require("node:child_process");
4
+ const fs = require("node:fs");
5
+ const path = require("node:path");
6
+
7
+ const root = path.resolve(__dirname, "..");
8
+ const exe = process.platform === "win32" ? "zenith.exe" : "zenith";
9
+ const binPath = path.join(root, "vendor", exe);
10
+
11
+ if (!fs.existsSync(binPath)) {
12
+ const { install } = require("../scripts/install");
13
+ install({ root });
14
+ }
15
+
16
+ const args = process.argv.length > 2 ? process.argv.slice(2) : ["mcp"];
17
+ const result = spawnSync(binPath, args, { stdio: "inherit" });
18
+
19
+ if (result.error) {
20
+ console.error(result.error.message);
21
+ process.exit(1);
22
+ }
23
+
24
+ process.exit(result.status === null ? 1 : result.status);
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@zenitheditor/zenith-mcp",
3
+ "version": "0.0.3",
4
+ "description": "MCP launcher for the Zenith deterministic .zen design engine.",
5
+ "license": "Apache-2.0",
6
+ "homepage": "https://github.com/zenitheditor/zenith#readme",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/zenitheditor/zenith.git",
10
+ "directory": "npm/zenith-mcp"
11
+ },
12
+ "bugs": {
13
+ "url": "https://github.com/zenitheditor/zenith/issues"
14
+ },
15
+ "mcpName": "io.github.zenitheditor/zenith",
16
+ "bin": {
17
+ "zenith-mcp": "bin/zenith.js"
18
+ },
19
+ "scripts": {
20
+ "postinstall": "node scripts/postinstall.js"
21
+ },
22
+ "files": [
23
+ "bin/",
24
+ "scripts/",
25
+ "vendor/"
26
+ ],
27
+ "engines": {
28
+ "node": ">=18"
29
+ }
30
+ }
@@ -0,0 +1,95 @@
1
+ const { execFileSync } = require("node:child_process");
2
+ const fs = require("node:fs");
3
+ const os = require("node:os");
4
+ const path = require("node:path");
5
+
6
+ const REPO = "zenitheditor/zenith";
7
+
8
+ function platformTarget() {
9
+ const arch = os.arch();
10
+
11
+ if (process.platform === "linux") {
12
+ if (arch === "x64") return { label: "linux-x64", archive: "tar.gz", exe: "zenith" };
13
+ if (arch === "arm64") return { label: "linux-arm64", archive: "tar.gz", exe: "zenith" };
14
+ }
15
+
16
+ if (process.platform === "darwin") {
17
+ if (arch === "x64") return { label: "macos-x64", archive: "tar.gz", exe: "zenith" };
18
+ if (arch === "arm64") return { label: "macos-arm64", archive: "tar.gz", exe: "zenith" };
19
+ }
20
+
21
+ if (process.platform === "win32" && arch === "x64") {
22
+ return { label: "windows-x64", archive: "zip", exe: "zenith.exe" };
23
+ }
24
+
25
+ throw new Error(`unsupported platform: ${process.platform}-${arch}`);
26
+ }
27
+
28
+ function packageVersion(root) {
29
+ const pkg = JSON.parse(fs.readFileSync(path.join(root, "package.json"), "utf8"));
30
+ return pkg.version;
31
+ }
32
+
33
+ function extract(archivePath, archiveType, tmpDir) {
34
+ if (archiveType === "zip") {
35
+ if (process.platform === "win32") {
36
+ execFileSync(
37
+ "powershell.exe",
38
+ [
39
+ "-NoProfile",
40
+ "-ExecutionPolicy",
41
+ "Bypass",
42
+ "-Command",
43
+ `Expand-Archive -LiteralPath ${JSON.stringify(archivePath)} -DestinationPath ${JSON.stringify(tmpDir)} -Force`,
44
+ ],
45
+ { stdio: "inherit" }
46
+ );
47
+ return;
48
+ }
49
+
50
+ execFileSync("unzip", ["-oq", archivePath, "-d", tmpDir], { stdio: "inherit" });
51
+ return;
52
+ }
53
+
54
+ execFileSync("tar", ["xzf", archivePath, "-C", tmpDir], { stdio: "inherit" });
55
+ }
56
+
57
+ function install(options = {}) {
58
+ if (process.env.ZENITH_NPM_SKIP_DOWNLOAD === "1") {
59
+ return;
60
+ }
61
+
62
+ const root = options.root || path.resolve(__dirname, "..");
63
+ const vendorDir = path.join(root, "vendor");
64
+ const target = platformTarget();
65
+ const version = packageVersion(root);
66
+ const archiveName = `zenith-${version}-${target.label}.${target.archive}`;
67
+ const url = `https://github.com/${REPO}/releases/download/v${version}/${archiveName}`;
68
+ const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "zenith-npm-"));
69
+ const archivePath = path.join(tmpDir, archiveName);
70
+ const outPath = path.join(vendorDir, target.exe);
71
+
72
+ fs.mkdirSync(vendorDir, { recursive: true });
73
+
74
+ try {
75
+ console.log(`Downloading Zenith ${version} (${target.label})...`);
76
+ execFileSync(process.execPath, [path.join(__dirname, "postinstall-download.js"), url, archivePath], {
77
+ stdio: "inherit",
78
+ });
79
+ extract(archivePath, target.archive, tmpDir);
80
+
81
+ const extracted = path.join(tmpDir, target.exe);
82
+ if (!fs.existsSync(extracted)) {
83
+ throw new Error(`archive did not contain ${target.exe}`);
84
+ }
85
+
86
+ fs.copyFileSync(extracted, outPath);
87
+ if (process.platform !== "win32") {
88
+ fs.chmodSync(outPath, 0o755);
89
+ }
90
+ } finally {
91
+ fs.rmSync(tmpDir, { recursive: true, force: true });
92
+ }
93
+ }
94
+
95
+ module.exports = { install };
@@ -0,0 +1,8 @@
1
+ const { download } = require("./util");
2
+
3
+ const [url, dest] = process.argv.slice(2);
4
+
5
+ download(url, dest).catch((error) => {
6
+ console.error(error.message);
7
+ process.exit(1);
8
+ });
@@ -0,0 +1,4 @@
1
+ const path = require("node:path");
2
+ const { install } = require("./install");
3
+
4
+ install({ root: path.resolve(__dirname, "..") });
@@ -0,0 +1,41 @@
1
+ const fs = require("node:fs");
2
+ const https = require("node:https");
3
+
4
+ function download(url, dest) {
5
+ return new Promise((resolve, reject) => {
6
+ const request = https.get(
7
+ url,
8
+ {
9
+ headers: {
10
+ "User-Agent": "@zenitheditor/zenith-mcp npm installer",
11
+ },
12
+ },
13
+ (response) => {
14
+ if (
15
+ response.statusCode >= 300 &&
16
+ response.statusCode < 400 &&
17
+ response.headers.location
18
+ ) {
19
+ response.resume();
20
+ download(response.headers.location, dest).then(resolve, reject);
21
+ return;
22
+ }
23
+
24
+ if (response.statusCode !== 200) {
25
+ response.resume();
26
+ reject(new Error(`download failed (${response.statusCode}): ${url}`));
27
+ return;
28
+ }
29
+
30
+ const file = fs.createWriteStream(dest, { mode: 0o755 });
31
+ response.pipe(file);
32
+ file.on("finish", () => file.close(resolve));
33
+ file.on("error", reject);
34
+ }
35
+ );
36
+
37
+ request.on("error", reject);
38
+ });
39
+ }
40
+
41
+ module.exports = { download };