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.
- package/README.md +29 -0
- package/index.js +34 -0
- package/install.js +141 -0
- 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
|
+
}
|