@mandors/cli 0.0.18 → 0.0.20

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/npm/bin/mandor CHANGED
@@ -1,32 +1,15 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- /**
4
- * @fileoverview Mandor CLI Node.js wrapper script
5
- * @description Resolves the Mandor binary path and spawns the CLI with provided arguments
6
- * @version 0.0.1
7
- */
8
-
9
- const { resolve } = require('../lib/resolve');
10
3
  const { spawn } = require('child_process');
11
4
  const path = require('path');
5
+ const os = require('os');
12
6
 
13
- /**
14
- * Main entry point for the Mandor CLI wrapper
15
- * @async
16
- * @returns {Promise<void>} Resolves when the CLI process exits
17
- * @throws {Error} If binary resolution fails
18
- * @example
19
- * // Run: mandor task list --project api
20
- * await main();
21
- */
22
- async function main() {
23
- const binaryPath = await resolve();
24
- const args = process.argv.slice(2);
25
- const proc = spawn(binaryPath, args, {
26
- stdio: 'inherit',
27
- cwd: process.cwd()
28
- });
29
- proc.on('exit', process.exit);
30
- }
7
+ const INSTALL_DIR = path.join(os.homedir(), '.local', 'bin');
8
+ const binaryPath = path.join(INSTALL_DIR, process.platform === 'win32' ? 'mandor.exe' : 'mandor');
31
9
 
32
- main().catch(console.error);
10
+ const args = process.argv.slice(2);
11
+ const proc = spawn(binaryPath, args, {
12
+ stdio: 'inherit',
13
+ cwd: process.cwd()
14
+ });
15
+ proc.on('exit', process.exit);
package/npm/lib/index.js CHANGED
@@ -1,138 +1,21 @@
1
1
  /**
2
2
  * @fileoverview Mandor CLI npm package entry point
3
- * @description Main export for programmatic usage and CLI access
4
- * @version 0.0.1
3
+ * @description Main export for CLI access
4
+ * @version 0.0.2
5
5
  */
6
6
 
7
- const Mandor = require('./api');
8
- const MandorConfig = require('./config');
9
- const { resolve, listCachedBinaries, clearCache } = require('./resolve');
10
- const { downloadBinary, getCurrentPlatform } = require('./download');
11
7
  const { install } = require('./install');
8
+ const MandorConfig = require('./config');
12
9
 
