@pajamadot/pajama 0.1.1

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/README.md ADDED
@@ -0,0 +1,51 @@
1
+ # Pajama CLI (npm)
2
+
3
+ Install the `pajama` CLI via npm (recommended for end users):
4
+
5
+ ```bash
6
+ npm i -g @pajamadot/pajama
7
+ ```
8
+
9
+ Login (OAuth PKCE):
10
+
11
+ ```bash
12
+ pajama login
13
+ ```
14
+
15
+ If your environment cannot open a browser automatically:
16
+
17
+ ```bash
18
+ pajama login --no-open
19
+ ```
20
+
21
+ Then use the Memory API:
22
+
23
+ ```bash
24
+ pajama projects list
25
+ pajama projects create --name "UE5 Prototype" --engine unreal --description "Memory sandbox"
26
+ ```
27
+
28
+ ## Environment Variables
29
+
30
+ - `PAJAMA_API_URL`: Memory API base URL (defaults to `https://api-game-dev-memory.pajamadot.com`)
31
+ - `PAJAMA_TOKEN`: Bearer token override (API key)
32
+ - `PAJAMA_OAUTH_CALLBACK_TIMEOUT_SECS`: loopback callback wait (default: 900)
33
+
34
+ Installer-only:
35
+
36
+ - `PAJAMA_DOWNLOAD_BASE_URL`: override binary download base URL (defaults to `https://api-game-dev-memory.pajamadot.com/downloads/pajama`)
37
+
38
+ ## Prebuilt Binary Support
39
+
40
+ This package downloads a platform-specific prebuilt binary at install time.
41
+
42
+ Current prebuilt support (initial release):
43
+
44
+ - Windows x64 (`win32/x64`)
45
+
46
+ If you are on macOS or Linux, install from source for now:
47
+
48
+ ```bash
49
+ cd pajama
50
+ cargo install --path . --force
51
+ ```
package/bin/pajama.js ADDED
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const fs = require("node:fs");
5
+ const path = require("node:path");
6
+ const { spawn } = require("node:child_process");
7
+
8
+ function binaryName() {
9
+ return process.platform === "win32" ? "pajama.exe" : "pajama";
10
+ }
11
+
12
+ function binaryPath() {
13
+ return path.join(__dirname, binaryName());
14
+ }
15
+
16
+ const bin = binaryPath();
17
+ if (!fs.existsSync(bin)) {
18
+ console.error("[pajama] CLI binary not found.");
19
+ console.error("[pajama] Try reinstalling: npm i -g @pajamadot/pajama");
20
+ console.error("[pajama] Or build from source: cargo install --path pajama --force");
21
+ process.exit(1);
22
+ }
23
+
24
+ const child = spawn(bin, process.argv.slice(2), { stdio: "inherit" });
25
+ child.on("exit", (code, signal) => {
26
+ if (signal) {
27
+ process.kill(process.pid, signal);
28
+ return;
29
+ }
30
+ process.exit(code == null ? 1 : code);
31
+ });
32
+
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@pajamadot/pajama",
3
+ "version": "0.1.1",
4
+ "description": "PajamaDot CLI for Game Dev Memory (prebuilt binary installer)",
5
+ "private": false,
6
+ "license": "UNLICENSED",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+ssh://git@github.com/pajamadot/game-dev-memory.git",
10
+ "directory": "packages/pajama"
11
+ },
12
+ "bin": {
13
+ "pajama": "bin/pajama.js"
14
+ },
15
+ "scripts": {
16
+ "postinstall": "node scripts/postinstall.js"
17
+ },
18
+ "publishConfig": {
19
+ "access": "public"
20
+ },
21
+ "os": [
22
+ "win32"
23
+ ],
24
+ "cpu": [
25
+ "x64"
26
+ ],
27
+ "files": [
28
+ "bin/pajama.js",
29
+ "scripts/postinstall.js",
30
+ "README.md"
31
+ ],
32
+ "engines": {
33
+ "node": ">=18"
34
+ }
35
+ }
@@ -0,0 +1,101 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+
4
+ const fs = require("node:fs");
5
+ const path = require("node:path");
6
+ const crypto = require("node:crypto");
7
+
8
+ const pkg = require("../package.json");
9
+
10
+ function platformAssetName() {
11
+ const p = process.platform;
12
+ const a = process.arch;
13
+
14
+ if (p === "win32" && a === "x64") return "pajama-win32-x64.exe";
15
+ if (p === "win32" && a === "arm64") return "pajama-win32-arm64.exe";
16
+ if (p === "darwin" && a === "x64") return "pajama-darwin-x64";
17
+ if (p === "darwin" && a === "arm64") return "pajama-darwin-arm64";
18
+ if (p === "linux" && a === "x64") return "pajama-linux-x64";
19
+ if (p === "linux" && a === "arm64") return "pajama-linux-arm64";
20
+
21
+ return null;
22
+ }
23
+
24
+ function binaryName() {
25
+ return process.platform === "win32" ? "pajama.exe" : "pajama";
26
+ }
27
+
28
+ function baseUrl() {
29
+ const fromEnv = (process.env.PAJAMA_DOWNLOAD_BASE_URL || "").trim();
30
+ return fromEnv || "https://api-game-dev-memory.pajamadot.com/downloads/pajama";
31
+ }
32
+
33
+ async function fetchOrNull(url) {
34
+ const res = await fetch(url, { redirect: "follow" });
35
+ if (res.status === 404) return null;
36
+ if (!res.ok) {
37
+ const text = await res.text().catch(() => "");
38
+ throw new Error(`HTTP ${res.status} downloading ${url}: ${text}`);
39
+ }
40
+ return res;
41
+ }
42
+
43
+ async function downloadToFile(url, dstPath) {
44
+ const res = await fetchOrNull(url);
45
+ if (!res) throw new Error(`Not found: ${url}`);
46
+
47
+ const buf = Buffer.from(await res.arrayBuffer());
48
+
49
+ fs.mkdirSync(path.dirname(dstPath), { recursive: true });
50
+
51
+ // Atomic write: write to tmp, then rename.
52
+ const tmp = `${dstPath}.tmp-${process.pid}`;
53
+ fs.writeFileSync(tmp, buf);
54
+ fs.renameSync(tmp, dstPath);
55
+ }
56
+
57
+ async function maybeVerifySha256(url, filePath) {
58
+ const res = await fetchOrNull(url);
59
+ if (!res) return; // optional sidecar
60
+
61
+ const text = (await res.text()).trim();
62
+ const expected = text.split(/\s+/)[0]?.toLowerCase();
63
+ if (!expected || expected.length < 32) return;
64
+
65
+ const data = fs.readFileSync(filePath);
66
+ const actual = crypto.createHash("sha256").update(data).digest("hex").toLowerCase();
67
+ if (actual !== expected) {
68
+ throw new Error(`SHA256 mismatch for ${path.basename(filePath)} (expected ${expected}, got ${actual})`);
69
+ }
70
+ }
71
+
72
+ async function main() {
73
+ const asset = platformAssetName();
74
+ if (!asset) {
75
+ console.error(`[pajama] No prebuilt binary for ${process.platform}/${process.arch}.`);
76
+ console.error("[pajama] Build from source: cargo install --path pajama --force");
77
+ return;
78
+ }
79
+
80
+ const tag = `v${pkg.version}`;
81
+ const url = `${baseUrl()}/${tag}/${asset}`;
82
+ const shaUrl = `${url}.sha256`;
83
+ const dst = path.join(__dirname, "..", "bin", binaryName());
84
+
85
+ // Skip if already present.
86
+ if (fs.existsSync(dst)) return;
87
+
88
+ console.error(`[pajama] Downloading ${url}`);
89
+ await downloadToFile(url, dst);
90
+ await maybeVerifySha256(shaUrl, dst);
91
+
92
+ if (process.platform !== "win32") {
93
+ fs.chmodSync(dst, 0o755);
94
+ }
95
+ }
96
+
97
+ main().catch((err) => {
98
+ console.error("[pajama] Install failed:", err && err.message ? err.message : String(err));
99
+ process.exit(1);
100
+ });
101
+