santui 0.1.8

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.
Files changed (4) hide show
  1. package/README.md +29 -0
  2. package/index.js +34 -0
  3. package/install.js +141 -0
  4. package/package.json +31 -0
package/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Santui — install via npm
2
+
3
+ ```bash
4
+ npm install -g santui
5
+ ```
6
+
7
+ Then run:
8
+
9
+ ```bash
10
+ santui
11
+ ```
12
+
13
+ Santui is a keyboard-driven TUI app that lives in your terminal. It's a launcher for plugins — the core is lightweight, and everything extra comes through the Plugin Registry.
14
+
15
+ ## What's included
16
+
17
+ This npm package downloads the correct pre-built binary for your platform (Windows, macOS, Linux) from GitHub Releases.
18
+
19
+ ## Platform support
20
+
21
+ | Platform | Binary |
22
+ |---|---|
23
+ | Windows x64 | `santui-x86_64-pc-windows-msvc.zip` |
24
+ | macOS ARM64 | `santui-aarch64-apple-darwin.tar.gz` |
25
+ | Linux x64 | `santui-x86_64-unknown-linux-gnu.tar.gz` |
26
+
27
+ ## Source
28
+
29
+ https://github.com/sonyarianto/santui
package/index.js ADDED
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawn } = require('child_process');
4
+ const path = require('path');
5
+ const fs = require('fs');
6
+
7
+ // Find the downloaded binary
8
+ const binaryName = process.platform === 'win32' ? 'santui.exe' : 'santui';
9
+ const binaryPath = path.join(__dirname, binaryName);
10
+
11
+ // Fallback: check node_modules/.bin
12
+ const fallbackPath = path.join(__dirname, '..', '.bin', binaryName);
13
+
14
+ const exe = fs.existsSync(binaryPath) ? binaryPath : fallbackPath;
15
+
16
+ if (!fs.existsSync(exe)) {
17
+ console.error('Santui binary not found. Run `npm install` again or check your installation.');
18
+ process.exit(1);
19
+ }
20
+
21
+ // Spawn the binary with all passed arguments
22
+ const child = spawn(exe, process.argv.slice(2), {
23
+ stdio: 'inherit',
24
+ windowsHide: false,
25
+ });
26
+
27
+ child.on('close', (code) => {
28
+ process.exit(code);
29
+ });
30
+
31
+ child.on('error', (err) => {
32
+ console.error('Failed to start Santui:', err.message);
33
+ process.exit(1);
34
+ });
package/install.js ADDED
@@ -0,0 +1,141 @@
1
+ const https = require('https');
2
+ const http = require('http');
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { createWriteStream, readFileSync, writeFileSync } = require('fs');
6
+ const { execSync } = require('child_process');
7
+
8
+ const pkg = JSON.parse(readFileSync(path.join(__dirname, 'package.json'), 'utf8'));
9
+ const version = pkg.version;
10
+ const repo = 'sonyarianto/santui';
11
+
12
+ // Map OS + arch → Rust target triple
13
+ function getTarget() {
14
+ const os = process.platform;
15
+ const arch = process.arch;
16
+
17
+ if (arch !== 'x64' && arch !== 'arm64') {
18
+ console.error(`Unsupported architecture: ${arch}`);
19
+ process.exit(1);
20
+ }
21
+
22
+ if (os === 'win32') {
23
+ return 'x86_64-pc-windows-msvc';
24
+ }
25
+ if (os === 'darwin') {
26
+ if (arch === 'arm64') return 'aarch64-apple-darwin';
27
+ console.error('Intel Mac (x64) is not supported yet. Build from source instead:');
28
+ console.error(' git clone https://github.com/sonyarianto/santui.git && cd santui && cargo build --workspace');
29
+ process.exit(1);
30
+ }
31
+ if (os === 'linux') {
32
+ return 'x86_64-unknown-linux-gnu';
33
+ }
34
+
35
+ console.error(`Unsupported platform: ${os}`);
36
+ process.exit(1);
37
+ }
38
+
39
+ function getArchiveExt() {
40
+ return process.platform === 'win32' ? 'zip' : 'tar.gz';
41
+ }
42
+
43
+ function download(url, dest) {
44
+ return new Promise((resolve, reject) => {
45
+ const file = createWriteStream(dest);
46
+ const protocol = url.startsWith('https') ? https : http;
47
+
48
+ protocol.get(url, (response) => {
49
+ // Handle redirects (GitHub)
50
+ if (response.statusCode >= 300 && response.statusCode < 400 && response.headers.location) {
51
+ file.close();
52
+ fs.unlinkSync(dest);
53
+ return download(response.headers.location, dest).then(resolve).catch(reject);
54
+ }
55
+
56
+ if (response.statusCode !== 200) {
57
+ file.close();
58
+ fs.unlinkSync(dest);
59
+ return reject(new Error(`HTTP ${response.statusCode}: ${response.statusMessage}`));
60
+ }
61
+
62
+ response.pipe(file);
63
+ file.on('finish', () => {
64
+ file.close();
65
+ resolve();
66
+ });
67
+ }).on('error', (err) => {
68
+ file.close();
69
+ fs.unlinkSync(dest, () => {});
70
+ reject(err);
71
+ });
72
+ });
73
+ }
74
+
75
+ async function install() {
76
+ const target = getTarget();
77
+ const ext = getArchiveExt();
78
+ const archiveUrl = `https://github.com/${repo}/releases/download/v${version}/santui-${target}.${ext}`;
79
+ const binaryName = process.platform === 'win32' ? 'santui.exe' : 'santui';
80
+ const destPath = path.join(__dirname, binaryName);
81
+
82
+ console.log(`Downloading Santui v${version} (${target})...`);
83
+ console.log(` ${archiveUrl}`);
84
+
85
+ const tmpDir = fs.mkdtempSync(path.join(__dirname, 'tmp-'));
86
+ const archivePath = path.join(tmpDir, `santui.${ext}`);
87
+
88
+ try {
89
+ // Download archive
90
+ await download(archiveUrl, archivePath);
91
+
92
+ // Extract
93
+ console.log(' Extracting...');
94
+ if (ext === 'zip') {
95
+ execSync(`powershell -Command "Expand-Archive -Path '${archivePath}' -DestinationPath '${tmpDir}' -Force"`, { stdio: 'pipe' });
96
+ // Find the exe in the extracted folder
97
+ const files = fs.readdirSync(tmpDir);
98
+ const exeFile = files.find(f => f.endsWith('.exe'));
99
+ if (!exeFile) throw new Error('santui.exe not found in archive');
100
+ fs.copyFileSync(path.join(tmpDir, exeFile), destPath);
101
+ } else {
102
+ execSync(`tar xzf '${archivePath}' -C '${tmpDir}'`, { stdio: 'pipe' });
103
+ // Binary is at root of archive (tar czf ... -C staging .)
104
+ const extractedBinary = path.join(tmpDir, binaryName);
105
+ if (fs.existsSync(extractedBinary)) {
106
+ fs.copyFileSync(extractedBinary, destPath);
107
+ } else {
108
+ // Fallback: check subdirectory (staging/)
109
+ const items = fs.readdirSync(tmpDir);
110
+ let found = false;
111
+ for (const item of items) {
112
+ const itemPath = path.join(tmpDir, item);
113
+ if (fs.statSync(itemPath).isDirectory()) {
114
+ const subBinary = path.join(itemPath, binaryName);
115
+ if (fs.existsSync(subBinary)) {
116
+ fs.copyFileSync(subBinary, destPath);
117
+ found = true;
118
+ break;
119
+ }
120
+ }
121
+ }
122
+ if (!found) throw new Error(`${binaryName} not found in archive`);
123
+ }
124
+ }
125
+
126
+ // Make executable on Unix
127
+ if (process.platform !== 'win32') {
128
+ execSync(`chmod +x '${destPath}'`, { stdio: 'pipe' });
129
+ }
130
+
131
+ console.log(' [OK] Binary installed');
132
+ } catch (err) {
133
+ console.error(` [FAIL] ${err.message}`);
134
+ process.exit(1);
135
+ } finally {
136
+ // Cleanup temp
137
+ fs.rmSync(tmpDir, { recursive: true, force: true });
138
+ }
139
+ }
140
+
141
+ install();
package/package.json ADDED
@@ -0,0 +1,31 @@
1
+ {
2
+ "name": "santui",
3
+ "version": "0.1.8",
4
+ "description": "Your terminal home base — a modern TUI launcher for plugins",
5
+ "homepage": "https://github.com/sonyarianto/santui",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/sonyarianto/santui.git"
10
+ },
11
+ "bin": {
12
+ "santui": "./index.js"
13
+ },
14
+ "scripts": {
15
+ "postinstall": "node install.js"
16
+ },
17
+ "files": [
18
+ "index.js",
19
+ "install.js",
20
+ "README.md"
21
+ ],
22
+ "engines": {
23
+ "node": ">=18"
24
+ },
25
+ "keywords": [
26
+ "tui",
27
+ "terminal",
28
+ "launcher",
29
+ "santui"
30
+ ]
31
+ }