13
- /**
14
- * Main export object containing all public APIs
15
- * @namespace mandor
16
- * @version 0.0.1
17
- * @example
18
- * const mandor = require('@mandor/cli');
19
- *
20
- * // CLI access via npx or npm script
21
- * // $ npx mandor init "My Project"
22
- *
23
- * // Programmatic usage
24
- * const cli = new mandor.Mandor({ json: true });
25
- * await cli.init('My Project');
26
- */
27
10
  module.exports = {
28
- /**
29
- * Mandor CLI wrapper class for programmatic access
30
- * @type {typeof Mandor}
31
- * @memberof mandor
32
- * @example
33
- * const mandor = require('@mandor/cli');
34
- * const cli = new mandor.Mandor({ json: true });
35
- */
36
- Mandor,
37
-
38
- /**
39
- * Configuration management class
40
- * @type {typeof MandorConfig}
41
- * @memberof mandor
42
- * @example
43
- * const config = new mandor.MandorConfig('/path/to/project');
44
- * const priority = config.get('priority.default', 'P3');
45
- */
46
11
  MandorConfig,
47
-
48
- /**
49
- * Resolves the Mandor binary path
50
- * @function
51
- * @param {Object} [options] - Resolution options
52
- * @param {string} [options.version] - Version to use
53
- * @returns {Promise<string>} Path to binary
54
- * @memberof mandor
55
- * @example
56
- * const binaryPath = await mandor.resolve({ version: 'latest' });
57
- */
58
- resolve,
59
-
60
- /**
61
- * Lists all cached binary versions
62
- * @function
63
- * @returns {Object[]} Cached binary info
64
- * @memberof mandor
65
- * @example
66
- * const cached = mandor.listCachedBinaries();
67
- */
68
- listCachedBinaries,
69
-
70
- /**
71
- * Clears all cached binaries
72
- * @function
73
- * @returns {number} Number of binaries removed
74
- * @memberof mandor
75
- * @example
76
- * const removed = mandor.clearCache();
77
- */
78
- clearCache,
79
-
80
- /**
81
- * Downloads a Mandor binary
82
- * @function
83
- * @param {string} version - Version to download
84
- * @param {string} [platform] - Target platform
85
- * @param {string} [arch] - Target architecture
86
- * @returns {Promise<string>} Path to downloaded binary
87
- * @memberof mandor
88
- * @example
89
- * const binary = await mandor.downloadBinary('1.0.0', 'darwin', 'x64');
90
- */
91
- downloadBinary,
92
-
93
- /**
94
- * Gets current platform information
95
- * @function
96
- * @returns {{platform: string, arch: string}} Platform info
97
- * @memberof mandor
98
- * @example
99
- * const { platform, arch } = mandor.getCurrentPlatform();
100
- */
101
- getCurrentPlatform,
102
-
103
- /**
104
- * Runs post-install setup
105
- * @function
106
- * @param {Object} [options] - Install options
107
- * @returns {Promise<string>} Path to installed binary
108
- * @memberof mandor
109
- * @example
110
- * await mandor.install({ version: 'latest' });
111
- */
112
12
  install,
113
-
114
- // Version info
115
- /** @type {string} Package version */
116
- version: '0.0.1',
117
-
118
- /** @type {string} Supported Mandor version range */
119
- mandorVersionRange: '>=0.0.1'
13
+ version: '0.0.2'
120
14
  };
121
15
 
