@mandors/cli 0.0.17 → 0.0.19

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.
@@ -1,17 +1,17 @@
1
1
  /**
2
2
  * @fileoverview Post-install hook for Mandor CLI
3
- * @description Downloads binary from GitHub releases during npm install
4
- * @version 0.0.3
3
+ * @description Downloads and extracts binary from GitHub releases
4
+ * @version 0.0.5
5
5
  */
6
6
 
7
7
  const fs = require('fs');
8
8
  const path = require('path');
9
9
  const os = require('os');
10
10
  const { execSync } = require('child_process');
11
+ const https = require('https');
11
12
 
12
13
  const REPO = 'sanxzy/mandor';
13
- const GITHUB_API = 'https://api.github.com';
14
- const CACHE_DIR = path.join(os.homedir(), '.mandor', 'bin');
14
+ const INSTALL_DIR = path.join(os.homedir(), '.local', 'bin');
15
15
 
16
16
  function getPlatform() {
17
17
  const platform = os.platform();
@@ -26,16 +26,42 @@ function getPlatform() {
26
26
 
27
27
  async function getLatestVersion(prerelease = false) {
28
28
  const url = prerelease
29
- ? `${GITHUB_API}/repos/${REPO}/releases`
30
- : `${GITHUB_API}/repos/${REPO}/releases/latest`;
29
+ ? `https://api.github.com/repos/${REPO}/releases`
30
+ : `https://api.github.com/repos/${REPO}/releases/latest`;
31
+
32
+ return new Promise((resolve, reject) => {
33
+ https.get(url, { headers: { 'User-Agent': 'Mandor-CLI' } }, (res) => {
34
+ let data = '';
35
+ res.on('data', chunk => data += chunk);
36
+ res.on('end', () => {
37
+ try {
38
+ const parsed = JSON.parse(data);
39
+ const tagName = Array.isArray(parsed) ? parsed[0].tag_name : parsed.tag_name;
40
+ resolve(tagName.replace(/^v/, ''));
41
+ } catch (e) {
42
+ reject(e);
43
+ }
44
+ });
45
+ }).on('error', reject);
46
+ });
47
+ }
31
48
 
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/, '');
49
+ function downloadFile(url, dest) {
50
+ return new Promise((resolve, reject) => {
51
+ const file = fs.createWriteStream(dest);
52
+ https.get(url, (res) => {
53
+ if (res.statusCode === 302 || res.statusCode === 301) {
54
+ return downloadFile(res.headers.location, dest).then(resolve).catch(reject);
55
+ }
56
+ res.pipe(file);
57
+ file.on('finish', () => {
58
+ file.close(resolve);
59
+ });
60
+ }).on('error', (err) => {
61
+ fs.unlink(dest, () => {});
62
+ reject(err);
63
+ });
64
+ });
39
65
  }
40
66
 
41
67
  async function install(options = {}) {
@@ -43,7 +69,7 @@ async function install(options = {}) {
43
69
  const version = options.version || 'latest';
44
70
  const prerelease = options.prerelease || false;
45
71
  const osArch = `${platform}-${arch}`;
46
- const assetName = `${osArch}.tar.gz`;
72
+ const binaryName = platform === 'win32' ? 'mandor.exe' : 'mandor';
47
73
 
48
74
  console.log('Mandor Installer');
49
75
  console.log('================');
@@ -58,48 +84,38 @@ async function install(options = {}) {
58
84
  console.log(`Version: ${installVersion}`);
59
85
  console.log('');
60
86
 
61
- const cachePath = path.join(CACHE_DIR, installVersion, osArch);
62
- const binaryPath = path.join(cachePath, platform === 'win32' ? 'mandor.exe' : 'mandor');
87
+ const binaryPath = path.join(INSTALL_DIR, binaryName);
63
88
 
64
89
  if (fs.existsSync(binaryPath)) {
65
- console.log(`Using cached binary: ${binaryPath}`);
90
+ console.log(`Already installed: ${binaryPath}`);
66
91
  return binaryPath;
67
92
  }
68
93
 
69
94
  console.log('Downloading from GitHub releases...');
70
- const downloadUrl = `https://github.com/${REPO}/releases/download/v${installVersion}/${assetName}`;
71
- const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mandor-install-'));
72
- const tarball = path.join(tempDir, assetName);
73
-
74
- const response = await fetch(downloadUrl);
75
- if (!response.ok) {
76
- fs.rmSync(tempDir, { recursive: true });
77
- throw new Error(`Download failed: ${response.statusText} (${downloadUrl})`);
78
- }
95
+ const downloadUrl = `https://github.com/${REPO}/releases/download/v${installVersion}/${osArch}.tar.gz`;
96
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mandor-'));
97
+ const tarball = path.join(tempDir, `${osArch}.tar.gz`);
79
98
 
80
- const file = fs.createWriteStream(tarball);
81
- await new Promise((resolve, reject) => {
82
- response.body.pipe(file);
83
- file.on('finish', resolve);
84
- file.on('error', reject);
85
- });
99
+ await downloadFile(downloadUrl, tarball);
86
100
 
87
- if (!fs.existsSync(cachePath)) {
88
- fs.mkdirSync(cachePath, { recursive: true });
89
- }
101
+ fs.mkdirSync(INSTALL_DIR, { recursive: true });
102
+ execSync(`tar -xzf "${tarball}" -C "${tempDir}"`, { stdio: 'inherit' });
90
103
 
91
- execSync(`tar -xzf "${tarball}" -C "${cachePath}"`, { stdio: 'inherit' });
104
+ const extractedBinary = path.join(tempDir, binaryName);
105
+ fs.copyFileSync(extractedBinary, binaryPath);
92
106
  fs.chmodSync(binaryPath, '755');
93
107
 
94
108
  fs.rmSync(tempDir, { recursive: true });
95
109
 
96
110
  console.log(`Installed: ${binaryPath}`);
111
+ console.log('');
112
+ console.log('Add to PATH:');
113
+ console.log(` export PATH="${INSTALL_DIR}:$PATH"`);
97
114
  return binaryPath;
98
115
  }
99
116
 
100
117
  if (require.main === module || process.env.npm_lifecycle_event === 'postinstall') {
101
- const prerelease = process.argv.includes('--prerelease') || process.argv.includes('-p');
102
- install({ prerelease }).catch(error => {
118
+ install().catch(error => {
103
119
  console.error('Failed to install Mandor:', error.message);
104
120
  process.exit(1);
105
121
  });
@@ -1,159 +1,60 @@
1
1
  /**
2
2
  * @fileoverview Version resolution module for Mandor CLI
3
- * @description Resolves the correct binary path based on version and platform
4
- * @version 0.0.2
3
+ * @description Resolves the binary path for the CLI
4
+ * @version 0.0.3
5
5
  */
6
6
 
7
7
  const path = require('path');
8
- const fs = require('fs');
9
8
  const os = require('os');
10
- const { downloadBinary, getCurrentPlatform } = require('./download');
9
+ const https = require('https');
11
10
 
12
11
  const REPO = 'sanxzy/mandor';
13
- const GITHUB_API = 'https://api.github.com';
14
12
  const DEFAULT_VERSION = 'latest';
15
-
16
- function getCachedBinary(version, platform, arch) {
17
- const osArch = `${platform}-${arch}`;
18
- const binaryName = platform === 'win32' ? 'mandor.exe' : 'mandor';
19
- const binaryPath = path.join(os.homedir(), '.mandor', 'bin', version, osArch, binaryName);
20
-
21
- if (fs.existsSync(binaryPath)) {
22
- return binaryPath;
23
- }
24
- return null;
13
+ const INSTALL_DIR = path.join(os.homedir(), '.local', 'bin');
14
+
15
+ function getPlatform() {
16
+ const platform = os.platform();
17
+ const arch = os.arch();
18
+ const platformMap = { darwin: 'darwin', linux: 'linux', win32: 'win32' };
19
+ const archMap = { x64: 'x64', arm64: 'arm64', amd64: 'x64', aarch64: 'arm64' };
20
+ return {
21
+ platform: platformMap[platform] || platform,
22
+ arch: archMap[arch] || arch
23
+ };
25
24
  }
26
25
 
27
26
  async function getLatestVersion(prerelease = false) {
28
27
  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
-
41
- function cacheBinary(binaryPath, version, platform, arch) {
42
- const osArch = `${platform}-${arch}`;
43
- const cacheDir = path.join(os.homedir(), '.mandor', 'bin', version, osArch);
44
- fs.mkdirSync(cacheDir, { recursive: true });
45
-
46
- const binaryName = platform === 'win32' ? 'mandor.exe' : 'mandor';
47
- const destPath = path.join(cacheDir, binaryName);
48
-
49
- fs.copyFileSync(binaryPath, destPath);
50
- fs.chmodSync(destPath, '755');
51
- }
52
-
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
-
101
- function listCachedBinaries() {
102
- const cacheDir = path.join(os.homedir(), '.mandor', 'bin');
103
-
104
- if (!fs.existsSync(cacheDir)) {
105
- return [];
106
- }
107
-
108
- const versions = [];
109
- const entries = fs.readdirSync(cacheDir);
110
-
111
- for (const entry of entries) {
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 });
28
+ ? `https://api.github.com/repos/${REPO}/releases`
29
+ : `https://api.github.com/repos/${REPO}/releases/latest`;
30
+
31
+ return new Promise((resolve, reject) => {
32
+ https.get(url, { headers: { 'User-Agent': 'Mandor-CLI' } }, (res) => {
33
+ let data = '';
34
+ res.on('data', chunk => data += chunk);
35
+ res.on('end', () => {
36
+ try {
37
+ const parsed = JSON.parse(data);
38
+ const tagName = Array.isArray(parsed) ? parsed[0].tag_name : parsed.tag_name;
39
+ resolve(tagName.replace(/^v/, ''));
40
+ } catch (e) {
41
+ reject(e);
122
42
  }
123
- }
124
- }
125
- }
126
-
127
- return versions;
43
+ });
44
+ }).on('error', reject);
45
+ });
128
46
  }
129
47
 
130
- function clearCache() {
131
- const cacheDir = path.join(os.homedir(), '.mandor', 'bin');
132
-
133
- if (!fs.existsSync(cacheDir)) {
134
- return 0;
135
- }
136
-
137
- const entries = fs.readdirSync(cacheDir);
138
- let removed = 0;
139
-
140
- for (const entry of entries) {
141
- const entryPath = path.join(cacheDir, entry);
142
- if (fs.statSync(entryPath).isDirectory()) {
143
- fs.rmSync(entryPath, { recursive: true, force: true });
144
- removed++;
145
- }
146
- }
147
-
148
- return removed;
48
+ function getBinaryPath(version = DEFAULT_VERSION) {
49
+ const { platform, arch } = getPlatform();
50
+ const binaryName = platform === 'win32' ? 'mandor.exe' : 'mandor';
51
+ return path.join(INSTALL_DIR, binaryName);
149
52
  }
150
53
 
151
54
  module.exports = {
152
- resolve,
153
- getCachedBinary,
154
- cacheBinary,
155
- listCachedBinaries,
156
- clearCache,
55
+ getPlatform,
56
+ getLatestVersion,
57
+ getBinaryPath,
157
58
  DEFAULT_VERSION,
158
- getLatestVersion
59
+ INSTALL_DIR
159
60
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mandors/cli",
3
- "version": "0.0.17",
3
+ "version": "0.0.19",
4
4
  "description": "Event-based task manager CLI for AI agent workflows",
5
5
  "main": "npm/lib/index.js",
6
6
  "bin": {