@mandors/cli 0.0.13 → 0.0.16
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 +42 -6
- package/npm/binaries/darwin-arm64/mandor +0 -0
- package/npm/binaries/darwin-arm64.tar.gz +0 -0
- package/npm/binaries/linux-arm64/mandor +0 -0
- package/npm/binaries/linux-arm64.tar.gz +0 -0
- package/npm/lib/install.js +84 -114
- package/npm/lib/resolve.js +84 -73
- package/package.json +1 -1
- package/scripts/install.sh +105 -0
package/README.md
CHANGED
|
@@ -69,22 +69,58 @@ Mandor provides:
|
|
|
69
69
|
|
|
70
70
|
## Installation
|
|
71
71
|
|
|
72
|
-
|
|
72
|
+
Choose one of the following methods:
|
|
73
|
+
|
|
74
|
+
### Option 1: curl (Recommended)
|
|
73
75
|
|
|
74
76
|
```bash
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
# Install latest stable version
|
|
78
|
+
curl -fsSL https://raw.githubusercontent.com/sanxzy/mandor/main/scripts/install.sh | sh
|
|
79
|
+
|
|
80
|
+
# Or install to custom directory
|
|
81
|
+
curl -fsSL https://raw.githubusercontent.com/sanxzy/mandor/main/scripts/install.sh | sh -s -- --prefix ~/bin
|
|
82
|
+
|
|
83
|
+
# Install latest prerelease
|
|
84
|
+
curl -fsSL https://raw.githubusercontent.com/sanxzy/mandor/main/scripts/install.sh | sh -s -- --prerelease
|
|
85
|
+
|
|
86
|
+
# Install specific version
|
|
87
|
+
curl -fsSL https://raw.githubusercontent.com/sanxzy/mandor/main/scripts/install.sh | sh -s -- --version v0.0.14
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Default install location: `$HOME/.local/bin/mandor`
|
|
91
|
+
|
|
92
|
+
Add to PATH if needed:
|
|
93
|
+
```bash
|
|
94
|
+
export PATH="$HOME/.local/bin:$PATH"
|
|
79
95
|
```
|
|
80
96
|
|
|
81
|
-
###
|
|
97
|
+
### Option 2: NPM
|
|
82
98
|
|
|
83
99
|
```bash
|
|
100
|
+
# Install globally
|
|
84
101
|
npm install -g @mandor/cli
|
|
102
|
+
|
|
103
|
+
# Or use npx without installing
|
|
85
104
|
npx @mandor/cli init "My Project"
|
|
86
105
|
```
|
|
87
106
|
|
|
107
|
+
### Option 3: From Source
|
|
108
|
+
|
|
109
|
+
```bash
|
|
110
|
+
git clone https://github.com/sanxzy/mandor.git
|
|
111
|
+
cd mandor
|
|
112
|
+
go build -o build/mandor ./cmd/mandor
|
|
113
|
+
sudo mv build/mandor /usr/local/bin/
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Platform Support
|
|
117
|
+
|
|
118
|
+
| Method | macOS | Linux | Windows |
|
|
119
|
+
|--------|-------|-------|---------|
|
|
120
|
+
| curl | ✅ arm64, x64 | ✅ arm64, x64 | ❌ |
|
|
121
|
+
| NPM | ✅ arm64, x64 | ✅ arm64, x64 | ✅ arm64, x64 |
|
|
122
|
+
| Source | ✅ | ✅ | ✅ |
|
|
123
|
+
|
|
88
124
|
---
|
|
89
125
|
|
|
90
126
|
## Quick Start
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/npm/lib/install.js
CHANGED
|
@@ -1,144 +1,118 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Post-install hook for Mandor CLI
|
|
3
|
-
* @description Handles binary
|
|
4
|
-
* @version 0.0.
|
|
3
|
+
* @description Handles binary extraction during npm install
|
|
4
|
+
* @version 0.0.2
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
const { downloadBinary, getCurrentPlatform } = require('./download');
|
|
8
7
|
const fs = require('fs');
|
|
9
8
|
const path = require('path');
|
|
10
9
|
const os = require('os');
|
|
10
|
+
const { execSync } = require('child_process');
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
const
|
|
14
|
-
|
|
15
|
-
/** @type {string} Bundled binaries directory */
|
|
12
|
+
const REPO = 'sanxzy/mandor';
|
|
13
|
+
const GITHUB_API = 'https://api.github.com';
|
|
16
14
|
const BUNDLE_DIR = path.join(__dirname, '..', 'binaries');
|
|
15
|
+
const CACHE_DIR = path.join(os.homedir(), '.mandor', 'bin');
|
|
16
|
+
|
|
17
|
+
function getPlatform() {
|
|
18
|
+
const platform = os.platform();
|
|
19
|
+
const arch = os.arch();
|
|
20
|
+
const platformMap = { darwin: 'darwin', linux: 'linux', win32: 'win32' };
|
|
21
|
+
const archMap = { x64: 'x64', arm64: 'arm64', amd64: 'x64', aarch64: 'arm64' };
|
|
22
|
+
return {
|
|
23
|
+
platform: platformMap[platform] || platform,
|
|
24
|
+
arch: archMap[arch] || arch
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
async function getLatestVersion(prerelease = false) {
|
|
29
|
+
const url = prerelease
|
|
30
|
+
? `${GITHUB_API}/repos/${REPO}/releases`
|
|
31
|
+
: `${GITHUB_API}/repos/${REPO}/releases/latest`;
|
|
32
|
+
|
|
33
|
+
const response = await fetch(url);
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
throw new Error(`Failed to fetch releases: ${response.statusText}`);
|
|
36
|
+
}
|
|
37
|
+
const data = await response.json();
|
|
38
|
+
const tagName = Array.isArray(data) ? data[0].tag_name : data.tag_name;
|
|
39
|
+
return tagName.replace(/^v/, '');
|
|
40
|
+
}
|
|
17
41
|
|
|
18
|
-
/**
|
|
19
|
-
* Installs the Mandor binary for the current platform
|
|
20
|
-
* @async
|
|
21
|
-
* @param {Object} [options] - Installation options
|
|
22
|
-
* @param {string} [options.version] - Version to install (default: 'latest')
|
|
23
|
-
* @returns {Promise<string>} Path to the installed binary
|
|
24
|
-
* @throws {Error} If download fails
|
|
25
|
-
* @example
|
|
26
|
-
* // Called automatically by npm postinstall
|
|
27
|
-
* await install();
|
|
28
|
-
*/
|
|
29
42
|
async function install(options = {}) {
|
|
43
|
+
const { platform, arch } = getPlatform();
|
|
30
44
|
const version = options.version || 'latest';
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
45
|
+
const prerelease = options.prerelease || false;
|
|
46
|
+
const osArch = `${platform}-${arch}`;
|
|
47
|
+
const assetName = `${osArch}.tar.gz`;
|
|
34
48
|
|
|
35
|
-
|
|
49
|
+
console.log('Mandor Installer');
|
|
50
|
+
console.log('================');
|
|
51
|
+
console.log(`OS: ${osArch}`);
|
|
36
52
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
binaryPath = bundledPath;
|
|
42
|
-
} else {
|
|
43
|
-
// Download from GitHub releases
|
|
44
|
-
binaryPath = await downloadBinary(version, platform, arch);
|
|
53
|
+
let installVersion = version;
|
|
54
|
+
if (version === 'latest') {
|
|
55
|
+
console.log(`Fetching latest ${prerelease ? 'prerelease' : 'release'}...`);
|
|
56
|
+
installVersion = await getLatestVersion(prerelease);
|
|
45
57
|
}
|
|
46
58
|
|
|
47
|
-
console.log(
|
|
59
|
+
console.log(`Version: ${installVersion}`);
|
|
60
|
+
console.log('');
|
|
48
61
|
|
|
49
|
-
|
|
50
|
-
|
|
62
|
+
const cachePath = path.join(CACHE_DIR, installVersion, osArch);
|
|
63
|
+
const binaryPath = path.join(cachePath, 'mandor');
|
|
51
64
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
* @param {string} platform - Target platform
|
|
55
|
-
* @param {string} arch - Target architecture
|
|
56
|
-
* @returns {string|null} Path to binary or null if not bundled
|
|
57
|
-
*/
|
|
58
|
-
function useBundledBinary(platform, arch) {
|
|
59
|
-
const osArch = `${platform}-${arch}`;
|
|
60
|
-
const tarball = path.join(BUNDLE_DIR, `${osArch}.tar.gz`);
|
|
61
|
-
const cacheDir = path.join(os.homedir(), '.mandor', 'bin');
|
|
62
|
-
const dest = path.join(cacheDir, osArch);
|
|
63
|
-
|
|
64
|
-
console.log(`DEBUG: Looking for binary for ${osArch}`);
|
|
65
|
-
console.log(`DEBUG: BUNDLE_DIR: ${BUNDLE_DIR}`);
|
|
66
|
-
console.log(`DEBUG: Files in BUNDLE_DIR: ${fs.readdirSync(BUNDLE_DIR).join(', ')}`);
|
|
67
|
-
|
|
68
|
-
// First check if binary already exists in cache
|
|
69
|
-
if (fs.existsSync(dest)) {
|
|
70
|
-
console.log(`DEBUG: Using cached binary: ${dest}`);
|
|
71
|
-
return dest;
|
|
65
|
+
if (platform === 'win32') {
|
|
66
|
+
binaryPath = binaryPath + '.exe';
|
|
72
67
|
}
|
|
73
68
|
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
return null;
|
|
69
|
+
if (fs.existsSync(binaryPath)) {
|
|
70
|
+
console.log(`Using cached binary: ${binaryPath}`);
|
|
71
|
+
return binaryPath;
|
|
78
72
|
}
|
|
79
73
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
fs.
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
console.log(`DEBUG: Extracted to: ${dest}`);
|
|
91
|
-
return dest;
|
|
92
|
-
} catch (e) {
|
|
93
|
-
console.log(`DEBUG: Failed to extract tarball: ${e.message}`);
|
|
94
|
-
return null;
|
|
74
|
+
const bundledPath = path.join(BUNDLE_DIR, assetName);
|
|
75
|
+
if (fs.existsSync(bundledPath)) {
|
|
76
|
+
console.log(`Using bundled binary: ${bundledPath}`);
|
|
77
|
+
if (!fs.existsSync(cachePath)) {
|
|
78
|
+
fs.mkdirSync(cachePath, { recursive: true });
|
|
79
|
+
}
|
|
80
|
+
execSync(`tar -xzf "${bundledPath}" -C "${cachePath}"`, { stdio: 'inherit' });
|
|
81
|
+
fs.chmodSync(binaryPath, '755');
|
|
82
|
+
console.log(`Installed: ${binaryPath}`);
|
|
83
|
+
return binaryPath;
|
|
95
84
|
}
|
|
96
|
-
}
|
|
97
85
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
* const removed = cleanupCache();
|
|
103
|
-
* console.log(`Removed ${removed} old binary files`);
|
|
104
|
-
*/
|
|
105
|
-
function cleanupCache() {
|
|
106
|
-
if (!fs.existsSync(CACHE_DIR)) return 0;
|
|
86
|
+
console.log('Downloading from GitHub releases...');
|
|
87
|
+
const downloadUrl = `https://github.com/${REPO}/releases/download/v${installVersion}/${assetName}`;
|
|
88
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mandor-install-'));
|
|
89
|
+
const tarball = path.join(tempDir, assetName);
|
|
107
90
|
|
|
108
|
-
const
|
|
109
|
-
|
|
91
|
+
const response = await fetch(downloadUrl);
|
|
92
|
+
if (!response.ok) {
|
|
93
|
+
throw new Error(`Download failed: ${response.statusText} (${downloadUrl})`);
|
|
94
|
+
}
|
|
110
95
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
96
|
+
const file = fs.createWriteStream(tarball);
|
|
97
|
+
await new Promise((resolve, reject) => {
|
|
98
|
+
response.body.pipe(file);
|
|
99
|
+
file.on('finish', resolve);
|
|
100
|
+
file.on('error', reject);
|
|
101
|
+
});
|
|
114
102
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
if (stats.mtimeMs < thirtyDaysAgo) {
|
|
118
|
-
fs.unlinkSync(filePath);
|
|
119
|
-
removed++;
|
|
120
|
-
}
|
|
103
|
+
if (!fs.existsSync(cachePath)) {
|
|
104
|
+
fs.mkdirSync(cachePath, { recursive: true });
|
|
121
105
|
}
|
|
122
106
|
|
|
123
|
-
|
|
124
|
-
|
|
107
|
+
execSync(`tar -xzf "${tarball}" -C "${cachePath}"`, { stdio: 'inherit' });
|
|
108
|
+
fs.chmodSync(binaryPath, '755');
|
|
125
109
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
* const version = getInstalledVersion();
|
|
131
|
-
* if (version) { console.log(`Using Mandor ${version}`); }
|
|
132
|
-
*/
|
|
133
|
-
function getInstalledVersion() {
|
|
134
|
-
const versionPath = path.join(CACHE_DIR, 'version.txt');
|
|
135
|
-
if (fs.existsSync(versionPath)) {
|
|
136
|
-
return fs.readFileSync(versionPath, 'utf-8').trim();
|
|
137
|
-
}
|
|
138
|
-
return null;
|
|
110
|
+
fs.rmSync(tempDir, { recursive: true });
|
|
111
|
+
|
|
112
|
+
console.log(`Installed: ${binaryPath}`);
|
|
113
|
+
return binaryPath;
|
|
139
114
|
}
|
|
140
115
|
|
|
141
|
-
// Run install on postinstall
|
|
142
116
|
if (require.main === module || process.env.npm_lifecycle_event === 'postinstall') {
|
|
143
117
|
install().catch(error => {
|
|
144
118
|
console.error('Failed to install Mandor:', error.message);
|
|
@@ -146,8 +120,4 @@ if (require.main === module || process.env.npm_lifecycle_event === 'postinstall'
|
|
|
146
120
|
});
|
|
147
121
|
}
|
|
148
122
|
|
|
149
|
-
module.exports = {
|
|
150
|
-
install,
|
|
151
|
-
cleanupCache,
|
|
152
|
-
getInstalledVersion
|
|
153
|
-
};
|
|
123
|
+
module.exports = { install, getLatestVersion, getPlatform };
|
package/npm/lib/resolve.js
CHANGED
|
@@ -1,59 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Version resolution module for Mandor CLI
|
|
3
3
|
* @description Resolves the correct binary path based on version and platform
|
|
4
|
-
* @version 0.0.
|
|
4
|
+
* @version 0.0.2
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const path = require('path');
|
|
8
8
|
const fs = require('fs');
|
|
9
9
|
const os = require('os');
|
|
10
|
-
const { downloadBinary, getCurrentPlatform
|
|
10
|
+
const { downloadBinary, getCurrentPlatform } = require('./download');
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
const REPO = 'sanxzy/mandor';
|
|
13
|
+
const GITHUB_API = 'https://api.github.com';
|
|
13
14
|
const DEFAULT_VERSION = 'latest';
|
|
14
15
|
|
|
15
|
-
/**
|
|
16
|
-
* Resolves the binary path for the requested version
|
|
17
|
-
* @async
|
|
18
|
-
* @param {Object} [options] - Resolution options
|
|
19
|
-
* @param {string} [options.version] - Requested version (default: 'latest')
|
|
20
|
-
* @param {boolean} [options.forceDownload] - Force re-download even if cached
|
|
21
|
-
* @returns {Promise<string>} Path to the Mandor binary
|
|
22
|
-
* @throws {Error} If binary cannot be resolved or downloaded
|
|
23
|
-
* @example
|
|
24
|
-
* const binaryPath = await resolve({ version: '1.0.0' });
|
|
25
|
-
* console.log(`Using: ${binaryPath}`);
|
|
26
|
-
*/
|
|
27
|
-
async function resolve(options = {}) {
|
|
28
|
-
const version = options.version || DEFAULT_VERSION;
|
|
29
|
-
const { platform, arch } = getCurrentPlatform();
|
|
30
|
-
|
|
31
|
-
// Check cache first
|
|
32
|
-
const cachedPath = getCachedBinary(version, platform, arch);
|
|
33
|
-
if (cachedPath && !options.forceDownload) {
|
|
34
|
-
return cachedPath;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Download if not cached
|
|
38
|
-
const binaryPath = await downloadBinary(version, platform, arch);
|
|
39
|
-
cacheBinary(binaryPath, version, platform, arch);
|
|
40
|
-
|
|
41
|
-
return binaryPath;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/**
|
|
45
|
-
* Gets the cached binary path for a specific version
|
|
46
|
-
* @param {string} version - Version to look for
|
|
47
|
-
* @param {string} platform - Target platform
|
|
48
|
-
* @param {string} arch - Target architecture
|
|
49
|
-
* @returns {string|null} Path to cached binary or null
|
|
50
|
-
* @example
|
|
51
|
-
* const cached = getCachedBinary('1.0.0', 'darwin', 'x64');
|
|
52
|
-
*/
|
|
53
16
|
function getCachedBinary(version, platform, arch) {
|
|
54
|
-
const
|
|
17
|
+
const osArch = `${platform}-${arch}`;
|
|
55
18
|
const binaryName = platform === 'win32' ? 'mandor.exe' : 'mandor';
|
|
56
|
-
const binaryPath = path.join(
|
|
19
|
+
const binaryPath = path.join(os.homedir(), '.mandor', 'bin', version, osArch, binaryName);
|
|
57
20
|
|
|
58
21
|
if (fs.existsSync(binaryPath)) {
|
|
59
22
|
return binaryPath;
|
|
@@ -61,18 +24,23 @@ function getCachedBinary(version, platform, arch) {
|
|
|
61
24
|
return null;
|
|
62
25
|
}
|
|
63
26
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
27
|
+
async function getLatestVersion(prerelease = false) {
|
|
28
|
+
const url = prerelease
|
|
29
|
+
? `${GITHUB_API}/repos/${REPO}/releases`
|
|
30
|
+
: `${GITHUB_API}/repos/${REPO}/releases/latest`;
|
|
31
|
+
|
|
32
|
+
const response = await fetch(url);
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
throw new Error(`Failed to fetch releases: ${response.statusText}`);
|
|
35
|
+
}
|
|
36
|
+
const data = await response.json();
|
|
37
|
+
const tagName = Array.isArray(data) ? data[0].tag_name : data.tag_name;
|
|
38
|
+
return tagName.replace(/^v/, '');
|
|
39
|
+
}
|
|
40
|
+
|
|
74
41
|
function cacheBinary(binaryPath, version, platform, arch) {
|
|
75
|
-
const
|
|
42
|
+
const osArch = `${platform}-${arch}`;
|
|
43
|
+
const cacheDir = path.join(os.homedir(), '.mandor', 'bin', version, osArch);
|
|
76
44
|
fs.mkdirSync(cacheDir, { recursive: true });
|
|
77
45
|
|
|
78
46
|
const binaryName = platform === 'win32' ? 'mandor.exe' : 'mandor';
|
|
@@ -82,13 +50,54 @@ function cacheBinary(binaryPath, version, platform, arch) {
|
|
|
82
50
|
fs.chmodSync(destPath, '755');
|
|
83
51
|
}
|
|
84
52
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
53
|
+
async function resolve(options = {}) {
|
|
54
|
+
const version = options.version || DEFAULT_VERSION;
|
|
55
|
+
const { platform, arch } = getCurrentPlatform();
|
|
56
|
+
const prerelease = options.prerelease || false;
|
|
57
|
+
|
|
58
|
+
let resolveVersion = version;
|
|
59
|
+
if (version === 'latest') {
|
|
60
|
+
resolveVersion = await getLatestVersion(prerelease);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const cachedPath = getCachedBinary(resolveVersion, platform, arch);
|
|
64
|
+
if (cachedPath && !options.forceDownload) {
|
|
65
|
+
return cachedPath;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const osArch = `${platform}-${arch}`;
|
|
69
|
+
const downloadUrl = `https://github.com/${REPO}/releases/download/v${resolveVersion}/${osArch}.tar.gz`;
|
|
70
|
+
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mandor-download-'));
|
|
71
|
+
const tarball = path.join(tempDir, `${osArch}.tar.gz`);
|
|
72
|
+
|
|
73
|
+
console.log(`Downloading Mandor ${resolveVersion}...`);
|
|
74
|
+
|
|
75
|
+
const response = await fetch(downloadUrl);
|
|
76
|
+
if (!response.ok) {
|
|
77
|
+
fs.rmSync(tempDir, { recursive: true });
|
|
78
|
+
throw new Error(`Download failed: ${response.statusText}`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const file = fs.createWriteStream(tarball);
|
|
82
|
+
await new Promise((resolve, reject) => {
|
|
83
|
+
response.body.pipe(file);
|
|
84
|
+
file.on('finish', resolve);
|
|
85
|
+
file.on('error', reject);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
const binaryName = platform === 'win32' ? 'mandor.exe' : 'mandor';
|
|
89
|
+
const cacheDir = path.join(os.homedir(), '.mandor', 'bin', resolveVersion, osArch);
|
|
90
|
+
fs.mkdirSync(cacheDir, { recursive: true });
|
|
91
|
+
|
|
92
|
+
const { execSync } = require('child_process');
|
|
93
|
+
execSync(`tar -xzf "${tarball}" -C "${cacheDir}"`, { stdio: 'pipe' });
|
|
94
|
+
fs.chmodSync(path.join(cacheDir, binaryName), '755');
|
|
95
|
+
|
|
96
|
+
fs.rmSync(tempDir, { recursive: true });
|
|
97
|
+
|
|
98
|
+
return path.join(cacheDir, binaryName);
|
|
99
|
+
}
|
|
100
|
+
|
|
92
101
|
function listCachedBinaries() {
|
|
93
102
|
const cacheDir = path.join(os.homedir(), '.mandor', 'bin');
|
|
94
103
|
|
|
@@ -100,23 +109,24 @@ function listCachedBinaries() {
|
|
|
100
109
|
const entries = fs.readdirSync(cacheDir);
|
|
101
110
|
|
|
102
111
|
for (const entry of entries) {
|
|
103
|
-
const
|
|
104
|
-
if (fs.statSync(
|
|
105
|
-
const
|
|
106
|
-
|
|
112
|
+
const versionPath = path.join(cacheDir, entry);
|
|
113
|
+
if (fs.statSync(versionPath).isDirectory()) {
|
|
114
|
+
const subEntries = fs.readdirSync(versionPath);
|
|
115
|
+
for (const subEntry of subEntries) {
|
|
116
|
+
const subPath = path.join(versionPath, subEntry);
|
|
117
|
+
if (fs.statSync(subPath).isDirectory()) {
|
|
118
|
+
const parts = subEntry.split('-');
|
|
119
|
+
const arch = parts.pop();
|
|
120
|
+
const platform = parts.join('-');
|
|
121
|
+
versions.push({ version: entry, platform, arch, path: subPath });
|
|
122
|
+
}
|
|
123
|
+
}
|
|
107
124
|
}
|
|
108
125
|
}
|
|
109
126
|
|
|
110
127
|
return versions;
|
|
111
128
|
}
|
|
112
129
|
|
|
113
|
-
/**
|
|
114
|
-
* Clears all cached binaries
|
|
115
|
-
* @returns {number} Number of binaries removed
|
|
116
|
-
* @example
|
|
117
|
-
* const removed = clearCache();
|
|
118
|
-
* console.log(`Cleared ${removed} cached binaries`);
|
|
119
|
-
*/
|
|
120
130
|
function clearCache() {
|
|
121
131
|
const cacheDir = path.join(os.homedir(), '.mandor', 'bin');
|
|
122
132
|
|
|
@@ -144,5 +154,6 @@ module.exports = {
|
|
|
144
154
|
cacheBinary,
|
|
145
155
|
listCachedBinaries,
|
|
146
156
|
clearCache,
|
|
147
|
-
DEFAULT_VERSION
|
|
157
|
+
DEFAULT_VERSION,
|
|
158
|
+
getLatestVersion
|
|
148
159
|
};
|
package/package.json
CHANGED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
#!/bin/sh
|
|
2
|
+
#
|
|
3
|
+
# install.sh - Install Mandor CLI
|
|
4
|
+
#
|
|
5
|
+
# Usage:
|
|
6
|
+
# curl -fsSL https://raw.githubusercontent.com/sanxzy/mandor/main/scripts/install.sh | sh
|
|
7
|
+
# curl -fsSL https://raw.githubusercontent.com/sanxzy/mandor/main/scripts/install.sh | sh -s -- --help
|
|
8
|
+
#
|
|
9
|
+
# Options:
|
|
10
|
+
# --prefix DIR Install prefix (default: $HOME/.local)
|
|
11
|
+
# --version VER Install specific version (default: latest)
|
|
12
|
+
# --prerelease Install latest prerelease
|
|
13
|
+
# --help Show this help
|
|
14
|
+
#
|
|
15
|
+
|
|
16
|
+
set -e
|
|
17
|
+
|
|
18
|
+
REPO="sanxzy/mandor"
|
|
19
|
+
INSTALL_DIR="${HOME}/.local/bin"
|
|
20
|
+
VERSION="latest"
|
|
21
|
+
PRERELEASE=""
|
|
22
|
+
TAG="latest"
|
|
23
|
+
|
|
24
|
+
while [ $# -gt 0 ]; do
|
|
25
|
+
case "$1" in
|
|
26
|
+
--prefix)
|
|
27
|
+
INSTALL_DIR="$2"
|
|
28
|
+
shift 2
|
|
29
|
+
;;
|
|
30
|
+
--version)
|
|
31
|
+
VERSION="$2"
|
|
32
|
+
shift 2
|
|
33
|
+
;;
|
|
34
|
+
--prerelease)
|
|
35
|
+
PRERELEASE="1"
|
|
36
|
+
TAG="latest"
|
|
37
|
+
shift
|
|
38
|
+
;;
|
|
39
|
+
--help|-h)
|
|
40
|
+
head -20 "$0"
|
|
41
|
+
exit 0
|
|
42
|
+
;;
|
|
43
|
+
esac
|
|
44
|
+
done
|
|
45
|
+
|
|
46
|
+
OS=$(uname -s | tr '[:upper:]' '[:lower:]')
|
|
47
|
+
ARCH=$(uname -m)
|
|
48
|
+
case "$ARCH" in
|
|
49
|
+
x86_64|amd64) ARCH="x64" ;;
|
|
50
|
+
arm64|aarch64) ARCH="arm64" ;;
|
|
51
|
+
esac
|
|
52
|
+
|
|
53
|
+
case "$OS" in
|
|
54
|
+
darwin) ;;
|
|
55
|
+
linux) ;;
|
|
56
|
+
*)
|
|
57
|
+
echo "Unsupported OS: $OS"
|
|
58
|
+
exit 1
|
|
59
|
+
;;
|
|
60
|
+
esac
|
|
61
|
+
|
|
62
|
+
echo "Mandor Installer"
|
|
63
|
+
echo "================"
|
|
64
|
+
echo "OS: $OS-$ARCH"
|
|
65
|
+
|
|
66
|
+
if [ "$VERSION" = "latest" ]; then
|
|
67
|
+
if [ -n "$PRERELEASE" ]; then
|
|
68
|
+
echo "Fetching latest prerelease..."
|
|
69
|
+
VERSION=$(curl -s "https://api.github.com/repos/${REPO}/releases" | sed -n 's/.*"tag_name": *"\([^"]*\)".*/\1/p' | head -1)
|
|
70
|
+
else
|
|
71
|
+
echo "Fetching latest release..."
|
|
72
|
+
VERSION=$(curl -s "https://api.github.com/repos/${REPO}/releases/latest" | sed -n 's/.*"tag_name": *"\([^"]*\)".*/\1/p')
|
|
73
|
+
fi
|
|
74
|
+
fi
|
|
75
|
+
|
|
76
|
+
echo "Version: $VERSION"
|
|
77
|
+
echo "Install dir: $INSTALL_DIR"
|
|
78
|
+
echo ""
|
|
79
|
+
|
|
80
|
+
ASSET_NAME="${OS}-${ARCH}.tar.gz"
|
|
81
|
+
DOWNLOAD_URL="https://github.com/${REPO}/releases/download/${VERSION}/${ASSET_NAME}"
|
|
82
|
+
TEMP_DIR=$(mktemp -d)
|
|
83
|
+
TARFILE="${TEMP_DIR}/${ASSET_NAME}"
|
|
84
|
+
|
|
85
|
+
echo "Downloading ${ASSET_NAME}..."
|
|
86
|
+
if ! curl -fsSL -o "$TARFILE" "$DOWNLOAD_URL"; then
|
|
87
|
+
echo "Download failed: $DOWNLOAD_URL"
|
|
88
|
+
rm -rf "$TEMP_DIR"
|
|
89
|
+
exit 1
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
echo "Extracting..."
|
|
93
|
+
mkdir -p "$INSTALL_DIR"
|
|
94
|
+
tar -xzf "$TARFILE" -C "$INSTALL_DIR"
|
|
95
|
+
chmod 755 "${INSTALL_DIR}/mandor"
|
|
96
|
+
|
|
97
|
+
rm -rf "$TEMP_DIR"
|
|
98
|
+
|
|
99
|
+
echo ""
|
|
100
|
+
echo "Installed: ${INSTALL_DIR}/mandor"
|
|
101
|
+
echo ""
|
|
102
|
+
|
|
103
|
+
if [ -d "$HOME/.local/bin" ]; then
|
|
104
|
+
echo "Add to PATH: export PATH=\"\$HOME/.local/bin:\$PATH\""
|
|
105
|
+
fi
|