122
- // CLI entry point when bin/mandor is executed
123
- if (require.main === module) {
124
- resolve()
125
- .then(binaryPath => {
126
- const { spawn } = require('child_process');
127
- const args = process.argv.slice(2);
128
- const proc = spawn(binaryPath, args, {
129
- stdio: 'inherit',
130
- cwd: process.cwd()
131
- });
132
- proc.on('exit', process.exit);
133
- })
134
- .catch(error => {
135
- console.error('Failed to start Mandor:', error.message);
136
- process.exit(1);
137
- });
16
+ if (require.main === module || process.env.npm_lifecycle_event === 'postinstall') {
17
+ install().catch(error => {
18
+ console.error('Failed to install Mandor:', error.message);
19
+ process.exit(1);
20
+ });
138
21
  }
@@ -1,7 +1,7 @@
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.4
3
+ * @description Downloads and extracts binary from GitHub releases
4
+ * @version 0.0.5
5
5
  */
6
6
 
7
7
  const fs = require('fs');
@@ -11,8 +11,7 @@ const { execSync } = require('child_process');
11
11
  const https = require('https');
12
12
 
13
13
  const REPO = 'sanxzy/mandor';
14
- const GITHUB_API = 'https://api.github.com';
15
- const CACHE_DIR = path.join(os.homedir(), '.mandor', 'bin');
14
+ const INSTALL_DIR = path.join(os.homedir(), '.local', 'bin');
16
15
 
17
16
  function getPlatform() {
18
17
  const platform = os.platform();
@@ -27,8 +26,8 @@ function getPlatform() {
27
26
 
28
27
  async function getLatestVersion(prerelease = false) {
29
28
  const url = prerelease
30
- ? `${GITHUB_API}/repos/${REPO}/releases`
31
- : `${GITHUB_API}/repos/${REPO}/releases/latest`;
29
+ ? `https://api.github.com/repos/${REPO}/releases`
30
+ : `https://api.github.com/repos/${REPO}/releases/latest`;
32
31
 
33
32
  return new Promise((resolve, reject) => {
34
33
  https.get(url, { headers: { 'User-Agent': 'Mandor-CLI' } }, (res) => {
@@ -37,8 +36,17 @@ async function getLatestVersion(prerelease = false) {
37
36
  res.on('end', () => {
38
37
  try {
39
38
  const parsed = JSON.parse(data);
40
- const tagName = Array.isArray(parsed) ? parsed[0].tag_name : parsed.tag_name;
41
- resolve(tagName.replace(/^v/, ''));
39
+ let tagName = null;
40
+ if (parsed && parsed.tag_name) {
41
+ tagName = parsed.tag_name;
42
+ } else if (Array.isArray(parsed) && parsed.length > 0 && parsed[0].tag_name) {
43
+ tagName = parsed[0].tag_name;
44
+ }
45
+ if (tagName) {
46
+ resolve(tagName.replace(/^v/, ''));
47
+ } else {
48
+ reject(new Error('No release found'));
49
+ }
42
50
  } catch (e) {
43
51
  reject(e);
44
52
  }
@@ -70,7 +78,7 @@ async function install(options = {}) {
70
78
  const version = options.version || 'latest';
71
79
  const prerelease = options.prerelease || false;
72
80
  const osArch = `${platform}-${arch}`;
73
- const assetName = `${osArch}.tar.gz`;
81
+ const binaryName = platform === 'win32' ? 'mandor.exe' : 'mandor';
74
82
 
75
83
  console.log('Mandor Installer');
76
84
  console.log('================');
@@ -85,37 +93,38 @@ async function install(options = {}) {
85
93
  console.log(`Version: ${installVersion}`);
86
94
  console.log('');
87
95
 
88
- const cachePath = path.join(CACHE_DIR, installVersion, osArch);
89
- const binaryPath = path.join(cachePath, platform === 'win32' ? 'mandor.exe' : 'mandor');
96
+ const binaryPath = path.join(INSTALL_DIR, binaryName);
90
97
 
91
98
  if (fs.existsSync(binaryPath)) {
92
- console.log(`Using cached binary: ${binaryPath}`);
99
+ console.log(`Already installed: ${binaryPath}`);
93
100
  return binaryPath;
94
101
  }
95
102
 
96
103
  console.log('Downloading from GitHub releases...');
97
- const downloadUrl = `https://github.com/${REPO}/releases/download/v${installVersion}/${assetName}`;
98
- const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mandor-install-'));
99
- const tarball = path.join(tempDir, assetName);
104
+ const downloadUrl = `https://github.com/${REPO}/releases/download/v${installVersion}/${osArch}.tar.gz`;
105
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mandor-'));
106
+ const tarball = path.join(tempDir, `${osArch}.tar.gz`);
100
107
 
101
108
  await downloadFile(downloadUrl, tarball);
102
109
 
103
- if (!fs.existsSync(cachePath)) {
104
- fs.mkdirSync(cachePath, { recursive: true });
105
- }
110
+ fs.mkdirSync(INSTALL_DIR, { recursive: true });
111
+ execSync(`tar -xzf "${tarball}" -C "${tempDir}"`, { stdio: 'inherit' });
106
112
 
107
- execSync(`tar -xzf "${tarball}" -C "${cachePath}"`, { stdio: 'inherit' });
113
+ const extractedBinary = path.join(tempDir, binaryName);
114
+ fs.copyFileSync(extractedBinary, binaryPath);
108
115
  fs.chmodSync(binaryPath, '755');
109
116
 
110
117
  fs.rmSync(tempDir, { recursive: true });
111
118
 
112
119
  console.log(`Installed: ${binaryPath}`);
120
+ console.log('');
121
+ console.log('Add to PATH:');
122
+ console.log(` export PATH="${INSTALL_DIR}:$PATH"`);
113
123
  return binaryPath;
114
124
  }
115
125
 
116
126
  if (require.main === module || process.env.npm_lifecycle_event === 'postinstall') {
117
- const prerelease = process.argv.includes('--prerelease') || process.argv.includes('-p');
118
- install({ prerelease }).catch(error => {
127
+ install().catch(error => {
119
128
  console.error('Failed to install Mandor:', error.message);
120
129
  process.exit(1);
121
130
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mandors/cli",
3
- "version": "0.0.18",
3
+ "version": "0.0.20",
4
4
  "description": "Event-based task manager CLI for AI agent workflows",
5
5
  "main": "npm/lib/index.js",
6
6
  "bin": {
package/npm/lib/api.js DELETED
@@ -1,216 +0,0 @@
1
- /**
2
- * @fileoverview Mandor CLI programmatic API
3
- * @description Node.js API for interacting with Mandor from JavaScript/TypeScript code
4
- * @version 0.0.1
5
- */
6
-
7
- const { spawn } = require('child_process');
8
-
9
- /**
10
- * @typedef {Object} MandorOptions
11
- * @property {string} [cwd] - Working directory (default: process.cwd())
12
- * @property {boolean} [json] - Use JSON output format (default: false)
13
- */
14
-
15
- /**
16
- * @typedef {Object} ProjectCreateOptions
17
- * @property {string} [name] - Project display name
18
- * @property {string} [goal] - Project goal description
19
- */
20
-
21
- /**
22
- * @typedef {Object} TaskListOptions
23
- * @property {string} [project] - Filter by project ID
24
- * @property {string} [feature] - Filter by feature ID
25
- * @property {string} [status] - Filter by status (pending, ready, in_progress, done, blocked, cancelled)
26
- * @property {string} [priority] - Filter by priority (P0-P5)
27
- */
28
-
29
- /**
30
- * Mandor CLI wrapper class for programmatic access
31
- * @class
32
- * @version 0.0.1
33
- * @example
34
- * const mandor = new Mandor({ cwd: '/path/to/project', json: true });
35
- * const tasks = await mandor.taskList({ project: 'api', status: 'pending' });
36
- */
37
- class Mandor {
38
- /**
39
- * Creates a new Mandor instance
40
- * @constructor
41
- * @param {MandorOptions} [options] - Configuration options
42
- * @example
43
- * const mandor = new Mandor({ cwd: '/my/project', json: true });
44
- */
45
- constructor(options = {}) {
46
- /** @type {string} Working directory */
47
- this.cwd = options.cwd || process.cwd();
48
- /** @type {boolean} Use JSON output */
49
- this.json = options.json || false;
50
- }
51
-
52
- /**
53
- * Initializes a new Mandor workspace
54
- * @async
55
- * @param {string} name - Workspace name
56
- * @returns {Promise<number>} Exit code from the CLI
57
- * @throws {Error} If initialization fails
58
- * @example
59
- * await mandor.init('My AI Project');
60
- */
61
- async init(name) {
62
- return this._run('init', [name]);
63
- }
64
-
65
- /**
66
- * Creates a new project
67
- * @async
68
- * @param {string} id - Project identifier (lowercase, hyphens only)
69
- * @param {ProjectCreateOptions} [options] - Project options
70
- * @returns {Promise<number>} Exit code from the CLI
71
- * @example
72
- * await mandor.projectCreate('api', {
73
- * name: 'API Service',
74
- * goal: 'Implement REST API with user management'
75
- * });
76
- */
77
- async projectCreate(id, options = {}) {
78
- const args = ['project', 'create', id];
79
- if (options.name) args.push('--name', options.name);
80
- if (options.goal) args.push('--goal', options.goal);
81
- return this._run(...args);
82
- }
83
-
84
- /**
85
- * Lists tasks with optional filters
86
- * @async
87
- * @param {TaskListOptions} [options] - Filter options
88
- * @returns {Promise<Object[]|number>} Task list (JSON) or exit code
89
- * @example
90
- * const tasks = await mandor.taskList({
91
- * project: 'api',
92
- * status: 'pending',
93
- * json: true
94
- * });
95
- */
96
- async taskList(options = {}) {
97
- const args = ['task', 'list'];
98
- if (options.project) args.push('--project', options.project);
99
- if (options.feature) args.push('--feature', options.feature);
100
- if (options.status) args.push('--status', options.status);
101
- if (options.priority) args.push('--priority', options.priority);
102
- if (options.json) args.push('--json');
103
- return this._run(...args);
104
- }
105
-
106
- /**
107
- * Gets detailed information about a task
108
- * @async
109
- * @param {string} taskId - Task identifier
110
- * @returns {Promise<Object|number>} Task details (JSON) or exit code
111
- * @example
112
- * const task = await mandor.taskDetail('api-feature-abc-task-xyz789', { json: true });
113
- */
114
- async taskDetail(taskId) {
115
- return this._run('task', 'detail', taskId);
116
- }
117
-
118
- /**
119
- * Updates a task's status or metadata
120
- * @async
121
- * @param {string} taskId - Task identifier
122
- * @param {Object} updates - Fields to update
123
- * @returns {Promise<number>} Exit code from the CLI
124
- * @example
125
- * await mandor.taskUpdate('api-feature-abc-task-xyz789', {
126
- * status: 'in_progress'
127
- * });
128
- */
129
- async taskUpdate(taskId, updates = {}) {
130
- const args = ['task', 'update', taskId];
131
- if (updates.status) args.push('--status', updates.status);
132
- if (updates.name) args.push('--name', updates.name);
133
- if (updates.priority) args.push('--priority', updates.priority);
134
- return this._run(...args);
135
- }
136
-
137
- /**
138
- * Lists features with optional filters
139
- * @async
140
- * @param {Object} [options] - Filter options
141
- * @returns {Promise<Object[]|number>} Feature list (JSON) or exit code
142
- * @example
143
- * const features = await mandor.featureList({ project: 'api', json: true });
144
- */
145
- async featureList(options = {}) {
146
- const args = ['feature', 'list'];
147
- if (options.project) args.push('--project', options.project);
148
- if (options.status) args.push('--status', options.status);
149
- if (options.json) args.push('--json');
150
- return this._run(...args);
151
- }
152
-
153
- /**
154
- * Lists issues with optional filters
155
- * @async
156
- * @param {Object} [options] - Filter options
157
- * @returns {Promise<Object[]|number>} Issue list (JSON) or exit code
158
- * @example
159
- * const issues = await mandor.issueList({ project: 'api', type: 'bug', json: true });
160
- */
161
- async issueList(options = {}) {
162
- const args = ['issue', 'list'];
163
- if (options.project) args.push('--project', options.project);
164
- if (options.type) args.push('--type', options.type);
165
- if (options.status) args.push('--status', options.status);
166
- if (options.json) args.push('--json');
167
- return this._run(...args);
168
- }
169
-
170
- /**
171
- * Gets workspace status and statistics
172
- * @async
173
- * @param {Object} [options] - Options
174
- * @returns {Promise<Object|number>} Status (JSON) or exit code
175
- * @example
176
- * const status = await mandor.status({ json: true });
177
- */
178
- async status(options = {}) {
179
- const args = ['status'];
180
- if (options.json) args.push('--json');
181
- return this._run(...args);
182
- }
183
-
184
- /**
185
- * Internal method to run mandor CLI commands
186
- * @private
187
- * @async
188
- * @param {...string} args - Command arguments
189
- * @returns {Promise<Object|number>} Result based on json option
190
- * @throws {Error} If process fails
191
- */
192
- _run(...args) {
193
- return new Promise((resolve, reject) => {
194
- const proc = spawn('mandor', args, {
195
- cwd: this.cwd,
196
- stdio: this.json ? 'pipe' : 'inherit'
197
- });
198
-
199
- if (this.json) {
200
- let data = '';
201
- proc.stdout.on('data', chunk => data += chunk);
202
- proc.on('close', (code) => {
203
- try {
204
- resolve(JSON.parse(data));
205
- } catch {
206
- resolve(data);
207
- }
208
- });
209
- } else {
210
- proc.on('close', resolve);
211
- }
212
- });
213
- }
214
- }
215
-
216
- module.exports = Mandor;
@@ -1,83 +0,0 @@
1
- /**
2
- * @fileoverview Binary download module for Mandor CLI
3
- * @description Handles downloading and caching Mandor binaries for the current platform
4
- * @version 0.0.1
5
- */
6
-
7
- const https = require('https');
8
- const fs = require('fs');
9
- const path = require('path');
10
- const os = require('os');
11
-
12
- /** @type {string} GitHub releases API URL */
13
- const RELEASES_URL = 'https://api.github.com/repos/sanxzy/mandor/releases';
14
-
15
- /**
16
- * Downloads the Mandor binary for the specified platform and architecture
17
- * @async
18
- * @param {string} version - The Mandor version to download (e.g., '1.0.0', 'latest')
19
- * @param {string} platform - Target platform (e.g., 'darwin', 'linux', 'win32')
20
- * @param {string} arch - Target architecture (e.g., 'x64', 'arm64')
21
- * @returns {Promise<string>} Path to the downloaded and executable binary
22
- * @throws {Error} If download fails or platform is unsupported
23
- * @example
24
- * // Download Mandor v1.0.0 for macOS x64
25
- * const binaryPath = await downloadBinary('1.0.0', 'darwin', 'x64');
26
- * console.log(`Binary downloaded to: ${binaryPath}`);
27
- */
28
- async function downloadBinary(version, platform, arch) {
29
- const filename = `mandor-${platform}-${arch}`;
30
- const url = `${RELEASES_URL}/download/${version}/${filename}`;
31
- const dest = path.join(os.homedir(), '.mandor', 'bin', filename);
32
-
33
- // Download and make executable
34
- return new Promise((resolve, reject) => {
35
- https.get(url, (response) => {
36
- if (response.statusCode === 302) {
37
- return downloadBinary(response.headers.location, platform, arch);
38
- }
39
- const file = fs.createWriteStream(dest);
40
- response.pipe(file);
41
- file.on('finish', () => {
42
- fs.chmodSync(dest, '755');
43
- resolve(dest);
44
- });
45
- }).on('error', reject);
46
- });
47
- }
48
-
49
- /**
50
- * Gets the platform identifier for the current system
51
- * @returns {{platform: string, arch: string}} Platform and architecture info
52
- * @example
53
- * const { platform, arch } = getCurrentPlatform();
54
- * console.log(`Running on ${platform}-${arch}`);
55
- */
56
- function getCurrentPlatform() {
57
- const platform = os.platform(); // 'darwin', 'linux', 'win32'
58
- const arch = os.arch(); // 'x64', 'arm64'
59
- return { platform, arch };
60
- }
61
-
62
- /**
63
- * Checks if a binary already exists and is up-to-date
64
- * @param {string} version - Expected version
65
- * @param {string} platform - Target platform
66
- * @param {string} arch - Target architecture
67
- * @returns {Promise<boolean>} True if binary exists and is valid
68
- * @example
69
- * const exists = await binaryExists('1.0.0', 'darwin', 'x64');
70
- * if (exists) { console.log('Binary cached'); }
71
- */
72
- async function binaryExists(version, platform, arch) {
73
- const filename = `mandor-${platform}-${arch}`;
74
- const dest = path.join(os.homedir(), '.mandor', 'bin', filename);
75
- return fs.existsSync(dest);
76
- }
77
-
78
- module.exports = {
79
- downloadBinary,
80
- getCurrentPlatform,
81
- binaryExists,
82
- RELEASES_URL
83
- };
@@ -1,159 +0,0 @@
1
- /**
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
5
- */
6
-
7
- const path = require('path');
8
- const fs = require('fs');
9
- const os = require('os');
10
- const { downloadBinary, getCurrentPlatform } = require('./download');
11
-
12
- const REPO = 'sanxzy/mandor';
13
- const GITHUB_API = 'https://api.github.com';
14
- 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;
25
- }
26
-
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
-
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 });
122
- }
123
- }
124
- }
125
- }
126
-
127
- return versions;
128
- }
129
-
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;
149
- }
150
-
151
- module.exports = {
152
- resolve,
153
- getCachedBinary,
154
- cacheBinary,
155
- listCachedBinaries,
156
- clearCache,
157
- DEFAULT_VERSION,
158
- getLatestVersion
159
- };