@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 +9 -26
- package/npm/lib/index.js +9 -126
- package/npm/lib/install.js +30 -21
- package/package.json +1 -1
- package/npm/lib/api.js +0 -216
- package/npm/lib/download.js +0 -83
- package/npm/lib/resolve.js +0 -159
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
|
-
|
|
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
|
-
|
|
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
|
|
4
|
-
* @version 0.0.
|
|
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
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
.
|
|
126
|
-
|
|
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
|
}
|
package/npm/lib/install.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @fileoverview Post-install hook for Mandor CLI
|
|
3
|
-
* @description Downloads binary from GitHub releases
|
|
4
|
-
* @version 0.0.
|
|
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
|
|
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
|
-
?
|
|
31
|
-
:
|
|
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
|
-
|
|
41
|
-
|
|
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
|
|
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
|
|
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(`
|
|
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}/${
|
|
98
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'mandor-
|
|
99
|
-
const tarball = path.join(tempDir,
|
|
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
|
-
|
|
104
|
-
|
|
105
|
-
}
|
|
110
|
+
fs.mkdirSync(INSTALL_DIR, { recursive: true });
|
|
111
|
+
execSync(`tar -xzf "${tarball}" -C "${tempDir}"`, { stdio: 'inherit' });
|
|
106
112
|
|
|
107
|
-
|
|
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
|
-
|
|
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
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;
|
package/npm/lib/download.js
DELETED
|
@@ -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
|
-
};
|
package/npm/lib/resolve.js
DELETED
|
@@ -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
|
-
};
|